1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/mathml/nsMathMLmoFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1060 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsMathMLmoFrame.h" 1.10 +#include "nsPresContext.h" 1.11 +#include "nsRenderingContext.h" 1.12 +#include "nsContentUtils.h" 1.13 +#include "nsFrameSelection.h" 1.14 +#include "nsMathMLElement.h" 1.15 +#include <algorithm> 1.16 + 1.17 +// 1.18 +// <mo> -- operator, fence, or separator - implementation 1.19 +// 1.20 + 1.21 +// additional style context to be used by our MathMLChar. 1.22 +#define NS_MATHML_CHAR_STYLE_CONTEXT_INDEX 0 1.23 + 1.24 +nsIFrame* 1.25 +NS_NewMathMLmoFrame(nsIPresShell* aPresShell, nsStyleContext *aContext) 1.26 +{ 1.27 + return new (aPresShell) nsMathMLmoFrame(aContext); 1.28 +} 1.29 + 1.30 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmoFrame) 1.31 + 1.32 +nsMathMLmoFrame::~nsMathMLmoFrame() 1.33 +{ 1.34 +} 1.35 + 1.36 +static const char16_t kApplyFunction = char16_t(0x2061); 1.37 +static const char16_t kInvisibleTimes = char16_t(0x2062); 1.38 +static const char16_t kInvisibleSeparator = char16_t(0x2063); 1.39 +static const char16_t kInvisiblePlus = char16_t(0x2064); 1.40 + 1.41 +eMathMLFrameType 1.42 +nsMathMLmoFrame::GetMathMLFrameType() 1.43 +{ 1.44 + return NS_MATHML_OPERATOR_IS_INVISIBLE(mFlags) 1.45 + ? eMathMLFrameType_OperatorInvisible 1.46 + : eMathMLFrameType_OperatorOrdinary; 1.47 +} 1.48 + 1.49 +// since a mouse click implies selection, we cannot just rely on the 1.50 +// frame's state bit in our child text frame. So we will first check 1.51 +// its selected state bit, and use this little helper to double check. 1.52 +bool 1.53 +nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame) 1.54 +{ 1.55 + NS_ASSERTION(aFrame, "null arg"); 1.56 + if (!aFrame || !aFrame->IsSelected()) 1.57 + return false; 1.58 + 1.59 + const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection(); 1.60 + SelectionDetails* details = 1.61 + frameSelection->LookUpSelection(aFrame->GetContent(), 0, 1, true); 1.62 + 1.63 + if (!details) 1.64 + return false; 1.65 + 1.66 + while (details) { 1.67 + SelectionDetails* next = details->mNext; 1.68 + delete details; 1.69 + details = next; 1.70 + } 1.71 + return true; 1.72 +} 1.73 + 1.74 +bool 1.75 +nsMathMLmoFrame::UseMathMLChar() 1.76 +{ 1.77 + return (NS_MATHML_OPERATOR_GET_FORM(mFlags) && 1.78 + NS_MATHML_OPERATOR_IS_MUTABLE(mFlags)) || 1.79 + NS_MATHML_OPERATOR_IS_CENTERED(mFlags); 1.80 +} 1.81 + 1.82 +void 1.83 +nsMathMLmoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.84 + const nsRect& aDirtyRect, 1.85 + const nsDisplayListSet& aLists) 1.86 +{ 1.87 + bool useMathMLChar = UseMathMLChar(); 1.88 + 1.89 + if (!useMathMLChar) { 1.90 + // let the base class do everything 1.91 + nsMathMLTokenFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); 1.92 + } else { 1.93 + DisplayBorderBackgroundOutline(aBuilder, aLists); 1.94 + 1.95 + // make our char selected if our inner child text frame is selected 1.96 + bool isSelected = false; 1.97 + nsRect selectedRect; 1.98 + nsIFrame* firstChild = mFrames.FirstChild(); 1.99 + if (IsFrameInSelection(firstChild)) { 1.100 + mMathMLChar.GetRect(selectedRect); 1.101 + // add a one pixel border (it renders better for operators like minus) 1.102 + selectedRect.Inflate(nsPresContext::CSSPixelsToAppUnits(1)); 1.103 + isSelected = true; 1.104 + } 1.105 + mMathMLChar.Display(aBuilder, this, aLists, 0, isSelected ? &selectedRect : nullptr); 1.106 + 1.107 +#if defined(DEBUG) && defined(SHOW_BOUNDING_BOX) 1.108 + // for visual debug 1.109 + DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists); 1.110 +#endif 1.111 + } 1.112 +} 1.113 + 1.114 +// get the text that we enclose and setup our nsMathMLChar 1.115 +void 1.116 +nsMathMLmoFrame::ProcessTextData() 1.117 +{ 1.118 + mFlags = 0; 1.119 + 1.120 + nsAutoString data; 1.121 + if (!nsContentUtils::GetNodeTextContent(mContent, false, data)) { 1.122 + NS_RUNTIMEABORT("OOM"); 1.123 + } 1.124 + 1.125 + data.CompressWhitespace(); 1.126 + int32_t length = data.Length(); 1.127 + char16_t ch = (length == 0) ? char16_t('\0') : data[0]; 1.128 + 1.129 + if ((length == 1) && 1.130 + (ch == kApplyFunction || 1.131 + ch == kInvisibleSeparator || 1.132 + ch == kInvisiblePlus || 1.133 + ch == kInvisibleTimes)) { 1.134 + mFlags |= NS_MATHML_OPERATOR_INVISIBLE; 1.135 + } 1.136 + 1.137 + // don't bother doing anything special if we don't have a single child 1.138 + nsPresContext* presContext = PresContext(); 1.139 + if (mFrames.GetLength() != 1) { 1.140 + data.Truncate(); // empty data to reset the char 1.141 + mMathMLChar.SetData(presContext, data); 1.142 + ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar); 1.143 + return; 1.144 + } 1.145 + 1.146 + // special... in math mode, the usual minus sign '-' looks too short, so 1.147 + // what we do here is to remap <mo>-</mo> to the official Unicode minus 1.148 + // sign (U+2212) which looks much better. For background on this, see 1.149 + // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1 1.150 + if (1 == length && ch == '-') { 1.151 + ch = 0x2212; 1.152 + data = ch; 1.153 + } 1.154 + 1.155 + // cache the special bits: mutable, accent, movablelimits, centered. 1.156 + // we need to do this in anticipation of other requirements, and these 1.157 + // bits don't change. Do not reset these bits unless the text gets changed. 1.158 + 1.159 + // lookup all the forms under which the operator is listed in the dictionary, 1.160 + // and record whether the operator has accent="true" or movablelimits="true" 1.161 + nsOperatorFlags flags[4]; 1.162 + float lspace[4], rspace[4]; 1.163 + nsMathMLOperators::LookupOperators(data, flags, lspace, rspace); 1.164 + nsOperatorFlags allFlags = 1.165 + flags[NS_MATHML_OPERATOR_FORM_INFIX] | 1.166 + flags[NS_MATHML_OPERATOR_FORM_POSTFIX] | 1.167 + flags[NS_MATHML_OPERATOR_FORM_PREFIX]; 1.168 + 1.169 + mFlags |= allFlags & NS_MATHML_OPERATOR_ACCENT; 1.170 + mFlags |= allFlags & NS_MATHML_OPERATOR_MOVABLELIMITS; 1.171 + 1.172 + // see if this is an operator that should be centered to cater for 1.173 + // fonts that are not math-aware 1.174 + if (1 == length) { 1.175 + if ((ch == '+') || (ch == '=') || (ch == '*') || 1.176 + (ch == 0x2212) || // − 1.177 + (ch == 0x2264) || // ≤ 1.178 + (ch == 0x2265) || // ≥ 1.179 + (ch == 0x00D7)) { // × 1.180 + mFlags |= NS_MATHML_OPERATOR_CENTERED; 1.181 + } 1.182 + } 1.183 + 1.184 + // cache the operator 1.185 + mMathMLChar.SetData(presContext, data); 1.186 + 1.187 + // cache the native direction -- beware of bug 133429... 1.188 + // mEmbellishData.direction must always retain our native direction, whereas 1.189 + // mMathMLChar.GetStretchDirection() may change later, when Stretch() is called 1.190 + mEmbellishData.direction = mMathMLChar.GetStretchDirection(); 1.191 + 1.192 + bool isMutable = 1.193 + NS_MATHML_OPERATOR_IS_LARGEOP(allFlags) || 1.194 + (mEmbellishData.direction != NS_STRETCH_DIRECTION_UNSUPPORTED); 1.195 + if (isMutable) 1.196 + mFlags |= NS_MATHML_OPERATOR_MUTABLE; 1.197 + 1.198 + ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar); 1.199 +} 1.200 + 1.201 +// get our 'form' and lookup in the Operator Dictionary to fetch 1.202 +// our default data that may come from there. Then complete our setup 1.203 +// using attributes that we may have. To stay in sync, this function is 1.204 +// called very often. We depend on many things that may change around us. 1.205 +// However, we re-use unchanged values. 1.206 +void 1.207 +nsMathMLmoFrame::ProcessOperatorData() 1.208 +{ 1.209 + // if we have been here before, we will just use our cached form 1.210 + nsOperatorFlags form = NS_MATHML_OPERATOR_GET_FORM(mFlags); 1.211 + nsAutoString value; 1.212 + 1.213 + // special bits are always kept in mFlags. 1.214 + // remember the mutable bit from ProcessTextData(). 1.215 + // Some chars are listed under different forms in the dictionary, 1.216 + // and there could be a form under which the char is mutable. 1.217 + // If the char is the core of an embellished container, we will keep 1.218 + // it mutable irrespective of the form of the embellished container. 1.219 + // Also remember the other special bits that we want to carry forward. 1.220 + mFlags &= NS_MATHML_OPERATOR_MUTABLE | 1.221 + NS_MATHML_OPERATOR_ACCENT | 1.222 + NS_MATHML_OPERATOR_MOVABLELIMITS | 1.223 + NS_MATHML_OPERATOR_CENTERED | 1.224 + NS_MATHML_OPERATOR_INVISIBLE; 1.225 + 1.226 + if (!mEmbellishData.coreFrame) { 1.227 + // i.e., we haven't been here before, the default form is infix 1.228 + form = NS_MATHML_OPERATOR_FORM_INFIX; 1.229 + 1.230 + // reset everything so that we don't keep outdated values around 1.231 + // in case of dynamic changes 1.232 + mEmbellishData.flags = 0; 1.233 + mEmbellishData.coreFrame = nullptr; 1.234 + mEmbellishData.leadingSpace = 0; 1.235 + mEmbellishData.trailingSpace = 0; 1.236 + if (mMathMLChar.Length() != 1) 1.237 + mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED; 1.238 + // else... retain the native direction obtained in ProcessTextData() 1.239 + 1.240 + if (!mFrames.FirstChild()) { 1.241 + return; 1.242 + } 1.243 + 1.244 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR; 1.245 + mEmbellishData.coreFrame = this; 1.246 + 1.247 + // there are two particular things that we also need to record so that if our 1.248 + // parent is <mover>, <munder>, or <munderover>, they will treat us properly: 1.249 + // 1) do we have accent="true" 1.250 + // 2) do we have movablelimits="true" 1.251 + 1.252 + // they need the extra information to decide how to treat their scripts/limits 1.253 + // (note: <mover>, <munder>, or <munderover> need not necessarily be our 1.254 + // direct parent -- case of embellished operators) 1.255 + 1.256 + // default values from the Operator Dictionary were obtained in ProcessTextData() 1.257 + // and these special bits are always kept in mFlags 1.258 + if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags)) 1.259 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; 1.260 + if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags)) 1.261 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS; 1.262 + 1.263 + // see if the accent attribute is there 1.264 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value); 1.265 + if (value.EqualsLiteral("true")) 1.266 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT; 1.267 + else if (value.EqualsLiteral("false")) 1.268 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT; 1.269 + 1.270 + // see if the movablelimits attribute is there 1.271 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::movablelimits_, value); 1.272 + if (value.EqualsLiteral("true")) 1.273 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS; 1.274 + else if (value.EqualsLiteral("false")) 1.275 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS; 1.276 + 1.277 + // --------------------------------------------------------------------- 1.278 + // we will be called again to re-sync the rest of our state next time... 1.279 + // (nobody needs the other values below at this stage) 1.280 + mFlags |= form; 1.281 + return; 1.282 + } 1.283 + 1.284 + nsPresContext* presContext = PresContext(); 1.285 + 1.286 + // beware of bug 133814 - there is a two-way dependency in the 1.287 + // embellished hierarchy: our embellished ancestors need to set 1.288 + // their flags based on some of our state (set above), and here we 1.289 + // need to re-sync our 'form' depending on our outermost embellished 1.290 + // container. A null form here means that an earlier attempt to stretch 1.291 + // our mMathMLChar failed, in which case we don't bother re-stretching again 1.292 + if (form) { 1.293 + // get our outermost embellished container and its parent. 1.294 + // (we ensure that we are the core, not just a sibling of the core) 1.295 + nsIFrame* embellishAncestor = this; 1.296 + nsEmbellishData embellishData; 1.297 + nsIFrame* parentAncestor = this; 1.298 + do { 1.299 + embellishAncestor = parentAncestor; 1.300 + parentAncestor = embellishAncestor->GetParent(); 1.301 + GetEmbellishDataFrom(parentAncestor, embellishData); 1.302 + } while (embellishData.coreFrame == this); 1.303 + 1.304 + // flag if we have an embellished ancestor 1.305 + if (embellishAncestor != this) 1.306 + mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR; 1.307 + else 1.308 + mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR; 1.309 + 1.310 + // find the position of our outermost embellished container w.r.t 1.311 + // its siblings. 1.312 + 1.313 + nsIFrame* nextSibling = embellishAncestor->GetNextSibling(); 1.314 + nsIFrame* prevSibling = embellishAncestor->GetPrevSibling(); 1.315 + 1.316 + // flag to distinguish from a real infix. Set for (embellished) operators 1.317 + // that live in (inferred) mrows. 1.318 + nsIMathMLFrame* mathAncestor = do_QueryFrame(parentAncestor); 1.319 + bool zeroSpacing = false; 1.320 + if (mathAncestor) { 1.321 + zeroSpacing = !mathAncestor->IsMrowLike(); 1.322 + } else { 1.323 + nsMathMLmathBlockFrame* blockFrame = do_QueryFrame(parentAncestor); 1.324 + if (blockFrame) { 1.325 + zeroSpacing = !blockFrame->IsMrowLike(); 1.326 + } 1.327 + } 1.328 + if (zeroSpacing) { 1.329 + mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ISOLATED; 1.330 + } else { 1.331 + mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ISOLATED; 1.332 + } 1.333 + 1.334 + // find our form 1.335 + form = NS_MATHML_OPERATOR_FORM_INFIX; 1.336 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::form, value); 1.337 + if (!value.IsEmpty()) { 1.338 + if (value.EqualsLiteral("prefix")) 1.339 + form = NS_MATHML_OPERATOR_FORM_PREFIX; 1.340 + else if (value.EqualsLiteral("postfix")) 1.341 + form = NS_MATHML_OPERATOR_FORM_POSTFIX; 1.342 + } 1.343 + else { 1.344 + // set our form flag depending on the position 1.345 + if (!prevSibling && nextSibling) 1.346 + form = NS_MATHML_OPERATOR_FORM_PREFIX; 1.347 + else if (prevSibling && !nextSibling) 1.348 + form = NS_MATHML_OPERATOR_FORM_POSTFIX; 1.349 + } 1.350 + mFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the old form bits 1.351 + mFlags |= form; 1.352 + 1.353 + // Use the default value suggested by the MathML REC. 1.354 + // http://www.w3.org/TR/MathML/chapter3.html#presm.mo.attrs 1.355 + // thickmathspace = 5/18em 1.356 + float lspace = 5.0f/18.0f; 1.357 + float rspace = 5.0f/18.0f; 1.358 + // lookup the operator dictionary 1.359 + nsAutoString data; 1.360 + mMathMLChar.GetData(data); 1.361 + nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace); 1.362 + // Spacing is zero if our outermost embellished operator is not in an 1.363 + // inferred mrow. 1.364 + if (!NS_MATHML_OPERATOR_EMBELLISH_IS_ISOLATED(mFlags) && 1.365 + (lspace || rspace)) { 1.366 + // Cache the default values of lspace and rspace. 1.367 + // since these values are relative to the 'em' unit, convert to twips now 1.368 + nscoord em; 1.369 + nsRefPtr<nsFontMetrics> fm; 1.370 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.371 + GetEmHeight(fm, em); 1.372 + 1.373 + mEmbellishData.leadingSpace = NSToCoordRound(lspace * em); 1.374 + mEmbellishData.trailingSpace = NSToCoordRound(rspace * em); 1.375 + 1.376 + // tuning if we don't want too much extra space when we are a script. 1.377 + // (with its fonts, TeX sets lspace=0 & rspace=0 as soon as scriptlevel>0. 1.378 + // Our fonts can be anything, so...) 1.379 + if (StyleFont()->mScriptLevel > 0 && 1.380 + !NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) { 1.381 + mEmbellishData.leadingSpace /= 2; 1.382 + mEmbellishData.trailingSpace /= 2; 1.383 + } 1.384 + } 1.385 + } 1.386 + 1.387 + // If we are an accent without explicit lspace="." or rspace=".", 1.388 + // we will ignore our default leading/trailing space 1.389 + 1.390 + // lspace 1.391 + // 1.392 + // "Specifies the leading space appearing before the operator" 1.393 + // 1.394 + // values: length 1.395 + // default: set by dictionary (thickmathspace) 1.396 + // 1.397 + // XXXfredw Support for negative and relative values is not implemented 1.398 + // (bug 805926). 1.399 + // Relative values will give a multiple of the current leading space, 1.400 + // which is not necessarily the default one. 1.401 + // 1.402 + nscoord leadingSpace = mEmbellishData.leadingSpace; 1.403 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::lspace_, value); 1.404 + if (!value.IsEmpty()) { 1.405 + nsCSSValue cssValue; 1.406 + if (nsMathMLElement::ParseNumericValue(value, cssValue, 0, 1.407 + mContent->OwnerDoc())) { 1.408 + if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue()) 1.409 + leadingSpace = 0; 1.410 + else if (cssValue.IsLengthUnit()) 1.411 + leadingSpace = CalcLength(presContext, mStyleContext, cssValue); 1.412 + mFlags |= NS_MATHML_OPERATOR_LSPACE_ATTR; 1.413 + } 1.414 + } 1.415 + 1.416 + // rspace 1.417 + // 1.418 + // "Specifies the trailing space appearing after the operator" 1.419 + // 1.420 + // values: length 1.421 + // default: set by dictionary (thickmathspace) 1.422 + // 1.423 + // XXXfredw Support for negative and relative values is not implemented 1.424 + // (bug 805926). 1.425 + // Relative values will give a multiple of the current leading space, 1.426 + // which is not necessarily the default one. 1.427 + // 1.428 + nscoord trailingSpace = mEmbellishData.trailingSpace; 1.429 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rspace_, value); 1.430 + if (!value.IsEmpty()) { 1.431 + nsCSSValue cssValue; 1.432 + if (nsMathMLElement::ParseNumericValue(value, cssValue, 0, 1.433 + mContent->OwnerDoc())) { 1.434 + if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue()) 1.435 + trailingSpace = 0; 1.436 + else if (cssValue.IsLengthUnit()) 1.437 + trailingSpace = CalcLength(presContext, mStyleContext, cssValue); 1.438 + mFlags |= NS_MATHML_OPERATOR_RSPACE_ATTR; 1.439 + } 1.440 + } 1.441 + 1.442 + // little extra tuning to round lspace & rspace to at least a pixel so that 1.443 + // operators don't look as if they are colliding with their operands 1.444 + if (leadingSpace || trailingSpace) { 1.445 + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); 1.446 + if (leadingSpace && leadingSpace < onePixel) 1.447 + leadingSpace = onePixel; 1.448 + if (trailingSpace && trailingSpace < onePixel) 1.449 + trailingSpace = onePixel; 1.450 + } 1.451 + 1.452 + // the values that we get from our attributes override the dictionary 1.453 + mEmbellishData.leadingSpace = leadingSpace; 1.454 + mEmbellishData.trailingSpace = trailingSpace; 1.455 + 1.456 + // Now see if there are user-defined attributes that override the dictionary. 1.457 + // XXX If an attribute can be forced to be true when it is false in the 1.458 + // dictionary, then the following code has to change... 1.459 + 1.460 + // For each attribute overriden by the user, turn off its bit flag. 1.461 + // symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form 1.462 + // special: accent and movablelimits are handled above, 1.463 + // don't process them here 1.464 + 1.465 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::stretchy_, value); 1.466 + if (value.EqualsLiteral("false")) { 1.467 + mFlags &= ~NS_MATHML_OPERATOR_STRETCHY; 1.468 + } else if (value.EqualsLiteral("true")) { 1.469 + mFlags |= NS_MATHML_OPERATOR_STRETCHY; 1.470 + } 1.471 + if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) { 1.472 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::fence_, value); 1.473 + if (value.EqualsLiteral("false")) 1.474 + mFlags &= ~NS_MATHML_OPERATOR_FENCE; 1.475 + } 1.476 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::largeop_, value); 1.477 + if (value.EqualsLiteral("false")) { 1.478 + mFlags &= ~NS_MATHML_OPERATOR_LARGEOP; 1.479 + } else if (value.EqualsLiteral("true")) { 1.480 + mFlags |= NS_MATHML_OPERATOR_LARGEOP; 1.481 + } 1.482 + if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) { 1.483 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separator_, value); 1.484 + if (value.EqualsLiteral("false")) 1.485 + mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR; 1.486 + } 1.487 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::symmetric_, value); 1.488 + if (value.EqualsLiteral("false")) 1.489 + mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC; 1.490 + else if (value.EqualsLiteral("true")) 1.491 + mFlags |= NS_MATHML_OPERATOR_SYMMETRIC; 1.492 + 1.493 + 1.494 + // minsize 1.495 + // 1.496 + // "Specifies the minimum size of the operator when stretchy" 1.497 + // 1.498 + // values: length 1.499 + // default: set by dictionary (1em) 1.500 + // 1.501 + // We don't allow negative values. 1.502 + // Note: Contrary to other "length" values, unitless and percentage do not 1.503 + // give a multiple of the defaut value but a multiple of the operator at 1.504 + // normal size. 1.505 + // 1.506 + mMinSize = 0; 1.507 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::minsize_, value); 1.508 + if (!value.IsEmpty()) { 1.509 + nsCSSValue cssValue; 1.510 + if (nsMathMLElement::ParseNumericValue(value, cssValue, 1.511 + nsMathMLElement:: 1.512 + PARSE_ALLOW_UNITLESS, 1.513 + mContent->OwnerDoc())) { 1.514 + nsCSSUnit unit = cssValue.GetUnit(); 1.515 + if (eCSSUnit_Number == unit) 1.516 + mMinSize = cssValue.GetFloatValue(); 1.517 + else if (eCSSUnit_Percent == unit) 1.518 + mMinSize = cssValue.GetPercentValue(); 1.519 + else if (eCSSUnit_Null != unit) { 1.520 + mMinSize = float(CalcLength(presContext, mStyleContext, cssValue)); 1.521 + mFlags |= NS_MATHML_OPERATOR_MINSIZE_ABSOLUTE; 1.522 + } 1.523 + } 1.524 + } 1.525 + 1.526 + // maxsize 1.527 + // 1.528 + // "Specifies the maximum size of the operator when stretchy" 1.529 + // 1.530 + // values: length | "infinity" 1.531 + // default: set by dictionary (infinity) 1.532 + // 1.533 + // We don't allow negative values. 1.534 + // Note: Contrary to other "length" values, unitless and percentage do not 1.535 + // give a multiple of the defaut value but a multiple of the operator at 1.536 + // normal size. 1.537 + // 1.538 + mMaxSize = NS_MATHML_OPERATOR_SIZE_INFINITY; 1.539 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::maxsize_, value); 1.540 + if (!value.IsEmpty()) { 1.541 + nsCSSValue cssValue; 1.542 + if (nsMathMLElement::ParseNumericValue(value, cssValue, 1.543 + nsMathMLElement:: 1.544 + PARSE_ALLOW_UNITLESS, 1.545 + mContent->OwnerDoc())) { 1.546 + nsCSSUnit unit = cssValue.GetUnit(); 1.547 + if (eCSSUnit_Number == unit) 1.548 + mMaxSize = cssValue.GetFloatValue(); 1.549 + else if (eCSSUnit_Percent == unit) 1.550 + mMaxSize = cssValue.GetPercentValue(); 1.551 + else if (eCSSUnit_Null != unit) { 1.552 + mMaxSize = float(CalcLength(presContext, mStyleContext, cssValue)); 1.553 + mFlags |= NS_MATHML_OPERATOR_MAXSIZE_ABSOLUTE; 1.554 + } 1.555 + } 1.556 + } 1.557 +} 1.558 + 1.559 +static uint32_t 1.560 +GetStretchHint(nsOperatorFlags aFlags, nsPresentationData aPresentationData, 1.561 + bool aIsVertical, const nsStyleFont* aStyleFont) 1.562 +{ 1.563 + uint32_t stretchHint = NS_STRETCH_NONE; 1.564 + // See if it is okay to stretch, 1.565 + // starting from what the Operator Dictionary said 1.566 + if (NS_MATHML_OPERATOR_IS_MUTABLE(aFlags)) { 1.567 + // set the largeop or largeopOnly flags to suitably cover all the 1.568 + // 8 possible cases depending on whether displaystyle, largeop, 1.569 + // stretchy are true or false (see bug 69325). 1.570 + // . largeopOnly is taken if largeop=true and stretchy=false 1.571 + // . largeop is taken if largeop=true and stretchy=true 1.572 + if (aStyleFont->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK && 1.573 + NS_MATHML_OPERATOR_IS_LARGEOP(aFlags)) { 1.574 + stretchHint = NS_STRETCH_LARGEOP; // (largeopOnly, not mask!) 1.575 + if (NS_MATHML_OPERATOR_IS_INTEGRAL(aFlags)) { 1.576 + stretchHint |= NS_STRETCH_INTEGRAL; 1.577 + } 1.578 + if (NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) { 1.579 + stretchHint |= NS_STRETCH_NEARER | NS_STRETCH_LARGER; 1.580 + } 1.581 + } 1.582 + else if(NS_MATHML_OPERATOR_IS_STRETCHY(aFlags)) { 1.583 + if (aIsVertical) { 1.584 + // TeX hint. Can impact some sloppy markups missing <mrow></mrow> 1.585 + stretchHint = NS_STRETCH_NEARER; 1.586 + } 1.587 + else { 1.588 + stretchHint = NS_STRETCH_NORMAL; 1.589 + } 1.590 + } 1.591 + // else if the stretchy and largeop attributes have been disabled, 1.592 + // the operator is not mutable 1.593 + } 1.594 + return stretchHint; 1.595 +} 1.596 + 1.597 +// NOTE: aDesiredStretchSize is an IN/OUT parameter 1.598 +// On input - it contains our current size 1.599 +// On output - the same size or the new size that we want 1.600 +NS_IMETHODIMP 1.601 +nsMathMLmoFrame::Stretch(nsRenderingContext& aRenderingContext, 1.602 + nsStretchDirection aStretchDirection, 1.603 + nsBoundingMetrics& aContainerSize, 1.604 + nsHTMLReflowMetrics& aDesiredStretchSize) 1.605 +{ 1.606 + if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) { 1.607 + NS_WARNING("it is wrong to fire stretch more than once on a frame"); 1.608 + return NS_OK; 1.609 + } 1.610 + mPresentationData.flags |= NS_MATHML_STRETCH_DONE; 1.611 + 1.612 + nsIFrame* firstChild = mFrames.FirstChild(); 1.613 + 1.614 + // get the axis height; 1.615 + nsRefPtr<nsFontMetrics> fm; 1.616 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.617 + aRenderingContext.SetFont(fm); 1.618 + nscoord axisHeight, height; 1.619 + GetAxisHeight(aRenderingContext, fm, axisHeight); 1.620 + 1.621 + // get the leading to be left at the top and the bottom of the stretched char 1.622 + // this seems more reliable than using fm->GetLeading() on suspicious fonts 1.623 + nscoord em; 1.624 + GetEmHeight(fm, em); 1.625 + nscoord leading = NSToCoordRound(0.2f * em); 1.626 + 1.627 + // Operators that are stretchy, or those that are to be centered 1.628 + // to cater for fonts that are not math-aware, are handled by the MathMLChar 1.629 + // ('form' is reset if stretch fails -- i.e., we don't bother to stretch next time) 1.630 + bool useMathMLChar = UseMathMLChar(); 1.631 + 1.632 + nsBoundingMetrics charSize; 1.633 + nsBoundingMetrics container = aDesiredStretchSize.mBoundingMetrics; 1.634 + bool isVertical = false; 1.635 + 1.636 + if (((aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) || 1.637 + (aStretchDirection == NS_STRETCH_DIRECTION_DEFAULT)) && 1.638 + (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL)) { 1.639 + isVertical = true; 1.640 + } 1.641 + 1.642 + uint32_t stretchHint = 1.643 + GetStretchHint(mFlags, mPresentationData, isVertical, StyleFont()); 1.644 + 1.645 + if (useMathMLChar) { 1.646 + nsBoundingMetrics initialSize = aDesiredStretchSize.mBoundingMetrics; 1.647 + 1.648 + if (stretchHint != NS_STRETCH_NONE) { 1.649 + 1.650 + container = aContainerSize; 1.651 + 1.652 + // some adjustments if the operator is symmetric and vertical 1.653 + 1.654 + if (isVertical && NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { 1.655 + // we need to center about the axis 1.656 + nscoord delta = std::max(container.ascent - axisHeight, 1.657 + container.descent + axisHeight); 1.658 + container.ascent = delta + axisHeight; 1.659 + container.descent = delta - axisHeight; 1.660 + 1.661 + // get ready in case we encounter user-desired min-max size 1.662 + delta = std::max(initialSize.ascent - axisHeight, 1.663 + initialSize.descent + axisHeight); 1.664 + initialSize.ascent = delta + axisHeight; 1.665 + initialSize.descent = delta - axisHeight; 1.666 + } 1.667 + 1.668 + // check for user-desired min-max size 1.669 + 1.670 + if (mMaxSize != NS_MATHML_OPERATOR_SIZE_INFINITY && mMaxSize > 0.0f) { 1.671 + // if we are here, there is a user defined maxsize ... 1.672 + //XXX Set stretchHint = NS_STRETCH_NORMAL? to honor the maxsize as close as possible? 1.673 + if (NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)) { 1.674 + // there is an explicit value like maxsize="20pt" 1.675 + // try to maintain the aspect ratio of the char 1.676 + float aspect = mMaxSize / float(initialSize.ascent + initialSize.descent); 1.677 + container.ascent = 1.678 + std::min(container.ascent, nscoord(initialSize.ascent * aspect)); 1.679 + container.descent = 1.680 + std::min(container.descent, nscoord(initialSize.descent * aspect)); 1.681 + // below we use a type cast instead of a conversion to avoid a VC++ bug 1.682 + // see http://support.microsoft.com/support/kb/articles/Q115/7/05.ASP 1.683 + container.width = 1.684 + std::min(container.width, (nscoord)mMaxSize); 1.685 + } 1.686 + else { // multiplicative value 1.687 + container.ascent = 1.688 + std::min(container.ascent, nscoord(initialSize.ascent * mMaxSize)); 1.689 + container.descent = 1.690 + std::min(container.descent, nscoord(initialSize.descent * mMaxSize)); 1.691 + container.width = 1.692 + std::min(container.width, nscoord(initialSize.width * mMaxSize)); 1.693 + } 1.694 + 1.695 + if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { 1.696 + // re-adjust to align the char with the bottom of the initial container 1.697 + height = container.ascent + container.descent; 1.698 + container.descent = aContainerSize.descent; 1.699 + container.ascent = height - container.descent; 1.700 + } 1.701 + } 1.702 + 1.703 + if (mMinSize > 0.0f) { 1.704 + // if we are here, there is a user defined minsize ... 1.705 + // always allow the char to stretch in its natural direction, 1.706 + // even if it is different from the caller's direction 1.707 + if (aStretchDirection != NS_STRETCH_DIRECTION_DEFAULT && 1.708 + aStretchDirection != mEmbellishData.direction) { 1.709 + aStretchDirection = NS_STRETCH_DIRECTION_DEFAULT; 1.710 + // but when we are not honoring the requested direction 1.711 + // we should not use the caller's container size either 1.712 + container = initialSize; 1.713 + } 1.714 + if (NS_MATHML_OPERATOR_MINSIZE_IS_ABSOLUTE(mFlags)) { 1.715 + // there is an explicit value like minsize="20pt" 1.716 + // try to maintain the aspect ratio of the char 1.717 + float aspect = mMinSize / float(initialSize.ascent + initialSize.descent); 1.718 + container.ascent = 1.719 + std::max(container.ascent, nscoord(initialSize.ascent * aspect)); 1.720 + container.descent = 1.721 + std::max(container.descent, nscoord(initialSize.descent * aspect)); 1.722 + container.width = 1.723 + std::max(container.width, (nscoord)mMinSize); 1.724 + } 1.725 + else { // multiplicative value 1.726 + container.ascent = 1.727 + std::max(container.ascent, nscoord(initialSize.ascent * mMinSize)); 1.728 + container.descent = 1.729 + std::max(container.descent, nscoord(initialSize.descent * mMinSize)); 1.730 + container.width = 1.731 + std::max(container.width, nscoord(initialSize.width * mMinSize)); 1.732 + } 1.733 + 1.734 + if (isVertical && !NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags)) { 1.735 + // re-adjust to align the char with the bottom of the initial container 1.736 + height = container.ascent + container.descent; 1.737 + container.descent = aContainerSize.descent; 1.738 + container.ascent = height - container.descent; 1.739 + } 1.740 + } 1.741 + } 1.742 + 1.743 + // let the MathMLChar stretch itself... 1.744 + nsresult res = mMathMLChar.Stretch(PresContext(), aRenderingContext, 1.745 + aStretchDirection, container, charSize, 1.746 + stretchHint, 1.747 + StyleVisibility()->mDirection); 1.748 + if (NS_FAILED(res)) { 1.749 + // gracefully handle cases where stretching the char failed (i.e., GetBoundingMetrics failed) 1.750 + // clear our 'form' to behave as if the operator wasn't in the dictionary 1.751 + mFlags &= ~NS_MATHML_OPERATOR_FORM; 1.752 + useMathMLChar = false; 1.753 + } 1.754 + } 1.755 + 1.756 + // Place our children using the default method 1.757 + // This will allow our child text frame to get its DidReflow() 1.758 + nsresult rv = Place(aRenderingContext, true, aDesiredStretchSize); 1.759 + if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) { 1.760 + // Make sure the child frames get their DidReflow() calls. 1.761 + DidReflowChildren(mFrames.FirstChild()); 1.762 + } 1.763 + 1.764 + if (useMathMLChar) { 1.765 + // update our bounding metrics... it becomes that of our MathML char 1.766 + mBoundingMetrics = charSize; 1.767 + 1.768 + // if the returned direction is 'unsupported', the char didn't actually change. 1.769 + // So we do the centering only if necessary 1.770 + if (mMathMLChar.GetStretchDirection() != NS_STRETCH_DIRECTION_UNSUPPORTED || 1.771 + NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { 1.772 + 1.773 + bool largeopOnly = 1.774 + (NS_STRETCH_LARGEOP & stretchHint) != 0 && 1.775 + (NS_STRETCH_VARIABLE_MASK & stretchHint) == 0; 1.776 + 1.777 + if (isVertical || NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { 1.778 + // the desired size returned by mMathMLChar maybe different 1.779 + // from the size of the container. 1.780 + // the mMathMLChar.mRect.y calculation is subtle, watch out!!! 1.781 + 1.782 + height = mBoundingMetrics.ascent + mBoundingMetrics.descent; 1.783 + if (NS_MATHML_OPERATOR_IS_SYMMETRIC(mFlags) || 1.784 + NS_MATHML_OPERATOR_IS_CENTERED(mFlags)) { 1.785 + // For symmetric and vertical operators, or for operators that are always 1.786 + // centered ('+', '*', etc) we want to center about the axis of the container 1.787 + mBoundingMetrics.descent = height/2 - axisHeight; 1.788 + } else if (!largeopOnly) { 1.789 + // Align the center of the char with the center of the container 1.790 + mBoundingMetrics.descent = height/2 + 1.791 + (container.ascent + container.descent)/2 - container.ascent; 1.792 + } // else align the baselines 1.793 + mBoundingMetrics.ascent = height - mBoundingMetrics.descent; 1.794 + } 1.795 + } 1.796 + } 1.797 + 1.798 + // Fixup for the final height. 1.799 + // On one hand, our stretchy height can sometimes be shorter than surrounding 1.800 + // ASCII chars, e.g., arrow symbols have |mBoundingMetrics.ascent + leading| 1.801 + // that is smaller than the ASCII's ascent, hence when painting the background 1.802 + // later, it won't look uniform along the line. 1.803 + // On the other hand, sometimes we may leave too much gap when our glyph happens 1.804 + // to come from a font with tall glyphs. For example, since CMEX10 has very tall 1.805 + // glyphs, its natural font metrics are large, even if we pick a small glyph 1.806 + // whose size is comparable to the size of a normal ASCII glyph. 1.807 + // So to avoid uneven spacing in either of these two cases, we use the height 1.808 + // of the ASCII font as a reference and try to match it if possible. 1.809 + 1.810 + // special case for accents... keep them short to improve mouse operations... 1.811 + // an accent can only be the non-first child of <mover>, <munder>, <munderover> 1.812 + bool isAccent = 1.813 + NS_MATHML_EMBELLISH_IS_ACCENT(mEmbellishData.flags); 1.814 + if (isAccent) { 1.815 + nsEmbellishData parentData; 1.816 + GetEmbellishDataFrom(mParent, parentData); 1.817 + isAccent = 1.818 + (NS_MATHML_EMBELLISH_IS_ACCENTOVER(parentData.flags) || 1.819 + NS_MATHML_EMBELLISH_IS_ACCENTUNDER(parentData.flags)) && 1.820 + parentData.coreFrame != this; 1.821 + } 1.822 + if (isAccent && firstChild) { 1.823 + // see bug 188467 for what is going on here 1.824 + nscoord dy = aDesiredStretchSize.TopAscent() - (mBoundingMetrics.ascent + leading); 1.825 + aDesiredStretchSize.SetTopAscent(mBoundingMetrics.ascent + leading); 1.826 + aDesiredStretchSize.Height() = aDesiredStretchSize.TopAscent() + mBoundingMetrics.descent; 1.827 + 1.828 + firstChild->SetPosition(firstChild->GetPosition() - nsPoint(0, dy)); 1.829 + } 1.830 + else if (useMathMLChar) { 1.831 + nscoord ascent = fm->MaxAscent(); 1.832 + nscoord descent = fm->MaxDescent(); 1.833 + aDesiredStretchSize.SetTopAscent(std::max(mBoundingMetrics.ascent + leading, ascent)); 1.834 + aDesiredStretchSize.Height() = aDesiredStretchSize.TopAscent() + 1.835 + std::max(mBoundingMetrics.descent + leading, descent); 1.836 + } 1.837 + aDesiredStretchSize.Width() = mBoundingMetrics.width; 1.838 + aDesiredStretchSize.mBoundingMetrics = mBoundingMetrics; 1.839 + mReference.x = 0; 1.840 + mReference.y = aDesiredStretchSize.TopAscent(); 1.841 + // Place our mMathMLChar, its origin is in our coordinate system 1.842 + if (useMathMLChar) { 1.843 + nscoord dy = aDesiredStretchSize.TopAscent() - mBoundingMetrics.ascent; 1.844 + mMathMLChar.SetRect(nsRect(0, dy, charSize.width, charSize.ascent + charSize.descent)); 1.845 + } 1.846 + 1.847 + // Before we leave... there is a last item in the check-list: 1.848 + // If our parent is not embellished, it means we are the outermost embellished 1.849 + // container and so we put the spacing, otherwise we don't include the spacing, 1.850 + // the outermost embellished container will take care of it. 1.851 + 1.852 + if (!NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) { 1.853 + 1.854 + // Account the spacing if we are not an accent with explicit attributes 1.855 + nscoord leadingSpace = mEmbellishData.leadingSpace; 1.856 + if (isAccent && !NS_MATHML_OPERATOR_HAS_LSPACE_ATTR(mFlags)) { 1.857 + leadingSpace = 0; 1.858 + } 1.859 + nscoord trailingSpace = mEmbellishData.trailingSpace; 1.860 + if (isAccent && !NS_MATHML_OPERATOR_HAS_RSPACE_ATTR(mFlags)) { 1.861 + trailingSpace = 0; 1.862 + } 1.863 + 1.864 + mBoundingMetrics.width += leadingSpace + trailingSpace; 1.865 + aDesiredStretchSize.Width() = mBoundingMetrics.width; 1.866 + aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width; 1.867 + 1.868 + nscoord dx = (StyleVisibility()->mDirection ? 1.869 + trailingSpace : leadingSpace); 1.870 + if (dx) { 1.871 + // adjust the offsets 1.872 + mBoundingMetrics.leftBearing += dx; 1.873 + mBoundingMetrics.rightBearing += dx; 1.874 + aDesiredStretchSize.mBoundingMetrics.leftBearing += dx; 1.875 + aDesiredStretchSize.mBoundingMetrics.rightBearing += dx; 1.876 + 1.877 + if (useMathMLChar) { 1.878 + nsRect rect; 1.879 + mMathMLChar.GetRect(rect); 1.880 + mMathMLChar.SetRect(nsRect(rect.x + dx, rect.y, 1.881 + rect.width, rect.height)); 1.882 + } 1.883 + else { 1.884 + nsIFrame* childFrame = firstChild; 1.885 + while (childFrame) { 1.886 + childFrame->SetPosition(childFrame->GetPosition() + 1.887 + nsPoint(dx, 0)); 1.888 + childFrame = childFrame->GetNextSibling(); 1.889 + } 1.890 + } 1.891 + } 1.892 + } 1.893 + 1.894 + // Finished with these: 1.895 + ClearSavedChildMetrics(); 1.896 + // Set our overflow area 1.897 + GatherAndStoreOverflow(&aDesiredStretchSize); 1.898 + 1.899 + // There used to be code here to change the height of the child frame to 1.900 + // change the caret height, but the text frame that manages the caret is now 1.901 + // not a direct child but wrapped in a block frame. See also bug 412033. 1.902 + 1.903 + return NS_OK; 1.904 +} 1.905 + 1.906 +NS_IMETHODIMP 1.907 +nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent) 1.908 +{ 1.909 + // retain our native direction, it only changes if our text content changes 1.910 + nsStretchDirection direction = mEmbellishData.direction; 1.911 + nsMathMLTokenFrame::InheritAutomaticData(aParent); 1.912 + ProcessTextData(); 1.913 + mEmbellishData.direction = direction; 1.914 + return NS_OK; 1.915 +} 1.916 + 1.917 +NS_IMETHODIMP 1.918 +nsMathMLmoFrame::TransmitAutomaticData() 1.919 +{ 1.920 + // this will cause us to re-sync our flags from scratch 1.921 + // but our returned 'form' is still not final (bug 133429), it will 1.922 + // be recomputed to its final value during the next call in Reflow() 1.923 + mEmbellishData.coreFrame = nullptr; 1.924 + ProcessOperatorData(); 1.925 + return NS_OK; 1.926 +} 1.927 + 1.928 +nsresult 1.929 +nsMathMLmoFrame::SetInitialChildList(ChildListID aListID, 1.930 + nsFrameList& aChildList) 1.931 +{ 1.932 + // First, let the parent class do its work 1.933 + nsresult rv = nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList); 1.934 + if (NS_FAILED(rv)) 1.935 + return rv; 1.936 + 1.937 + ProcessTextData(); 1.938 + return rv; 1.939 +} 1.940 + 1.941 +nsresult 1.942 +nsMathMLmoFrame::Reflow(nsPresContext* aPresContext, 1.943 + nsHTMLReflowMetrics& aDesiredSize, 1.944 + const nsHTMLReflowState& aReflowState, 1.945 + nsReflowStatus& aStatus) 1.946 +{ 1.947 + // certain values use units that depend on our style context, so 1.948 + // it is safer to just process the whole lot here 1.949 + ProcessOperatorData(); 1.950 + 1.951 + return nsMathMLTokenFrame::Reflow(aPresContext, aDesiredSize, 1.952 + aReflowState, aStatus); 1.953 +} 1.954 + 1.955 +/* virtual */ void 1.956 +nsMathMLmoFrame::MarkIntrinsicWidthsDirty() 1.957 +{ 1.958 + // if we get this, it may mean that something changed in the text 1.959 + // content. So blow away everything an re-build the automatic data 1.960 + // from the parent of our outermost embellished container (we ensure 1.961 + // that we are the core, not just a sibling of the core) 1.962 + 1.963 + ProcessTextData(); 1.964 + 1.965 + nsIFrame* target = this; 1.966 + nsEmbellishData embellishData; 1.967 + do { 1.968 + target = target->GetParent(); 1.969 + GetEmbellishDataFrom(target, embellishData); 1.970 + } while (embellishData.coreFrame == this); 1.971 + 1.972 + // we have automatic data to update in the children of the target frame 1.973 + // XXXldb This should really be marking dirty rather than rebuilding 1.974 + // so that we don't rebuild multiple times for the same change. 1.975 + RebuildAutomaticDataForChildren(target); 1.976 + 1.977 + nsMathMLContainerFrame::MarkIntrinsicWidthsDirty(); 1.978 +} 1.979 + 1.980 +/* virtual */ void 1.981 +nsMathMLmoFrame::GetIntrinsicWidthMetrics(nsRenderingContext *aRenderingContext, nsHTMLReflowMetrics& aDesiredSize) 1.982 +{ 1.983 + ProcessOperatorData(); 1.984 + if (UseMathMLChar()) { 1.985 + uint32_t stretchHint = GetStretchHint(mFlags, mPresentationData, true, 1.986 + StyleFont()); 1.987 + aDesiredSize.Width() = mMathMLChar. 1.988 + GetMaxWidth(PresContext(), *aRenderingContext, 1.989 + stretchHint, mMaxSize, 1.990 + NS_MATHML_OPERATOR_MAXSIZE_IS_ABSOLUTE(mFlags)); 1.991 + } 1.992 + else { 1.993 + nsMathMLTokenFrame::GetIntrinsicWidthMetrics(aRenderingContext, 1.994 + aDesiredSize); 1.995 + } 1.996 + 1.997 + // leadingSpace and trailingSpace are actually applied to the outermost 1.998 + // embellished container but for determining total intrinsic width it should 1.999 + // be safe to include it for the core here instead. 1.1000 + bool isRTL = StyleVisibility()->mDirection; 1.1001 + aDesiredSize.Width() += 1.1002 + mEmbellishData.leadingSpace + mEmbellishData.trailingSpace; 1.1003 + aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width(); 1.1004 + if (isRTL) { 1.1005 + aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.trailingSpace; 1.1006 + aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.trailingSpace; 1.1007 + } else { 1.1008 + aDesiredSize.mBoundingMetrics.leftBearing += mEmbellishData.leadingSpace; 1.1009 + aDesiredSize.mBoundingMetrics.rightBearing += mEmbellishData.leadingSpace; 1.1010 + } 1.1011 +} 1.1012 + 1.1013 +nsresult 1.1014 +nsMathMLmoFrame::AttributeChanged(int32_t aNameSpaceID, 1.1015 + nsIAtom* aAttribute, 1.1016 + int32_t aModType) 1.1017 +{ 1.1018 + // check if this is an attribute that can affect the embellished hierarchy 1.1019 + // in a significant way and re-layout the entire hierarchy. 1.1020 + if (nsGkAtoms::accent_ == aAttribute || 1.1021 + nsGkAtoms::movablelimits_ == aAttribute) { 1.1022 + 1.1023 + // set the target as the parent of our outermost embellished container 1.1024 + // (we ensure that we are the core, not just a sibling of the core) 1.1025 + nsIFrame* target = this; 1.1026 + nsEmbellishData embellishData; 1.1027 + do { 1.1028 + target = target->GetParent(); 1.1029 + GetEmbellishDataFrom(target, embellishData); 1.1030 + } while (embellishData.coreFrame == this); 1.1031 + 1.1032 + // we have automatic data to update in the children of the target frame 1.1033 + return ReLayoutChildren(target); 1.1034 + } 1.1035 + 1.1036 + return nsMathMLTokenFrame:: 1.1037 + AttributeChanged(aNameSpaceID, aAttribute, aModType); 1.1038 +} 1.1039 + 1.1040 +// ---------------------- 1.1041 +// No need to track the style context given to our MathML char. 1.1042 +// the Style System will use these to pass the proper style context to our MathMLChar 1.1043 +nsStyleContext* 1.1044 +nsMathMLmoFrame::GetAdditionalStyleContext(int32_t aIndex) const 1.1045 +{ 1.1046 + switch (aIndex) { 1.1047 + case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX: 1.1048 + return mMathMLChar.GetStyleContext(); 1.1049 + default: 1.1050 + return nullptr; 1.1051 + } 1.1052 +} 1.1053 + 1.1054 +void 1.1055 +nsMathMLmoFrame::SetAdditionalStyleContext(int32_t aIndex, 1.1056 + nsStyleContext* aStyleContext) 1.1057 +{ 1.1058 + switch (aIndex) { 1.1059 + case NS_MATHML_CHAR_STYLE_CONTEXT_INDEX: 1.1060 + mMathMLChar.SetStyleContext(aStyleContext); 1.1061 + break; 1.1062 + } 1.1063 +}