1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/mathml/nsMathMLmmultiscriptsFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,637 @@ 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 + 1.10 +#include "nsMathMLmmultiscriptsFrame.h" 1.11 +#include "nsPresContext.h" 1.12 +#include "nsRenderingContext.h" 1.13 +#include <algorithm> 1.14 + 1.15 +using mozilla::WritingMode; 1.16 + 1.17 +// 1.18 +// <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation 1.19 +// <msub> -- attach a subscript to a base - implementation 1.20 +// <msubsup> -- attach a subscript-superscript pair to a base - implementation 1.21 +// <msup> -- attach a superscript to a base - implementation 1.22 +// 1.23 + 1.24 +nsIFrame* 1.25 +NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.26 +{ 1.27 + return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext); 1.28 +} 1.29 + 1.30 +NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame) 1.31 + 1.32 +nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame() 1.33 +{ 1.34 +} 1.35 + 1.36 +uint8_t 1.37 +nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame) 1.38 +{ 1.39 + if (!aFrame) 1.40 + return 0; 1.41 + if (mFrames.ContainsFrame(aFrame)) { 1.42 + if (mFrames.FirstChild() == aFrame || 1.43 + aFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) { 1.44 + return 0; // No script increment for base frames or prescript markers 1.45 + } 1.46 + return 1; 1.47 + } 1.48 + return 0; //not a child 1.49 +} 1.50 + 1.51 +NS_IMETHODIMP 1.52 +nsMathMLmmultiscriptsFrame::TransmitAutomaticData() 1.53 +{ 1.54 + // if our base is an embellished operator, let its state bubble to us 1.55 + mPresentationData.baseFrame = mFrames.FirstChild(); 1.56 + GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData); 1.57 + 1.58 + // The TeXbook (Ch 17. p.141) says the superscript inherits the compression 1.59 + // while the subscript is compressed. So here we collect subscripts and set 1.60 + // the compression flag in them. 1.61 + 1.62 + int32_t count = 0; 1.63 + bool isSubScript = mContent->Tag() != nsGkAtoms::msup_; 1.64 + 1.65 + nsAutoTArray<nsIFrame*, 8> subScriptFrames; 1.66 + nsIFrame* childFrame = mFrames.FirstChild(); 1.67 + while (childFrame) { 1.68 + if (childFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) { 1.69 + // mprescripts frame 1.70 + } else if (0 == count) { 1.71 + // base frame 1.72 + } else { 1.73 + // super/subscript block 1.74 + if (isSubScript) { 1.75 + // subscript 1.76 + subScriptFrames.AppendElement(childFrame); 1.77 + } else { 1.78 + // superscript 1.79 + } 1.80 + PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT); 1.81 + isSubScript = !isSubScript; 1.82 + } 1.83 + count++; 1.84 + childFrame = childFrame->GetNextSibling(); 1.85 + } 1.86 + for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) { 1.87 + childFrame = subScriptFrames[i]; 1.88 + PropagatePresentationDataFor(childFrame, 1.89 + NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED); 1.90 + } 1.91 + 1.92 + return NS_OK; 1.93 +} 1.94 + 1.95 +/* virtual */ nsresult 1.96 +nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext, 1.97 + bool aPlaceOrigin, 1.98 + nsHTMLReflowMetrics& aDesiredSize) 1.99 +{ 1.100 + nscoord subScriptShift = 0; 1.101 + nscoord supScriptShift = 0; 1.102 + nsIAtom* tag = mContent->Tag(); 1.103 + 1.104 + // subscriptshift 1.105 + // 1.106 + // "Specifies the minimum amount to shift the baseline of subscript down; the 1.107 + // default is for the rendering agent to use its own positioning rules." 1.108 + // 1.109 + // values: length 1.110 + // default: automatic 1.111 + // 1.112 + // We use 0 as the default value so unitless values can be ignored. 1.113 + // As a minimum, negative values can be ignored. 1.114 + // 1.115 + nsAutoString value; 1.116 + if (tag != nsGkAtoms::msup_) { 1.117 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value); 1.118 + if (!value.IsEmpty()) { 1.119 + ParseNumericValue(value, &subScriptShift, 0, PresContext(), 1.120 + mStyleContext); 1.121 + } 1.122 + } 1.123 + // superscriptshift 1.124 + // 1.125 + // "Specifies the minimum amount to shift the baseline of superscript up; the 1.126 + // default is for the rendering agent to use its own positioning rules." 1.127 + // 1.128 + // values: length 1.129 + // default: automatic 1.130 + // 1.131 + // We use 0 as the default value so unitless values can be ignored. 1.132 + // As a minimum, negative values can be ignored. 1.133 + // 1.134 + if (tag != nsGkAtoms::msub_) { 1.135 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value); 1.136 + if (!value.IsEmpty()) { 1.137 + ParseNumericValue(value, &supScriptShift, 0, PresContext(), 1.138 + mStyleContext); 1.139 + } 1.140 + } 1.141 + // scriptspace from TeX for extra spacing after sup/subscript 1.142 + // (0.5pt in plain TeX) 1.143 + nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); 1.144 + 1.145 + return PlaceMultiScript(PresContext(), aRenderingContext, aPlaceOrigin, 1.146 + aDesiredSize, this, subScriptShift, supScriptShift, 1.147 + scriptSpace); 1.148 +} 1.149 + 1.150 +// exported routine that both munderover and mmultiscripts share. 1.151 +// munderover uses this when movablelimits is set. 1.152 +nsresult 1.153 +nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext* aPresContext, 1.154 + nsRenderingContext& aRenderingContext, 1.155 + bool aPlaceOrigin, 1.156 + nsHTMLReflowMetrics& aDesiredSize, 1.157 + nsMathMLContainerFrame* aFrame, 1.158 + nscoord aUserSubScriptShift, 1.159 + nscoord aUserSupScriptShift, 1.160 + nscoord aScriptSpace) 1.161 +{ 1.162 + nsIAtom* tag = aFrame->GetContent()->Tag(); 1.163 + 1.164 + // This function deals with both munderover etc. as well as msubsup etc. 1.165 + // As the former behaves identically to the later, we treat it as such 1.166 + // to avoid additional checks later. 1.167 + if (tag == nsGkAtoms::mover_) 1.168 + tag = nsGkAtoms::msup_; 1.169 + else if (tag == nsGkAtoms::munder_) 1.170 + tag = nsGkAtoms::msub_; 1.171 + else if (tag == nsGkAtoms::munderover_) 1.172 + tag = nsGkAtoms::msubsup_; 1.173 + 1.174 + nsBoundingMetrics bmFrame; 1.175 + 1.176 + nscoord minShiftFromXHeight, subDrop, supDrop; 1.177 + 1.178 + //////////////////////////////////////// 1.179 + // Initialize super/sub shifts that 1.180 + // depend only on the current font 1.181 + //////////////////////////////////////// 1.182 + 1.183 + nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild(); 1.184 + 1.185 + if (!baseFrame) { 1.186 + if (tag == nsGkAtoms::mmultiscripts_) 1.187 + aFrame->ReportErrorToConsole("NoBase"); 1.188 + else 1.189 + aFrame->ReportChildCountError(); 1.190 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.191 + } 1.192 + 1.193 + 1.194 + // get x-height (an ex) 1.195 + const nsStyleFont* font = aFrame->StyleFont(); 1.196 + nsRefPtr<nsFontMetrics> fm; 1.197 + nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm)); 1.198 + aRenderingContext.SetFont(fm); 1.199 + 1.200 + nscoord xHeight = fm->XHeight(); 1.201 + 1.202 + nscoord ruleSize; 1.203 + GetRuleThickness (aRenderingContext, fm, ruleSize); 1.204 + 1.205 + // force the scriptSpace to be at least 1 pixel 1.206 + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); 1.207 + aScriptSpace = std::max(onePixel, aScriptSpace); 1.208 + 1.209 + ///////////////////////////////////// 1.210 + // first the shift for the subscript 1.211 + 1.212 + // subScriptShift{1,2} 1.213 + // = minimum amount to shift the subscript down 1.214 + // = sub{1,2} in TeXbook 1.215 + // subScriptShift1 = subscriptshift attribute * x-height 1.216 + nscoord subScriptShift1, subScriptShift2; 1.217 + 1.218 + // Get subScriptShift{1,2} default from font 1.219 + GetSubScriptShifts (fm, subScriptShift1, subScriptShift2); 1.220 + nscoord subScriptShift; 1.221 + if (tag == nsGkAtoms::msub_) { 1.222 + subScriptShift = subScriptShift1; 1.223 + } else { 1.224 + subScriptShift = std::max(subScriptShift1, subScriptShift2); 1.225 + } 1.226 + if (0 < aUserSubScriptShift) { 1.227 + // the user has set the subscriptshift attribute 1.228 + subScriptShift = std::max(subScriptShift, aUserSubScriptShift); 1.229 + } 1.230 + 1.231 + ///////////////////////////////////// 1.232 + // next the shift for the superscript 1.233 + 1.234 + // supScriptShift{1,2,3} 1.235 + // = minimum amount to shift the supscript up 1.236 + // = sup{1,2,3} in TeX 1.237 + // supScriptShift1 = superscriptshift attribute * x-height 1.238 + // Note that there are THREE values for supscript shifts depending 1.239 + // on the current style 1.240 + nscoord supScriptShift1, supScriptShift2, supScriptShift3; 1.241 + // Set supScriptShift{1,2,3} default from font 1.242 + GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3); 1.243 + 1.244 + // get sup script shift depending on current script level and display style 1.245 + // Rule 18c, App. G, TeXbook 1.246 + nsPresentationData presentationData; 1.247 + aFrame->GetPresentationData(presentationData); 1.248 + nscoord supScriptShift; 1.249 + if (font->mScriptLevel == 0 && 1.250 + font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK && 1.251 + !NS_MATHML_IS_COMPRESSED(presentationData.flags)) { 1.252 + // Style D in TeXbook 1.253 + supScriptShift = supScriptShift1; 1.254 + } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) { 1.255 + // Style C' in TeXbook = D',T',S',SS' 1.256 + supScriptShift = supScriptShift3; 1.257 + } else { 1.258 + // everything else = T,S,SS 1.259 + supScriptShift = supScriptShift2; 1.260 + } 1.261 + 1.262 + if (0 < aUserSupScriptShift) { 1.263 + // the user has set the supscriptshift attribute 1.264 + supScriptShift = std::max(supScriptShift, aUserSupScriptShift); 1.265 + } 1.266 + 1.267 + //////////////////////////////////// 1.268 + // Get the children's sizes 1.269 + //////////////////////////////////// 1.270 + 1.271 + const WritingMode wm(aDesiredSize.GetWritingMode()); 1.272 + nscoord width = 0, prescriptsWidth = 0, rightBearing = 0; 1.273 + nscoord minSubScriptShift = 0, minSupScriptShift = 0; 1.274 + nscoord trySubScriptShift = subScriptShift; 1.275 + nscoord trySupScriptShift = supScriptShift; 1.276 + nscoord maxSubScriptShift = subScriptShift; 1.277 + nscoord maxSupScriptShift = supScriptShift; 1.278 + nsHTMLReflowMetrics baseSize(wm); 1.279 + nsHTMLReflowMetrics subScriptSize(wm); 1.280 + nsHTMLReflowMetrics supScriptSize(wm); 1.281 + nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm); 1.282 + baseFrame = nullptr; 1.283 + nsIFrame* subScriptFrame = nullptr; 1.284 + nsIFrame* supScriptFrame = nullptr; 1.285 + nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there. 1.286 + 1.287 + bool firstPrescriptsPair = false; 1.288 + nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup; 1.289 + multiSubSize.SetTopAscent(-0x7FFFFFFF); 1.290 + multiSupSize.SetTopAscent(-0x7FFFFFFF); 1.291 + bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF; 1.292 + bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF; 1.293 + nscoord italicCorrection = 0; 1.294 + 1.295 + nsBoundingMetrics boundingMetrics; 1.296 + boundingMetrics.width = 0; 1.297 + boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF; 1.298 + aDesiredSize.Width() = aDesiredSize.Height() = 0; 1.299 + 1.300 + int32_t count = 0; 1.301 + bool foundNoneTag = false; 1.302 + 1.303 + // Boolean to determine whether the current child is a subscript. 1.304 + // Note that only msup starts with a superscript. 1.305 + bool isSubScript = (tag != nsGkAtoms::msup_); 1.306 + 1.307 + nsIFrame* childFrame = aFrame->GetFirstPrincipalChild(); 1.308 + while (childFrame) { 1.309 + nsIAtom* childTag = childFrame->GetContent()->Tag(); 1.310 + if (childTag == nsGkAtoms::mprescripts_) { 1.311 + if (tag != nsGkAtoms::mmultiscripts_) { 1.312 + if (aPlaceOrigin) { 1.313 + aFrame->ReportInvalidChildError(childTag); 1.314 + } 1.315 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.316 + } 1.317 + if (prescriptsFrame) { 1.318 + // duplicate <mprescripts/> found 1.319 + // report an error, encourage people to get their markups in order 1.320 + if (aPlaceOrigin) { 1.321 + aFrame->ReportErrorToConsole("DuplicateMprescripts"); 1.322 + } 1.323 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.324 + } 1.325 + if (!isSubScript) { 1.326 + if (aPlaceOrigin) { 1.327 + aFrame->ReportErrorToConsole("SubSupMismatch"); 1.328 + } 1.329 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.330 + } 1.331 + 1.332 + prescriptsFrame = childFrame; 1.333 + firstPrescriptsPair = true; 1.334 + } else if (0 == count) { 1.335 + // base 1.336 + 1.337 + if (childTag == nsGkAtoms::none) { 1.338 + if (tag == nsGkAtoms::mmultiscripts_) { 1.339 + if (aPlaceOrigin) { 1.340 + aFrame->ReportErrorToConsole("NoBase"); 1.341 + } 1.342 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.343 + } else { 1.344 + //A different error message is triggered later for the other tags 1.345 + foundNoneTag = true; 1.346 + } 1.347 + } 1.348 + baseFrame = childFrame; 1.349 + GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase); 1.350 + 1.351 + if (tag != nsGkAtoms::msub_) { 1.352 + // Apply italics correction if there is the potential for a 1.353 + // postsupscript. 1.354 + GetItalicCorrection(bmBase, italicCorrection); 1.355 + // If italics correction is applied, we always add "a little to spare" 1.356 + // (see TeXbook Ch.11, p.64), as we estimate the italic creation 1.357 + // ourselves and it isn't the same as TeX. 1.358 + italicCorrection += onePixel; 1.359 + } 1.360 + 1.361 + // we update boundingMetrics.{ascent,descent} with that 1.362 + // of the baseFrame only after processing all the sup/sub pairs 1.363 + boundingMetrics.width = bmBase.width; 1.364 + boundingMetrics.rightBearing = bmBase.rightBearing; 1.365 + boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten 1.366 + } else { 1.367 + // super/subscript block 1.368 + if ( childTag == nsGkAtoms::none) { 1.369 + foundNoneTag = true; 1.370 + } 1.371 + 1.372 + if (isSubScript) { 1.373 + // subscript 1.374 + subScriptFrame = childFrame; 1.375 + GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); 1.376 + // get the subdrop from the subscript font 1.377 + GetSubDropFromChild (subScriptFrame, subDrop); 1.378 + // parameter v, Rule 18a, App. G, TeXbook 1.379 + minSubScriptShift = bmBase.descent + subDrop; 1.380 + trySubScriptShift = std::max(minSubScriptShift,subScriptShift); 1.381 + multiSubSize.SetTopAscent(std::max(multiSubSize.TopAscent(), 1.382 + subScriptSize.TopAscent())); 1.383 + bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent); 1.384 + bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent); 1.385 + multiSubSize.Height() = 1.386 + std::max(multiSubSize.Height(), 1.387 + subScriptSize.Height() - subScriptSize.TopAscent()); 1.388 + if (bmSubScript.width) 1.389 + width = bmSubScript.width + aScriptSpace; 1.390 + rightBearing = bmSubScript.rightBearing; 1.391 + 1.392 + if (tag == nsGkAtoms::msub_) { 1.393 + boundingMetrics.rightBearing = boundingMetrics.width + rightBearing; 1.394 + boundingMetrics.width += width; 1.395 + 1.396 + // get min subscript shift limit from x-height 1.397 + // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook 1.398 + nscoord minShiftFromXHeight = (nscoord) 1.399 + (bmSubScript.ascent - (4.0f/5.0f) * xHeight); 1.400 + maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight); 1.401 + 1.402 + maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift); 1.403 + trySubScriptShift = subScriptShift; 1.404 + } 1.405 + } else { 1.406 + // supscript 1.407 + supScriptFrame = childFrame; 1.408 + GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); 1.409 + // get the supdrop from the supscript font 1.410 + GetSupDropFromChild (supScriptFrame, supDrop); 1.411 + // parameter u, Rule 18a, App. G, TeXbook 1.412 + minSupScriptShift = bmBase.ascent - supDrop; 1.413 + // get min supscript shift limit from x-height 1.414 + // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook 1.415 + minShiftFromXHeight = NSToCoordRound 1.416 + ((bmSupScript.descent + (1.0f/4.0f) * xHeight)); 1.417 + trySupScriptShift = std::max(minSupScriptShift, 1.418 + std::max(minShiftFromXHeight, 1.419 + supScriptShift)); 1.420 + multiSupSize.SetTopAscent(std::max(multiSupSize.TopAscent(), 1.421 + supScriptSize.TopAscent())); 1.422 + bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent); 1.423 + bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent); 1.424 + multiSupSize.Height() = 1.425 + std::max(multiSupSize.Height(), 1.426 + supScriptSize.Height() - supScriptSize.TopAscent()); 1.427 + 1.428 + if (bmSupScript.width) 1.429 + width = std::max(width, bmSupScript.width + aScriptSpace); 1.430 + 1.431 + if (!prescriptsFrame) { // we are still looping over base & postscripts 1.432 + rightBearing = std::max(rightBearing, 1.433 + italicCorrection + bmSupScript.rightBearing); 1.434 + boundingMetrics.rightBearing = boundingMetrics.width + rightBearing; 1.435 + boundingMetrics.width += width; 1.436 + } else { 1.437 + prescriptsWidth += width; 1.438 + if (firstPrescriptsPair) { 1.439 + firstPrescriptsPair = false; 1.440 + boundingMetrics.leftBearing = 1.441 + std::min(bmSubScript.leftBearing, bmSupScript.leftBearing); 1.442 + } 1.443 + } 1.444 + width = rightBearing = 0; 1.445 + 1.446 + // negotiate between the various shifts so that 1.447 + // there is enough gap between the sup and subscripts 1.448 + // Rule 18e, App. G, TeXbook 1.449 + if (tag == nsGkAtoms::mmultiscripts_ || 1.450 + tag == nsGkAtoms::msubsup_) { 1.451 + nscoord gap = 1.452 + (trySupScriptShift - bmSupScript.descent) - 1.453 + (bmSubScript.ascent - trySubScriptShift); 1.454 + if (gap < 4.0f * ruleSize) { 1.455 + // adjust trySubScriptShift to get a gap of (4.0 * ruleSize) 1.456 + trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap); 1.457 + } 1.458 + 1.459 + // next we want to ensure that the bottom of the superscript 1.460 + // will be > (4/5) * x-height above baseline 1.461 + gap = NSToCoordRound ((4.0f/5.0f) * xHeight - 1.462 + (trySupScriptShift - bmSupScript.descent)); 1.463 + if (gap > 0) { 1.464 + trySupScriptShift += gap; 1.465 + trySubScriptShift -= gap; 1.466 + } 1.467 + } 1.468 + 1.469 + maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift); 1.470 + maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift); 1.471 + 1.472 + trySubScriptShift = subScriptShift; 1.473 + trySupScriptShift = supScriptShift; 1.474 + } 1.475 + 1.476 + isSubScript = !isSubScript; 1.477 + } 1.478 + count++; 1.479 + childFrame = childFrame->GetNextSibling(); 1.480 + } 1.481 + 1.482 + //NoBase error may also have been reported above 1.483 + if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) || 1.484 + (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame || 1.485 + (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) || 1.486 + (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) { 1.487 + // report an error, encourage people to get their markups in order 1.488 + if (aPlaceOrigin) { 1.489 + if ((count != 2 && (tag == nsGkAtoms::msup_ || 1.490 + tag == nsGkAtoms::msub_)) || 1.491 + (count != 3 && tag == nsGkAtoms::msubsup_ )) { 1.492 + aFrame->ReportChildCountError(); 1.493 + } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) { 1.494 + aFrame->ReportInvalidChildError(nsGkAtoms::none); 1.495 + } else if (!baseFrame) { 1.496 + aFrame->ReportErrorToConsole("NoBase"); 1.497 + } else { 1.498 + aFrame->ReportErrorToConsole("SubSupMismatch"); 1.499 + } 1.500 + } 1.501 + return aFrame->ReflowError(aRenderingContext, aDesiredSize); 1.502 + } 1.503 + 1.504 + // we left out the width of prescripts, so ... 1.505 + boundingMetrics.rightBearing += prescriptsWidth; 1.506 + boundingMetrics.width += prescriptsWidth; 1.507 + 1.508 + // Zero out the shifts in where a frame isn't present to avoid the potential 1.509 + // for overflow. 1.510 + if (!subScriptFrame) 1.511 + maxSubScriptShift = 0; 1.512 + if (!supScriptFrame) 1.513 + maxSupScriptShift = 0; 1.514 + 1.515 + // we left out the base during our bounding box updates, so ... 1.516 + if (tag == nsGkAtoms::msub_) { 1.517 + boundingMetrics.ascent = std::max(bmBase.ascent, 1.518 + bmMultiSub.ascent - maxSubScriptShift); 1.519 + } else { 1.520 + boundingMetrics.ascent = 1.521 + std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift)); 1.522 + } 1.523 + if (tag == nsGkAtoms::msup_) { 1.524 + boundingMetrics.descent = std::max(bmBase.descent, 1.525 + bmMultiSup.descent - maxSupScriptShift); 1.526 + } else { 1.527 + boundingMetrics.descent = 1.528 + std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift)); 1.529 + } 1.530 + aFrame->SetBoundingMetrics(boundingMetrics); 1.531 + 1.532 + // get the reflow metrics ... 1.533 + aDesiredSize.SetTopAscent( 1.534 + std::max(baseSize.TopAscent(), 1.535 + std::max(multiSubSize.TopAscent() - maxSubScriptShift, 1.536 + multiSupSize.TopAscent() + maxSupScriptShift))); 1.537 + aDesiredSize.Height() = aDesiredSize.TopAscent() + 1.538 + std::max(baseSize.Height() - baseSize.TopAscent(), 1.539 + std::max(multiSubSize.Height() + maxSubScriptShift, 1.540 + multiSupSize.Height() - maxSupScriptShift)); 1.541 + aDesiredSize.Width() = boundingMetrics.width; 1.542 + aDesiredSize.mBoundingMetrics = boundingMetrics; 1.543 + 1.544 + aFrame->SetReference(nsPoint(0, aDesiredSize.TopAscent())); 1.545 + 1.546 + ////////////////// 1.547 + // Place Children 1.548 + 1.549 + // Place prescripts, followed by base, and then postscripts. 1.550 + // The list of frames is in the order: {base} {postscripts} {prescripts} 1.551 + // We go over the list in a circular manner, starting at <prescripts/> 1.552 + 1.553 + if (aPlaceOrigin) { 1.554 + nscoord dx = 0, dy = 0; 1.555 + 1.556 + // With msub and msup there is only one element and 1.557 + // subscriptFrame/supScriptFrame have already been set above where 1.558 + // relevant. In these cases we skip to the reflow part. 1.559 + if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_) 1.560 + count = 1; 1.561 + else 1.562 + count = 0; 1.563 + childFrame = prescriptsFrame; 1.564 + bool isPreScript = true; 1.565 + do { 1.566 + if (!childFrame) { // end of prescripts, 1.567 + isPreScript = false; 1.568 + // place the base ... 1.569 + childFrame = baseFrame; 1.570 + dy = aDesiredSize.TopAscent() - baseSize.TopAscent(); 1.571 + FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr, 1.572 + aFrame->MirrorIfRTL(aDesiredSize.Width(), 1.573 + baseSize.Width(), 1.574 + dx), 1.575 + dy, 0); 1.576 + dx += bmBase.width; 1.577 + } else if (prescriptsFrame == childFrame) { 1.578 + // Clear reflow flags of prescripts frame. 1.579 + prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); 1.580 + } else { 1.581 + // process each sup/sub pair 1.582 + if (0 == count) { 1.583 + subScriptFrame = childFrame; 1.584 + count = 1; 1.585 + } else if (1 == count) { 1.586 + if (tag != nsGkAtoms::msub_) 1.587 + supScriptFrame = childFrame; 1.588 + count = 0; 1.589 + 1.590 + // get the ascent/descent of sup/subscripts stored in their rects 1.591 + // rect.x = descent, rect.y = ascent 1.592 + if (subScriptFrame) 1.593 + GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript); 1.594 + if (supScriptFrame) 1.595 + GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript); 1.596 + 1.597 + width = std::max(subScriptSize.Width(), supScriptSize.Width()); 1.598 + 1.599 + if (subScriptFrame) { 1.600 + nscoord x = dx; 1.601 + // prescripts should be right aligned 1.602 + // https://bugzilla.mozilla.org/show_bug.cgi?id=928675 1.603 + if (isPreScript) 1.604 + x += width - subScriptSize.Width(); 1.605 + dy = aDesiredSize.TopAscent() - subScriptSize.TopAscent() + 1.606 + maxSubScriptShift; 1.607 + FinishReflowChild (subScriptFrame, aPresContext, subScriptSize, 1.608 + nullptr, 1.609 + aFrame->MirrorIfRTL(aDesiredSize.Width(), 1.610 + subScriptSize.Width(), 1.611 + x), 1.612 + dy, 0); 1.613 + } 1.614 + 1.615 + if (supScriptFrame) { 1.616 + nscoord x = dx; 1.617 + if (isPreScript) { 1.618 + x += width - supScriptSize.Width(); 1.619 + } else { 1.620 + // post superscripts are shifted by the italic correction value 1.621 + x += italicCorrection; 1.622 + } 1.623 + dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() - 1.624 + maxSupScriptShift; 1.625 + FinishReflowChild (supScriptFrame, aPresContext, supScriptSize, 1.626 + nullptr, 1.627 + aFrame->MirrorIfRTL(aDesiredSize.Width(), 1.628 + supScriptSize.Width(), 1.629 + x), 1.630 + dy, 0); 1.631 + } 1.632 + dx += width + aScriptSpace; 1.633 + } 1.634 + } 1.635 + childFrame = childFrame->GetNextSibling(); 1.636 + } while (prescriptsFrame != childFrame); 1.637 + } 1.638 + 1.639 + return NS_OK; 1.640 +}