Bug 1226301. Remove Shumway from b2gdroid nightly builds. r=fabrice
[gecko.git] / layout / mathml / nsMathMLmmultiscriptsFrame.cpp
blobe0c8700d835bfd35d6264f90768b1a6a21892315
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMathMLmmultiscriptsFrame.h"
8 #include "nsPresContext.h"
9 #include "nsRenderingContext.h"
10 #include <algorithm>
12 using mozilla::WritingMode;
15 // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
16 // <msub> -- attach a subscript to a base - implementation
17 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
18 // <msup> -- attach a superscript to a base - implementation
21 nsIFrame*
22 NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
24 return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext);
27 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame)
29 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
33 uint8_t
34 nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame)
36 if (!aFrame)
37 return 0;
38 if (mFrames.ContainsFrame(aFrame)) {
39 if (mFrames.FirstChild() == aFrame ||
40 aFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
41 return 0; // No script increment for base frames or prescript markers
43 return 1;
45 return 0; //not a child
48 NS_IMETHODIMP
49 nsMathMLmmultiscriptsFrame::TransmitAutomaticData()
51 // if our base is an embellished operator, let its state bubble to us
52 mPresentationData.baseFrame = mFrames.FirstChild();
53 GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
55 // The TeXbook (Ch 17. p.141) says the superscript inherits the compression
56 // while the subscript is compressed. So here we collect subscripts and set
57 // the compression flag in them.
59 int32_t count = 0;
60 bool isSubScript = !mContent->IsMathMLElement(nsGkAtoms::msup_);
62 nsAutoTArray<nsIFrame*, 8> subScriptFrames;
63 nsIFrame* childFrame = mFrames.FirstChild();
64 while (childFrame) {
65 if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
66 // mprescripts frame
67 } else if (0 == count) {
68 // base frame
69 } else {
70 // super/subscript block
71 if (isSubScript) {
72 // subscript
73 subScriptFrames.AppendElement(childFrame);
74 } else {
75 // superscript
77 PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT);
78 isSubScript = !isSubScript;
80 count++;
81 childFrame = childFrame->GetNextSibling();
83 for (int32_t i = subScriptFrames.Length() - 1; i >= 0; i--) {
84 childFrame = subScriptFrames[i];
85 PropagatePresentationDataFor(childFrame,
86 NS_MATHML_COMPRESSED, NS_MATHML_COMPRESSED);
89 return NS_OK;
92 /* virtual */ nsresult
93 nsMathMLmmultiscriptsFrame::Place(DrawTarget* aDrawTarget,
94 bool aPlaceOrigin,
95 nsHTMLReflowMetrics& aDesiredSize)
97 nscoord subScriptShift = 0;
98 nscoord supScriptShift = 0;
99 float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(this);
101 // subscriptshift
103 // "Specifies the minimum amount to shift the baseline of subscript down; the
104 // default is for the rendering agent to use its own positioning rules."
106 // values: length
107 // default: automatic
109 // We use 0 as the default value so unitless values can be ignored.
110 // As a minimum, negative values can be ignored.
112 nsAutoString value;
113 if (!mContent->IsMathMLElement(nsGkAtoms::msup_)) {
114 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value);
115 if (!value.IsEmpty()) {
116 ParseNumericValue(value, &subScriptShift, 0, PresContext(),
117 mStyleContext, fontSizeInflation);
120 // superscriptshift
122 // "Specifies the minimum amount to shift the baseline of superscript up; the
123 // default is for the rendering agent to use its own positioning rules."
125 // values: length
126 // default: automatic
128 // We use 0 as the default value so unitless values can be ignored.
129 // As a minimum, negative values can be ignored.
131 if (!mContent->IsMathMLElement(nsGkAtoms::msub_)) {
132 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value);
133 if (!value.IsEmpty()) {
134 ParseNumericValue(value, &supScriptShift, 0, PresContext(),
135 mStyleContext, fontSizeInflation);
138 return PlaceMultiScript(PresContext(), aDrawTarget, aPlaceOrigin,
139 aDesiredSize, this, subScriptShift, supScriptShift,
140 fontSizeInflation);
143 // exported routine that both munderover and mmultiscripts share.
144 // munderover uses this when movablelimits is set.
145 nsresult
146 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext* aPresContext,
147 DrawTarget* aDrawTarget,
148 bool aPlaceOrigin,
149 nsHTMLReflowMetrics& aDesiredSize,
150 nsMathMLContainerFrame* aFrame,
151 nscoord aUserSubScriptShift,
152 nscoord aUserSupScriptShift,
153 float aFontSizeInflation)
155 nsIAtom* tag = aFrame->GetContent()->NodeInfo()->NameAtom();
157 // This function deals with both munderover etc. as well as msubsup etc.
158 // As the former behaves identically to the later, we treat it as such
159 // to avoid additional checks later.
160 if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::mover_))
161 tag = nsGkAtoms::msup_;
162 else if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::munder_))
163 tag = nsGkAtoms::msub_;
164 else if (aFrame->GetContent()->IsMathMLElement(nsGkAtoms::munderover_))
165 tag = nsGkAtoms::msubsup_;
167 nsBoundingMetrics bmFrame;
169 nscoord minShiftFromXHeight, subDrop, supDrop;
171 ////////////////////////////////////////
172 // Initialize super/sub shifts that
173 // depend only on the current font
174 ////////////////////////////////////////
176 nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
178 if (!baseFrame) {
179 if (tag == nsGkAtoms::mmultiscripts_)
180 aFrame->ReportErrorToConsole("NoBase");
181 else
182 aFrame->ReportChildCountError();
183 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
186 // get x-height (an ex)
187 const nsStyleFont* font = aFrame->StyleFont();
188 RefPtr<nsFontMetrics> fm;
189 nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm),
190 aFontSizeInflation);
192 nscoord xHeight = fm->XHeight();
194 nscoord oneDevPixel = fm->AppUnitsPerDevPixel();
195 gfxFont* mathFont = fm->GetThebesFontGroup()->GetFirstMathFont();
196 // scriptspace from TeX for extra spacing after sup/subscript
197 nscoord scriptSpace;
198 if (mathFont) {
199 scriptSpace =
200 mathFont->GetMathConstant(gfxFontEntry::SpaceAfterScript, oneDevPixel);
201 } else {
202 // (0.5pt in plain TeX)
203 scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
206 // force the scriptSpace to be at least 1 pixel
207 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
208 scriptSpace = std::max(onePixel, scriptSpace);
210 /////////////////////////////////////
211 // first the shift for the subscript
213 nscoord subScriptShift;
214 if (mathFont) {
215 // Try and get the sub script shift from the MATH table. Note that contrary
216 // to TeX we only have one parameter.
217 subScriptShift =
218 mathFont->GetMathConstant(gfxFontEntry::SubscriptShiftDown, oneDevPixel);
219 } else {
220 // subScriptShift{1,2}
221 // = minimum amount to shift the subscript down
222 // = sub{1,2} in TeXbook
223 // subScriptShift1 = subscriptshift attribute * x-height
224 nscoord subScriptShift1, subScriptShift2;
225 // Get subScriptShift{1,2} default from font
226 GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
227 if (tag == nsGkAtoms::msub_) {
228 subScriptShift = subScriptShift1;
229 } else {
230 subScriptShift = std::max(subScriptShift1, subScriptShift2);
234 if (0 < aUserSubScriptShift) {
235 // the user has set the subscriptshift attribute
236 subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
239 /////////////////////////////////////
240 // next the shift for the superscript
242 nscoord supScriptShift;
243 nsPresentationData presentationData;
244 aFrame->GetPresentationData(presentationData);
245 if (mathFont) {
246 // Try and get the super script shift from the MATH table. Note that
247 // contrary to TeX we only have two parameters.
248 supScriptShift = mathFont->
249 GetMathConstant(NS_MATHML_IS_COMPRESSED(presentationData.flags) ?
250 gfxFontEntry::SuperscriptShiftUpCramped :
251 gfxFontEntry::SuperscriptShiftUp,
252 oneDevPixel);
253 } else {
254 // supScriptShift{1,2,3}
255 // = minimum amount to shift the supscript up
256 // = sup{1,2,3} in TeX
257 // supScriptShift1 = superscriptshift attribute * x-height
258 // Note that there are THREE values for supscript shifts depending
259 // on the current style
260 nscoord supScriptShift1, supScriptShift2, supScriptShift3;
261 // Set supScriptShift{1,2,3} default from font
262 GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
264 // get sup script shift depending on current script level and display style
265 // Rule 18c, App. G, TeXbook
266 if (font->mScriptLevel == 0 &&
267 font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
268 !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
269 // Style D in TeXbook
270 supScriptShift = supScriptShift1;
271 } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
272 // Style C' in TeXbook = D',T',S',SS'
273 supScriptShift = supScriptShift3;
274 } else {
275 // everything else = T,S,SS
276 supScriptShift = supScriptShift2;
280 if (0 < aUserSupScriptShift) {
281 // the user has set the supscriptshift attribute
282 supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
285 ////////////////////////////////////
286 // Get the children's sizes
287 ////////////////////////////////////
289 const WritingMode wm(aDesiredSize.GetWritingMode());
290 nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
291 nscoord minSubScriptShift = 0, minSupScriptShift = 0;
292 nscoord trySubScriptShift = subScriptShift;
293 nscoord trySupScriptShift = supScriptShift;
294 nscoord maxSubScriptShift = subScriptShift;
295 nscoord maxSupScriptShift = supScriptShift;
296 nsHTMLReflowMetrics baseSize(wm);
297 nsHTMLReflowMetrics subScriptSize(wm);
298 nsHTMLReflowMetrics supScriptSize(wm);
299 nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm);
300 baseFrame = nullptr;
301 nsIFrame* subScriptFrame = nullptr;
302 nsIFrame* supScriptFrame = nullptr;
303 nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
305 bool firstPrescriptsPair = false;
306 nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
307 multiSubSize.SetBlockStartAscent(-0x7FFFFFFF);
308 multiSupSize.SetBlockStartAscent(-0x7FFFFFFF);
309 bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
310 bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
311 nscoord italicCorrection = 0;
313 nsBoundingMetrics boundingMetrics;
314 boundingMetrics.width = 0;
315 boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
316 aDesiredSize.Width() = aDesiredSize.Height() = 0;
318 int32_t count = 0;
319 bool foundNoneTag = false;
321 // Boolean to determine whether the current child is a subscript.
322 // Note that only msup starts with a superscript.
323 bool isSubScript = (tag != nsGkAtoms::msup_);
325 nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
326 while (childFrame) {
327 if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_)) {
328 if (tag != nsGkAtoms::mmultiscripts_) {
329 if (aPlaceOrigin) {
330 aFrame->ReportInvalidChildError(nsGkAtoms::mprescripts_);
332 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
334 if (prescriptsFrame) {
335 // duplicate <mprescripts/> found
336 // report an error, encourage people to get their markups in order
337 if (aPlaceOrigin) {
338 aFrame->ReportErrorToConsole("DuplicateMprescripts");
340 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
342 if (!isSubScript) {
343 if (aPlaceOrigin) {
344 aFrame->ReportErrorToConsole("SubSupMismatch");
346 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
349 prescriptsFrame = childFrame;
350 firstPrescriptsPair = true;
351 } else if (0 == count) {
352 // base
354 if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::none)) {
355 if (tag == nsGkAtoms::mmultiscripts_) {
356 if (aPlaceOrigin) {
357 aFrame->ReportErrorToConsole("NoBase");
359 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
360 } else {
361 //A different error message is triggered later for the other tags
362 foundNoneTag = true;
365 baseFrame = childFrame;
366 GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
368 if (tag != nsGkAtoms::msub_) {
369 // Apply italics correction if there is the potential for a
370 // postsupscript.
371 GetItalicCorrection(bmBase, italicCorrection);
372 // If italics correction is applied, we always add "a little to spare"
373 // (see TeXbook Ch.11, p.64), as we estimate the italic creation
374 // ourselves and it isn't the same as TeX.
375 italicCorrection += onePixel;
378 // we update boundingMetrics.{ascent,descent} with that
379 // of the baseFrame only after processing all the sup/sub pairs
380 boundingMetrics.width = bmBase.width;
381 boundingMetrics.rightBearing = bmBase.rightBearing;
382 boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
383 } else {
384 // super/subscript block
385 if (childFrame->GetContent()->IsMathMLElement(nsGkAtoms::none)) {
386 foundNoneTag = true;
389 if (isSubScript) {
390 // subscript
391 subScriptFrame = childFrame;
392 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
393 // get the subdrop from the subscript font
394 GetSubDropFromChild (subScriptFrame, subDrop, aFontSizeInflation);
395 // parameter v, Rule 18a, App. G, TeXbook
396 minSubScriptShift = bmBase.descent + subDrop;
397 trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
398 multiSubSize.SetBlockStartAscent(
399 std::max(multiSubSize.BlockStartAscent(),
400 subScriptSize.BlockStartAscent()));
401 bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
402 bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
403 multiSubSize.Height() =
404 std::max(multiSubSize.Height(),
405 subScriptSize.Height() - subScriptSize.BlockStartAscent());
406 if (bmSubScript.width)
407 width = bmSubScript.width + scriptSpace;
408 rightBearing = bmSubScript.rightBearing;
410 if (tag == nsGkAtoms::msub_) {
411 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
412 boundingMetrics.width += width;
414 nscoord subscriptTopMax;
415 if (mathFont) {
416 subscriptTopMax =
417 mathFont->GetMathConstant(gfxFontEntry::SubscriptTopMax,
418 oneDevPixel);
419 } else {
420 // get min subscript shift limit from x-height
421 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
422 subscriptTopMax = NSToCoordRound((4.0f/5.0f) * xHeight);
424 nscoord minShiftFromXHeight = bmSubScript.ascent - subscriptTopMax;
425 maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
427 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
428 trySubScriptShift = subScriptShift;
430 } else {
431 // supscript
432 supScriptFrame = childFrame;
433 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
434 // get the supdrop from the supscript font
435 GetSupDropFromChild (supScriptFrame, supDrop, aFontSizeInflation);
436 // parameter u, Rule 18a, App. G, TeXbook
437 minSupScriptShift = bmBase.ascent - supDrop;
438 nscoord superscriptBottomMin;
439 if (mathFont) {
440 superscriptBottomMin =
441 mathFont->GetMathConstant(gfxFontEntry::SuperscriptBottomMin,
442 oneDevPixel);
443 } else {
444 // get min supscript shift limit from x-height
445 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
446 superscriptBottomMin = NSToCoordRound((1.0f / 4.0f) * xHeight);
448 minShiftFromXHeight = bmSupScript.descent + superscriptBottomMin;
449 trySupScriptShift = std::max(minSupScriptShift,
450 std::max(minShiftFromXHeight,
451 supScriptShift));
452 multiSupSize.SetBlockStartAscent(
453 std::max(multiSupSize.BlockStartAscent(),
454 supScriptSize.BlockStartAscent()));
455 bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
456 bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
457 multiSupSize.Height() =
458 std::max(multiSupSize.Height(),
459 supScriptSize.Height() - supScriptSize.BlockStartAscent());
461 if (bmSupScript.width)
462 width = std::max(width, bmSupScript.width + scriptSpace);
464 if (!prescriptsFrame) { // we are still looping over base & postscripts
465 rightBearing = std::max(rightBearing,
466 italicCorrection + bmSupScript.rightBearing);
467 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
468 boundingMetrics.width += width;
469 } else {
470 prescriptsWidth += width;
471 if (firstPrescriptsPair) {
472 firstPrescriptsPair = false;
473 boundingMetrics.leftBearing =
474 std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
477 width = rightBearing = 0;
479 // negotiate between the various shifts so that
480 // there is enough gap between the sup and subscripts
481 // Rule 18e, App. G, TeXbook
482 if (tag == nsGkAtoms::mmultiscripts_ ||
483 tag == nsGkAtoms::msubsup_) {
484 nscoord subSuperscriptGapMin;
485 if (mathFont) {
486 subSuperscriptGapMin =
487 mathFont->GetMathConstant(gfxFontEntry::SubSuperscriptGapMin,
488 oneDevPixel);
489 } else {
490 nscoord ruleSize;
491 GetRuleThickness(aDrawTarget, fm, ruleSize);
492 subSuperscriptGapMin = 4 * ruleSize;
494 nscoord gap =
495 (trySupScriptShift - bmSupScript.descent) -
496 (bmSubScript.ascent - trySubScriptShift);
497 if (gap < subSuperscriptGapMin) {
498 // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
499 trySubScriptShift += subSuperscriptGapMin - gap;
502 // next we want to ensure that the bottom of the superscript
503 // will be > superscriptBottomMaxWithSubscript
504 nscoord superscriptBottomMaxWithSubscript;
505 if (mathFont) {
506 superscriptBottomMaxWithSubscript = mathFont->
507 GetMathConstant(gfxFontEntry::SuperscriptBottomMaxWithSubscript,
508 oneDevPixel);
509 } else {
510 superscriptBottomMaxWithSubscript =
511 NSToCoordRound((4.0f / 5.0f) * xHeight);
513 gap = superscriptBottomMaxWithSubscript -
514 (trySupScriptShift - bmSupScript.descent);
515 if (gap > 0) {
516 trySupScriptShift += gap;
517 trySubScriptShift -= gap;
521 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
522 maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
524 trySubScriptShift = subScriptShift;
525 trySupScriptShift = supScriptShift;
528 isSubScript = !isSubScript;
530 count++;
531 childFrame = childFrame->GetNextSibling();
534 //NoBase error may also have been reported above
535 if ((count != 2 && (tag == nsGkAtoms::msup_ || tag == nsGkAtoms::msub_)) ||
536 (count != 3 && tag == nsGkAtoms::msubsup_) || !baseFrame ||
537 (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
538 (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
539 // report an error, encourage people to get their markups in order
540 if (aPlaceOrigin) {
541 if ((count != 2 && (tag == nsGkAtoms::msup_ ||
542 tag == nsGkAtoms::msub_)) ||
543 (count != 3 && tag == nsGkAtoms::msubsup_ )) {
544 aFrame->ReportChildCountError();
545 } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
546 aFrame->ReportInvalidChildError(nsGkAtoms::none);
547 } else if (!baseFrame) {
548 aFrame->ReportErrorToConsole("NoBase");
549 } else {
550 aFrame->ReportErrorToConsole("SubSupMismatch");
553 return aFrame->ReflowError(aDrawTarget, aDesiredSize);
556 // we left out the width of prescripts, so ...
557 boundingMetrics.rightBearing += prescriptsWidth;
558 boundingMetrics.width += prescriptsWidth;
560 // Zero out the shifts in where a frame isn't present to avoid the potential
561 // for overflow.
562 if (!subScriptFrame)
563 maxSubScriptShift = 0;
564 if (!supScriptFrame)
565 maxSupScriptShift = 0;
567 // we left out the base during our bounding box updates, so ...
568 if (tag == nsGkAtoms::msub_) {
569 boundingMetrics.ascent = std::max(bmBase.ascent,
570 bmMultiSub.ascent - maxSubScriptShift);
571 } else {
572 boundingMetrics.ascent =
573 std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
575 if (tag == nsGkAtoms::msup_) {
576 boundingMetrics.descent = std::max(bmBase.descent,
577 bmMultiSup.descent - maxSupScriptShift);
578 } else {
579 boundingMetrics.descent =
580 std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
582 aFrame->SetBoundingMetrics(boundingMetrics);
584 // get the reflow metrics ...
585 aDesiredSize.SetBlockStartAscent(
586 std::max(baseSize.BlockStartAscent(),
587 std::max(multiSubSize.BlockStartAscent() - maxSubScriptShift,
588 multiSupSize.BlockStartAscent() + maxSupScriptShift)));
589 aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
590 std::max(baseSize.Height() - baseSize.BlockStartAscent(),
591 std::max(multiSubSize.Height() + maxSubScriptShift,
592 multiSupSize.Height() - maxSupScriptShift));
593 aDesiredSize.Width() = boundingMetrics.width;
594 aDesiredSize.mBoundingMetrics = boundingMetrics;
596 aFrame->SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
598 //////////////////
599 // Place Children
601 // Place prescripts, followed by base, and then postscripts.
602 // The list of frames is in the order: {base} {postscripts} {prescripts}
603 // We go over the list in a circular manner, starting at <prescripts/>
605 if (aPlaceOrigin) {
606 nscoord dx = 0, dy = 0;
608 // With msub and msup there is only one element and
609 // subscriptFrame/supScriptFrame have already been set above where
610 // relevant. In these cases we skip to the reflow part.
611 if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
612 count = 1;
613 else
614 count = 0;
615 childFrame = prescriptsFrame;
616 bool isPreScript = true;
617 do {
618 if (!childFrame) { // end of prescripts,
619 isPreScript = false;
620 // place the base ...
621 childFrame = baseFrame;
622 dy = aDesiredSize.BlockStartAscent() - baseSize.BlockStartAscent();
623 FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
624 aFrame->MirrorIfRTL(aDesiredSize.Width(),
625 baseSize.Width(),
626 dx),
627 dy, 0);
628 dx += bmBase.width;
629 } else if (prescriptsFrame == childFrame) {
630 // Clear reflow flags of prescripts frame.
631 prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
632 } else {
633 // process each sup/sub pair
634 if (0 == count) {
635 subScriptFrame = childFrame;
636 count = 1;
637 } else if (1 == count) {
638 if (tag != nsGkAtoms::msub_)
639 supScriptFrame = childFrame;
640 count = 0;
642 // get the ascent/descent of sup/subscripts stored in their rects
643 // rect.x = descent, rect.y = ascent
644 if (subScriptFrame)
645 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
646 if (supScriptFrame)
647 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
649 width = std::max(subScriptSize.Width(), supScriptSize.Width());
651 if (subScriptFrame) {
652 nscoord x = dx;
653 // prescripts should be right aligned
654 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
655 if (isPreScript)
656 x += width - subScriptSize.Width();
657 dy = aDesiredSize.BlockStartAscent() - subScriptSize.BlockStartAscent() +
658 maxSubScriptShift;
659 FinishReflowChild (subScriptFrame, aPresContext, subScriptSize,
660 nullptr,
661 aFrame->MirrorIfRTL(aDesiredSize.Width(),
662 subScriptSize.Width(),
664 dy, 0);
667 if (supScriptFrame) {
668 nscoord x = dx;
669 if (isPreScript) {
670 x += width - supScriptSize.Width();
671 } else {
672 // post superscripts are shifted by the italic correction value
673 x += italicCorrection;
675 dy = aDesiredSize.BlockStartAscent() - supScriptSize.BlockStartAscent() -
676 maxSupScriptShift;
677 FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
678 nullptr,
679 aFrame->MirrorIfRTL(aDesiredSize.Width(),
680 supScriptSize.Width(),
682 dy, 0);
684 dx += width + scriptSpace;
687 childFrame = childFrame->GetNextSibling();
688 } while (prescriptsFrame != childFrame);
691 return NS_OK;