1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/mathml/nsMathMLmunderoverFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,624 @@ 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 "nsMathMLmunderoverFrame.h" 1.10 +#include "nsPresContext.h" 1.11 +#include "nsRenderingContext.h" 1.12 +#include "nsMathMLmmultiscriptsFrame.h" 1.13 +#include <algorithm> 1.14 + 1.15 +// 1.16 +// <munderover> -- attach an underscript-overscript pair to a base - implementation 1.17 +// <mover> -- attach an overscript to a base - implementation 1.18 +// <munder> -- attach an underscript to a base - implementation 1.19 +// 1.20 + 1.21 +nsIFrame* 1.22 +NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.23 +{ 1.24 + return new (aPresShell) nsMathMLmunderoverFrame(aContext); 1.25 +} 1.26 + 1.27 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmunderoverFrame) 1.28 + 1.29 +nsMathMLmunderoverFrame::~nsMathMLmunderoverFrame() 1.30 +{ 1.31 +} 1.32 + 1.33 +nsresult 1.34 +nsMathMLmunderoverFrame::AttributeChanged(int32_t aNameSpaceID, 1.35 + nsIAtom* aAttribute, 1.36 + int32_t aModType) 1.37 +{ 1.38 + if (nsGkAtoms::accent_ == aAttribute || 1.39 + nsGkAtoms::accentunder_ == aAttribute) { 1.40 + // When we have automatic data to update within ourselves, we ask our 1.41 + // parent to re-layout its children 1.42 + return ReLayoutChildren(mParent); 1.43 + } 1.44 + 1.45 + return nsMathMLContainerFrame:: 1.46 + AttributeChanged(aNameSpaceID, aAttribute, aModType); 1.47 +} 1.48 + 1.49 +NS_IMETHODIMP 1.50 +nsMathMLmunderoverFrame::UpdatePresentationData(uint32_t aFlagsValues, 1.51 + uint32_t aFlagsToUpdate) 1.52 +{ 1.53 + nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues, aFlagsToUpdate); 1.54 + // disable the stretch-all flag if we are going to act like a subscript-superscript pair 1.55 + if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && 1.56 + StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) { 1.57 + mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; 1.58 + } 1.59 + else { 1.60 + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; 1.61 + } 1.62 + return NS_OK; 1.63 +} 1.64 + 1.65 +NS_IMETHODIMP 1.66 +nsMathMLmunderoverFrame::InheritAutomaticData(nsIFrame* aParent) 1.67 +{ 1.68 + // let the base class get the default from our parent 1.69 + nsMathMLContainerFrame::InheritAutomaticData(aParent); 1.70 + 1.71 + mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; 1.72 + 1.73 + return NS_OK; 1.74 +} 1.75 + 1.76 +uint8_t 1.77 +nsMathMLmunderoverFrame::ScriptIncrement(nsIFrame* aFrame) 1.78 +{ 1.79 + nsIFrame* child = mFrames.FirstChild(); 1.80 + if (!aFrame || aFrame == child) { 1.81 + return 0; 1.82 + } 1.83 + child = child->GetNextSibling(); 1.84 + if (aFrame == child) { 1.85 + if (mContent->Tag() == nsGkAtoms::mover_) { 1.86 + return mIncrementOver ? 1 : 0; 1.87 + } 1.88 + return mIncrementUnder ? 1 : 0; 1.89 + } 1.90 + if (child && aFrame == child->GetNextSibling()) { 1.91 + // must be a over frame of munderover 1.92 + return mIncrementOver ? 1 : 0; 1.93 + } 1.94 + return 0; // frame not found 1.95 +} 1.96 + 1.97 +NS_IMETHODIMP 1.98 +nsMathMLmunderoverFrame::TransmitAutomaticData() 1.99 +{ 1.100 + // At this stage, all our children are in sync and we can fully 1.101 + // resolve our own mEmbellishData struct 1.102 + //--------------------------------------------------------------------- 1.103 + 1.104 + /* 1.105 + The REC says: 1.106 + 1.107 + As regards munder (respectively mover) : 1.108 + The default value of accentunder is false, unless underscript 1.109 + is an <mo> element or an embellished operator. If underscript is 1.110 + an <mo> element, the value of its accent attribute is used as the 1.111 + default value of accentunder. If underscript is an embellished 1.112 + operator, the accent attribute of the <mo> element at its 1.113 + core is used as the default value. As with all attributes, an 1.114 + explicitly given value overrides the default. 1.115 + 1.116 +XXX The winner is the outermost setting in conflicting settings like these: 1.117 +<munder accentunder='true'> 1.118 + <mi>...</mi> 1.119 + <mo accentunder='false'> ... </mo> 1.120 +</munder> 1.121 + 1.122 + As regards munderover: 1.123 + The accent and accentunder attributes have the same effect as 1.124 + the attributes with the same names on <mover> and <munder>, 1.125 + respectively. Their default values are also computed in the 1.126 + same manner as described for those elements, with the default 1.127 + value of accent depending on overscript and the default value 1.128 + of accentunder depending on underscript. 1.129 + */ 1.130 + 1.131 + nsIFrame* overscriptFrame = nullptr; 1.132 + nsIFrame* underscriptFrame = nullptr; 1.133 + nsIFrame* baseFrame = mFrames.FirstChild(); 1.134 + nsIAtom* tag = mContent->Tag(); 1.135 + 1.136 + if (baseFrame) { 1.137 + if (tag == nsGkAtoms::munder_ || 1.138 + tag == nsGkAtoms::munderover_) { 1.139 + underscriptFrame = baseFrame->GetNextSibling(); 1.140 + } else { 1.141 + NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized"); 1.142 + overscriptFrame = baseFrame->GetNextSibling(); 1.143 + } 1.144 + } 1.145 + if (underscriptFrame && 1.146 + tag == nsGkAtoms::munderover_) { 1.147 + overscriptFrame = underscriptFrame->GetNextSibling(); 1.148 + 1.149 + } 1.150 + 1.151 + // if our base is an embellished operator, let its state bubble to us (in particular, 1.152 + // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags 1.153 + // are reset to the default values of false if the base frame isn't embellished. 1.154 + mPresentationData.baseFrame = baseFrame; 1.155 + GetEmbellishDataFrom(baseFrame, mEmbellishData); 1.156 + 1.157 + // The default value of accentunder is false, unless the underscript is embellished 1.158 + // and its core <mo> is an accent 1.159 + nsEmbellishData embellishData; 1.160 + nsAutoString value; 1.161 + if (tag == nsGkAtoms::munder_ || 1.162 + tag == nsGkAtoms::munderover_) { 1.163 + GetEmbellishDataFrom(underscriptFrame, embellishData); 1.164 + if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) { 1.165 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER; 1.166 + } else { 1.167 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER; 1.168 + } 1.169 + 1.170 + // if we have an accentunder attribute, it overrides what the underscript said 1.171 + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accentunder_, value)) { 1.172 + if (value.EqualsLiteral("true")) { 1.173 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER; 1.174 + } else if (value.EqualsLiteral("false")) { 1.175 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER; 1.176 + } 1.177 + } 1.178 + } 1.179 + 1.180 + // The default value of accent is false, unless the overscript is embellished 1.181 + // and its core <mo> is an accent 1.182 + if (tag == nsGkAtoms::mover_ || 1.183 + tag == nsGkAtoms::munderover_) { 1.184 + GetEmbellishDataFrom(overscriptFrame, embellishData); 1.185 + if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) { 1.186 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; 1.187 + } else { 1.188 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; 1.189 + } 1.190 + 1.191 + // if we have an accent attribute, it overrides what the overscript said 1.192 + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value)) { 1.193 + if (value.EqualsLiteral("true")) { 1.194 + mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER; 1.195 + } else if (value.EqualsLiteral("false")) { 1.196 + mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER; 1.197 + } 1.198 + } 1.199 + } 1.200 + 1.201 + bool subsupDisplay = 1.202 + NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && 1.203 + StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE; 1.204 + 1.205 + // disable the stretch-all flag if we are going to act like a superscript 1.206 + if (subsupDisplay) { 1.207 + mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY; 1.208 + } 1.209 + 1.210 + // Now transmit any change that we want to our children so that they 1.211 + // can update their mPresentationData structs 1.212 + //--------------------------------------------------------------------- 1.213 + 1.214 + /* The REC says: 1.215 + Within underscript, <munderover> always sets displaystyle to "false", 1.216 + but increments scriptlevel by 1 only when accentunder is "false". 1.217 + 1.218 + Within overscript, <munderover> always sets displaystyle to "false", 1.219 + but increments scriptlevel by 1 only when accent is "false". 1.220 + 1.221 + Within subscript and superscript it increments scriptlevel by 1, and 1.222 + sets displaystyle to "false", but leaves both attributes unchanged within 1.223 + base. 1.224 + 1.225 + The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a 1.226 + say it shouldn't be compressed. However, The TeXBook says 1.227 + that math accents and \overline change uncramped styles to their 1.228 + cramped counterparts. 1.229 + */ 1.230 + if (tag == nsGkAtoms::mover_ || 1.231 + tag == nsGkAtoms::munderover_) { 1.232 + uint32_t compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) 1.233 + ? NS_MATHML_COMPRESSED : 0; 1.234 + mIncrementOver = 1.235 + !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) || 1.236 + subsupDisplay; 1.237 + SetIncrementScriptLevel(tag == nsGkAtoms::mover_ ? 1 : 2, mIncrementOver); 1.238 + if (mIncrementOver) { 1.239 + PropagateFrameFlagFor(overscriptFrame, 1.240 + NS_FRAME_MATHML_SCRIPT_DESCENDANT); 1.241 + } 1.242 + PropagatePresentationDataFor(overscriptFrame, compress, compress); 1.243 + } 1.244 + /* 1.245 + The TeXBook treats 'under' like a subscript, so p.141 or Rule 13a 1.246 + say it should be compressed 1.247 + */ 1.248 + if (tag == nsGkAtoms::munder_ || 1.249 + tag == nsGkAtoms::munderover_) { 1.250 + mIncrementUnder = 1.251 + !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags) || 1.252 + subsupDisplay; 1.253 + SetIncrementScriptLevel(1, mIncrementUnder); 1.254 + if (mIncrementUnder) { 1.255 + PropagateFrameFlagFor(underscriptFrame, 1.256 + NS_FRAME_MATHML_SCRIPT_DESCENDANT); 1.257 + } 1.258 + PropagatePresentationDataFor(underscriptFrame, 1.259 + NS_MATHML_COMPRESSED, 1.260 + NS_MATHML_COMPRESSED); 1.261 + } 1.262 + return NS_OK; 1.263 +} 1.264 + 1.265 +/* 1.266 +The REC says: 1.267 +* If the base is an operator with movablelimits="true" (or an embellished 1.268 + operator whose <mo> element core has movablelimits="true"), and 1.269 + displaystyle="false", then underscript and overscript are drawn in 1.270 + a subscript and superscript position, respectively. In this case, 1.271 + the accent and accentunder attributes are ignored. This is often 1.272 + used for limits on symbols such as ∑. 1.273 + 1.274 +i.e.,: 1.275 + if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishDataflags) && 1.276 + StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) { 1.277 + // place like subscript-superscript pair 1.278 + } 1.279 + else { 1.280 + // place like underscript-overscript pair 1.281 + } 1.282 +*/ 1.283 + 1.284 +/* virtual */ nsresult 1.285 +nsMathMLmunderoverFrame::Place(nsRenderingContext& aRenderingContext, 1.286 + bool aPlaceOrigin, 1.287 + nsHTMLReflowMetrics& aDesiredSize) 1.288 +{ 1.289 + nsIAtom* tag = mContent->Tag(); 1.290 + if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) && 1.291 + StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) { 1.292 + //place like sub sup or subsup 1.293 + nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); 1.294 + if (tag == nsGkAtoms::munderover_) { 1.295 + return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(), 1.296 + aRenderingContext, 1.297 + aPlaceOrigin, 1.298 + aDesiredSize, 1.299 + this, 0, 0, 1.300 + scriptSpace); 1.301 + } else if (tag == nsGkAtoms::munder_) { 1.302 + return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(), 1.303 + aRenderingContext, 1.304 + aPlaceOrigin, 1.305 + aDesiredSize, 1.306 + this, 0, 0, 1.307 + scriptSpace); 1.308 + } else { 1.309 + NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized"); 1.310 + return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(), 1.311 + aRenderingContext, 1.312 + aPlaceOrigin, 1.313 + aDesiredSize, 1.314 + this, 0, 0, 1.315 + scriptSpace); 1.316 + } 1.317 + 1.318 + } 1.319 + 1.320 + //////////////////////////////////// 1.321 + // Get the children's desired sizes 1.322 + 1.323 + nsBoundingMetrics bmBase, bmUnder, bmOver; 1.324 + nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode()); 1.325 + nsHTMLReflowMetrics underSize(aDesiredSize.GetWritingMode()); 1.326 + nsHTMLReflowMetrics overSize(aDesiredSize.GetWritingMode()); 1.327 + nsIFrame* overFrame = nullptr; 1.328 + nsIFrame* underFrame = nullptr; 1.329 + nsIFrame* baseFrame = mFrames.FirstChild(); 1.330 + underSize.SetTopAscent(0); 1.331 + overSize.SetTopAscent(0); 1.332 + bool haveError = false; 1.333 + if (baseFrame) { 1.334 + if (tag == nsGkAtoms::munder_ || 1.335 + tag == nsGkAtoms::munderover_) { 1.336 + underFrame = baseFrame->GetNextSibling(); 1.337 + } else if (tag == nsGkAtoms::mover_) { 1.338 + overFrame = baseFrame->GetNextSibling(); 1.339 + } 1.340 + } 1.341 + if (underFrame && tag == nsGkAtoms::munderover_) { 1.342 + overFrame = underFrame->GetNextSibling(); 1.343 + } 1.344 + 1.345 + if (tag == nsGkAtoms::munder_) { 1.346 + if (!baseFrame || !underFrame || underFrame->GetNextSibling()) { 1.347 + // report an error, encourage people to get their markups in order 1.348 + haveError = true; 1.349 + } 1.350 + } 1.351 + if (tag == nsGkAtoms::mover_) { 1.352 + if (!baseFrame || !overFrame || overFrame->GetNextSibling()) { 1.353 + // report an error, encourage people to get their markups in order 1.354 + haveError = true; 1.355 + } 1.356 + } 1.357 + if (tag == nsGkAtoms::munderover_) { 1.358 + if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) { 1.359 + // report an error, encourage people to get their markups in order 1.360 + haveError = true; 1.361 + } 1.362 + } 1.363 + if (haveError) { 1.364 + if (aPlaceOrigin) { 1.365 + ReportChildCountError(); 1.366 + } 1.367 + return ReflowError(aRenderingContext, aDesiredSize); 1.368 + } 1.369 + GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); 1.370 + if (underFrame) { 1.371 + GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder); 1.372 + } 1.373 + if (overFrame) { 1.374 + GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver); 1.375 + } 1.376 + 1.377 + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); 1.378 + 1.379 + //////////////////// 1.380 + // Place Children 1.381 + 1.382 + nsRefPtr<nsFontMetrics> fm; 1.383 + nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm)); 1.384 + aRenderingContext.SetFont(fm); 1.385 + 1.386 + nscoord xHeight = fm->XHeight(); 1.387 + 1.388 + nscoord ruleThickness; 1.389 + GetRuleThickness (aRenderingContext, fm, ruleThickness); 1.390 + 1.391 + nscoord correction = 0; 1.392 + GetItalicCorrection (bmBase, correction); 1.393 + 1.394 + // there are 2 different types of placement depending on 1.395 + // whether we want an accented under or not 1.396 + 1.397 + nscoord underDelta1 = 0; // gap between base and underscript 1.398 + nscoord underDelta2 = 0; // extra space beneath underscript 1.399 + 1.400 + if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { 1.401 + // Rule 13a, App. G, TeXbook 1.402 + nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; 1.403 + GetBigOpSpacings (fm, 1.404 + dummy, bigOpSpacing2, 1.405 + dummy, bigOpSpacing4, 1.406 + bigOpSpacing5); 1.407 + underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent)); 1.408 + underDelta2 = bigOpSpacing5; 1.409 + } 1.410 + else { 1.411 + // No corresponding rule in TeXbook - we are on our own here 1.412 + // XXX tune the gap delta between base and underscript 1.413 + 1.414 + // Should we use Rule 10 like \underline does? 1.415 + underDelta1 = ruleThickness + onePixel/2; 1.416 + underDelta2 = ruleThickness; 1.417 + } 1.418 + // empty under? 1.419 + if (!(bmUnder.ascent + bmUnder.descent)) { 1.420 + underDelta1 = 0; 1.421 + underDelta2 = 0; 1.422 + } 1.423 + 1.424 + nscoord overDelta1 = 0; // gap between base and overscript 1.425 + nscoord overDelta2 = 0; // extra space above overscript 1.426 + 1.427 + if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { 1.428 + // Rule 13a, App. G, TeXbook 1.429 + nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; 1.430 + GetBigOpSpacings (fm, 1.431 + bigOpSpacing1, dummy, 1.432 + bigOpSpacing3, dummy, 1.433 + bigOpSpacing5); 1.434 + overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent)); 1.435 + overDelta2 = bigOpSpacing5; 1.436 + 1.437 + // XXX This is not a TeX rule... 1.438 + // delta1 (as computed abvove) can become really big when bmOver.descent is 1.439 + // negative, e.g., if the content is &OverBar. In such case, we use the height 1.440 + if (bmOver.descent < 0) 1.441 + overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent))); 1.442 + } 1.443 + else { 1.444 + // Rule 12, App. G, TeXbook 1.445 + // We are going to modify this rule to make it more general. 1.446 + // The idea behind Rule 12 in the TeXBook is to keep the accent 1.447 + // as close to the base as possible, while ensuring that the 1.448 + // distance between the *baseline* of the accent char and 1.449 + // the *baseline* of the base is atleast x-height. 1.450 + // The idea is that for normal use, we would like all the accents 1.451 + // on a line to line up atleast x-height above the baseline 1.452 + // if possible. 1.453 + // When the ascent of the base is >= x-height, 1.454 + // the baseline of the accent char is placed just above the base 1.455 + // (specifically, the baseline of the accent char is placed 1.456 + // above the baseline of the base by the ascent of the base). 1.457 + // For ease of implementation, 1.458 + // this assumes that the font-designer designs accents 1.459 + // in such a way that the bottom of the accent is atleast x-height 1.460 + // above its baseline, otherwise there will be collisions 1.461 + // with the base. Also there should be proper padding between 1.462 + // the bottom of the accent char and its baseline. 1.463 + // The above rule may not be obvious from a first 1.464 + // reading of rule 12 in the TeXBook !!! 1.465 + // The mathml <mover> tag can use accent chars that 1.466 + // do not follow this convention. So we modify TeX's rule 1.467 + // so that TeX's rule gets subsumed for accents that follow 1.468 + // TeX's convention, 1.469 + // while also allowing accents that do not follow the convention : 1.470 + // we try to keep the *bottom* of the accent char atleast x-height 1.471 + // from the baseline of the base char. we also slap on an extra 1.472 + // padding between the accent and base chars. 1.473 + overDelta1 = ruleThickness + onePixel/2; 1.474 + if (bmBase.ascent < xHeight) { 1.475 + // also ensure at least x-height above the baseline of the base 1.476 + overDelta1 += xHeight - bmBase.ascent; 1.477 + } 1.478 + overDelta2 = ruleThickness; 1.479 + } 1.480 + // empty over? 1.481 + if (!(bmOver.ascent + bmOver.descent)) { 1.482 + overDelta1 = 0; 1.483 + overDelta2 = 0; 1.484 + } 1.485 + 1.486 + nscoord dxBase = 0, dxOver = 0, dxUnder = 0; 1.487 + nsAutoString valueAlign; 1.488 + enum { 1.489 + center, 1.490 + left, 1.491 + right 1.492 + } alignPosition = center; 1.493 + 1.494 + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, valueAlign)) { 1.495 + if (valueAlign.EqualsLiteral("left")) { 1.496 + alignPosition = left; 1.497 + } else if (valueAlign.EqualsLiteral("right")) { 1.498 + alignPosition = right; 1.499 + } 1.500 + } 1.501 + 1.502 + ////////// 1.503 + // pass 1, do what <mover> does: attach the overscript on the base 1.504 + 1.505 + // Ad-hoc - This is to override fonts which have ready-made _accent_ 1.506 + // glyphs with negative lbearing and rbearing. We want to position 1.507 + // the overscript ourselves 1.508 + nscoord overWidth = bmOver.width; 1.509 + if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) { 1.510 + overWidth = bmOver.rightBearing - bmOver.leftBearing; 1.511 + dxOver = -bmOver.leftBearing; 1.512 + } 1.513 + 1.514 + if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) { 1.515 + mBoundingMetrics.width = bmBase.width; 1.516 + if (alignPosition == center) { 1.517 + dxOver += correction; 1.518 + } 1.519 + } 1.520 + else { 1.521 + mBoundingMetrics.width = std::max(bmBase.width, overWidth); 1.522 + if (alignPosition == center) { 1.523 + dxOver += correction/2; 1.524 + } 1.525 + } 1.526 + 1.527 + if (alignPosition == center) { 1.528 + dxOver += (mBoundingMetrics.width - overWidth)/2; 1.529 + dxBase = (mBoundingMetrics.width - bmBase.width)/2; 1.530 + } else if (alignPosition == right) { 1.531 + dxOver += mBoundingMetrics.width - overWidth; 1.532 + dxBase = mBoundingMetrics.width - bmBase.width; 1.533 + } 1.534 + 1.535 + mBoundingMetrics.ascent = 1.536 + bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent; 1.537 + mBoundingMetrics.descent = bmBase.descent; 1.538 + mBoundingMetrics.leftBearing = 1.539 + std::min(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing); 1.540 + mBoundingMetrics.rightBearing = 1.541 + std::max(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing); 1.542 + 1.543 + ////////// 1.544 + // pass 2, do what <munder> does: attach the underscript on the previous 1.545 + // result. We conceptually view the previous result as an "anynomous base" 1.546 + // from where to attach the underscript. Hence if the underscript is empty, 1.547 + // we should end up like <mover>. If the overscript is empty, we should 1.548 + // end up like <munder>. 1.549 + 1.550 + nsBoundingMetrics bmAnonymousBase = mBoundingMetrics; 1.551 + nscoord ascentAnonymousBase = 1.552 + std::max(mBoundingMetrics.ascent + overDelta2, 1.553 + overSize.TopAscent() + bmOver.descent + overDelta1 + bmBase.ascent); 1.554 + ascentAnonymousBase = std::max(ascentAnonymousBase, baseSize.TopAscent()); 1.555 + 1.556 + // Width of non-spacing marks is zero so use left and right bearing. 1.557 + nscoord underWidth = bmUnder.width; 1.558 + if (!underWidth) { 1.559 + underWidth = bmUnder.rightBearing - bmUnder.leftBearing; 1.560 + dxUnder = -bmUnder.leftBearing; 1.561 + } 1.562 + 1.563 + nscoord maxWidth = std::max(bmAnonymousBase.width, underWidth); 1.564 + if (alignPosition == center && 1.565 + !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) { 1.566 + GetItalicCorrection(bmAnonymousBase, correction); 1.567 + dxUnder += -correction/2; 1.568 + } 1.569 + nscoord dxAnonymousBase = 0; 1.570 + if (alignPosition == center) { 1.571 + dxUnder += (maxWidth - underWidth)/2; 1.572 + dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2; 1.573 + } else if (alignPosition == right) { 1.574 + dxUnder += maxWidth - underWidth; 1.575 + dxAnonymousBase = maxWidth - bmAnonymousBase.width; 1.576 + } 1.577 + 1.578 + // adjust the offsets of the real base and overscript since their 1.579 + // final offsets should be relative to us... 1.580 + dxOver += dxAnonymousBase; 1.581 + dxBase += dxAnonymousBase; 1.582 + 1.583 + mBoundingMetrics.width = 1.584 + std::max(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width); 1.585 + // At this point, mBoundingMetrics.ascent = bmAnonymousBase.ascent 1.586 + mBoundingMetrics.descent = 1.587 + bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent; 1.588 + mBoundingMetrics.leftBearing = 1.589 + std::min(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing); 1.590 + mBoundingMetrics.rightBearing = 1.591 + std::max(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing); 1.592 + 1.593 + aDesiredSize.SetTopAscent(ascentAnonymousBase); 1.594 + aDesiredSize.Height() = aDesiredSize.TopAscent() + 1.595 + std::max(mBoundingMetrics.descent + underDelta2, 1.596 + bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + 1.597 + underSize.Height() - underSize.TopAscent()); 1.598 + aDesiredSize.Height() = std::max(aDesiredSize.Height(), 1.599 + aDesiredSize.TopAscent() + 1.600 + baseSize.Height() - baseSize.TopAscent()); 1.601 + aDesiredSize.Width() = mBoundingMetrics.width; 1.602 + aDesiredSize.mBoundingMetrics = mBoundingMetrics; 1.603 + 1.604 + mReference.x = 0; 1.605 + mReference.y = aDesiredSize.TopAscent(); 1.606 + 1.607 + if (aPlaceOrigin) { 1.608 + nscoord dy; 1.609 + // place overscript 1.610 + if (overFrame) { 1.611 + dy = aDesiredSize.TopAscent() - mBoundingMetrics.ascent + bmOver.ascent 1.612 + - overSize.TopAscent(); 1.613 + FinishReflowChild (overFrame, PresContext(), overSize, nullptr, dxOver, dy, 0); 1.614 + } 1.615 + // place base 1.616 + dy = aDesiredSize.TopAscent() - baseSize.TopAscent(); 1.617 + FinishReflowChild (baseFrame, PresContext(), baseSize, nullptr, dxBase, dy, 0); 1.618 + // place underscript 1.619 + if (underFrame) { 1.620 + dy = aDesiredSize.TopAscent() + mBoundingMetrics.descent - bmUnder.descent 1.621 + - underSize.TopAscent(); 1.622 + FinishReflowChild (underFrame, PresContext(), underSize, nullptr, 1.623 + dxUnder, dy, 0); 1.624 + } 1.625 + } 1.626 + return NS_OK; 1.627 +}