1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMathMLmmultiscriptsFrame.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/Element.h"
11 #include "mozilla/PresShell.h"
12 #include "mozilla/StaticPrefs_mathml.h"
13 #include "nsLayoutUtils.h"
14 #include "nsPresContext.h"
16 #include "gfxContext.h"
17 #include "gfxMathTable.h"
18 #include "gfxTextRun.h"
20 using namespace mozilla
;
23 // <mmultiscripts> -- attach prescripts and tensor indices to a base -
24 // implementation <msub> -- attach a subscript to a base - implementation
25 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
26 // <msup> -- attach a superscript to a base - implementation
29 nsIFrame
* NS_NewMathMLmmultiscriptsFrame(PresShell
* aPresShell
,
30 ComputedStyle
* aStyle
) {
31 return new (aPresShell
)
32 nsMathMLmmultiscriptsFrame(aStyle
, aPresShell
->GetPresContext());
35 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame
)
37 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame() = default;
39 uint8_t nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame
* aFrame
) {
40 if (!aFrame
) return 0;
41 if (mFrames
.ContainsFrame(aFrame
)) {
42 if (mFrames
.FirstChild() == aFrame
||
43 aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
44 return 0; // No script increment for base frames or prescript markers
48 return 0; // not a child
52 nsMathMLmmultiscriptsFrame::TransmitAutomaticData() {
53 // if our base is an embellished operator, let its state bubble to us
54 mPresentationData
.baseFrame
= mFrames
.FirstChild();
55 GetEmbellishDataFrom(mPresentationData
.baseFrame
, mEmbellishData
);
57 // The TeXbook (Ch 17. p.141) says the superscript inherits the compression
58 // while the subscript is compressed. So here we collect subscripts and set
59 // the compression flag in them.
62 bool isSubScript
= !mContent
->IsMathMLElement(nsGkAtoms::msup_
);
64 AutoTArray
<nsIFrame
*, 8> subScriptFrames
;
65 nsIFrame
* childFrame
= mFrames
.FirstChild();
67 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
69 } else if (0 == count
) {
72 // super/subscript block
75 subScriptFrames
.AppendElement(childFrame
);
79 PropagateFrameFlagFor(childFrame
, NS_FRAME_MATHML_SCRIPT_DESCENDANT
);
80 isSubScript
= !isSubScript
;
83 childFrame
= childFrame
->GetNextSibling();
85 for (int32_t i
= subScriptFrames
.Length() - 1; i
>= 0; i
--) {
86 childFrame
= subScriptFrames
[i
];
87 PropagatePresentationDataFor(childFrame
, NS_MATHML_COMPRESSED
,
88 NS_MATHML_COMPRESSED
);
95 nsresult
nsMathMLmmultiscriptsFrame::Place(DrawTarget
* aDrawTarget
,
97 ReflowOutput
& aDesiredSize
) {
98 nscoord subScriptShift
= 0;
99 nscoord supScriptShift
= 0;
100 float fontSizeInflation
= nsLayoutUtils::FontSizeInflationFor(this);
102 return PlaceMultiScript(PresContext(), aDrawTarget
, aPlaceOrigin
,
103 aDesiredSize
, this, subScriptShift
, supScriptShift
,
107 // exported routine that both munderover and mmultiscripts share.
108 // munderover uses this when movablelimits is set.
109 nsresult
nsMathMLmmultiscriptsFrame::PlaceMultiScript(
110 nsPresContext
* aPresContext
, DrawTarget
* aDrawTarget
, bool aPlaceOrigin
,
111 ReflowOutput
& aDesiredSize
, nsMathMLContainerFrame
* aFrame
,
112 nscoord aUserSubScriptShift
, nscoord aUserSupScriptShift
,
113 float aFontSizeInflation
) {
114 nsAtom
* tag
= aFrame
->GetContent()->NodeInfo()->NameAtom();
116 // This function deals with both munderover etc. as well as msubsup etc.
117 // As the former behaves identically to the later, we treat it as such
118 // to avoid additional checks later.
119 if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mover_
))
120 tag
= nsGkAtoms::msup_
;
121 else if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::munder_
))
122 tag
= nsGkAtoms::msub_
;
123 else if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::munderover_
))
124 tag
= nsGkAtoms::msubsup_
;
126 nsBoundingMetrics bmFrame
;
128 nscoord minShiftFromXHeight
, subDrop
, supDrop
;
130 ////////////////////////////////////////
131 // Initialize super/sub shifts that
132 // depend only on the current font
133 ////////////////////////////////////////
135 nsIFrame
* baseFrame
= aFrame
->PrincipalChildList().FirstChild();
138 if (tag
== nsGkAtoms::mmultiscripts_
)
139 aFrame
->ReportErrorToConsole("NoBase");
141 aFrame
->ReportChildCountError();
142 return aFrame
->PlaceAsMrow(aDrawTarget
, aPlaceOrigin
, aDesiredSize
);
145 // get x-height (an ex)
146 const nsStyleFont
* font
= aFrame
->StyleFont();
147 RefPtr
<nsFontMetrics
> fm
=
148 nsLayoutUtils::GetFontMetricsForFrame(baseFrame
, aFontSizeInflation
);
150 nscoord xHeight
= fm
->XHeight();
152 nscoord oneDevPixel
= fm
->AppUnitsPerDevPixel();
153 RefPtr
<gfxFont
> mathFont
= fm
->GetThebesFontGroup()->GetFirstMathFont();
154 // scriptspace from TeX for extra spacing after sup/subscript
157 scriptSpace
= mathFont
->MathTable()->Constant(
158 gfxMathTable::SpaceAfterScript
, oneDevPixel
);
160 // (0.5pt in plain TeX)
161 scriptSpace
= nsPresContext::CSSPointsToAppUnits(0.5f
);
164 // Try and read sub and sup drops from the MATH table.
166 subDrop
= mathFont
->MathTable()->Constant(
167 gfxMathTable::SubscriptBaselineDropMin
, oneDevPixel
);
168 supDrop
= mathFont
->MathTable()->Constant(
169 gfxMathTable::SuperscriptBaselineDropMax
, oneDevPixel
);
172 // force the scriptSpace to be at least 1 pixel
173 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
174 scriptSpace
= std::max(onePixel
, scriptSpace
);
176 /////////////////////////////////////
177 // first the shift for the subscript
179 nscoord subScriptShift
;
181 // Try and get the sub script shift from the MATH table. Note that contrary
182 // to TeX we only have one parameter.
183 subScriptShift
= mathFont
->MathTable()->Constant(
184 gfxMathTable::SubscriptShiftDown
, oneDevPixel
);
186 // subScriptShift{1,2}
187 // = minimum amount to shift the subscript down
188 // = sub{1,2} in TeXbook
189 // subScriptShift1 = subscriptshift attribute * x-height
190 nscoord subScriptShift1
, subScriptShift2
;
191 // Get subScriptShift{1,2} default from font
192 GetSubScriptShifts(fm
, subScriptShift1
, subScriptShift2
);
193 if (tag
== nsGkAtoms::msub_
) {
194 subScriptShift
= subScriptShift1
;
196 subScriptShift
= std::max(subScriptShift1
, subScriptShift2
);
200 if (0 < aUserSubScriptShift
) {
201 // the user has set the subscriptshift attribute
202 subScriptShift
= std::max(subScriptShift
, aUserSubScriptShift
);
205 /////////////////////////////////////
206 // next the shift for the superscript
208 nscoord supScriptShift
;
209 nsPresentationData presentationData
;
210 aFrame
->GetPresentationData(presentationData
);
212 // Try and get the super script shift from the MATH table. Note that
213 // contrary to TeX we only have two parameters.
214 supScriptShift
= mathFont
->MathTable()->Constant(
215 NS_MATHML_IS_COMPRESSED(presentationData
.flags
)
216 ? gfxMathTable::SuperscriptShiftUpCramped
217 : gfxMathTable::SuperscriptShiftUp
,
220 // supScriptShift{1,2,3}
221 // = minimum amount to shift the supscript up
222 // = sup{1,2,3} in TeX
223 // supScriptShift1 = superscriptshift attribute * x-height
224 // Note that there are THREE values for supscript shifts depending
225 // on the current style
226 nscoord supScriptShift1
, supScriptShift2
, supScriptShift3
;
227 // Set supScriptShift{1,2,3} default from font
228 GetSupScriptShifts(fm
, supScriptShift1
, supScriptShift2
, supScriptShift3
);
230 // get sup script shift depending on current script level and display style
231 // Rule 18c, App. G, TeXbook
232 if (font
->mMathDepth
== 0 && font
->mMathStyle
== StyleMathStyle::Normal
&&
233 !NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
234 // Style D in TeXbook
235 supScriptShift
= supScriptShift1
;
236 } else if (NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
237 // Style C' in TeXbook = D',T',S',SS'
238 supScriptShift
= supScriptShift3
;
240 // everything else = T,S,SS
241 supScriptShift
= supScriptShift2
;
245 if (0 < aUserSupScriptShift
) {
246 // the user has set the supscriptshift attribute
247 supScriptShift
= std::max(supScriptShift
, aUserSupScriptShift
);
250 ////////////////////////////////////
251 // Get the children's sizes
252 ////////////////////////////////////
254 const WritingMode
wm(aDesiredSize
.GetWritingMode());
255 nscoord width
= 0, prescriptsWidth
= 0, rightBearing
= 0;
256 nscoord minSubScriptShift
= 0, minSupScriptShift
= 0;
257 nscoord trySubScriptShift
= subScriptShift
;
258 nscoord trySupScriptShift
= supScriptShift
;
259 nscoord maxSubScriptShift
= subScriptShift
;
260 nscoord maxSupScriptShift
= supScriptShift
;
261 ReflowOutput
baseSize(wm
);
262 ReflowOutput
subScriptSize(wm
);
263 ReflowOutput
supScriptSize(wm
);
264 ReflowOutput
multiSubSize(wm
), multiSupSize(wm
);
266 nsIFrame
* subScriptFrame
= nullptr;
267 nsIFrame
* supScriptFrame
= nullptr;
268 nsIFrame
* prescriptsFrame
= nullptr; // frame of <mprescripts/>, if there.
270 bool firstPrescriptsPair
= false;
271 nsBoundingMetrics bmBase
, bmSubScript
, bmSupScript
, bmMultiSub
, bmMultiSup
;
272 multiSubSize
.SetBlockStartAscent(-0x7FFFFFFF);
273 multiSupSize
.SetBlockStartAscent(-0x7FFFFFFF);
274 bmMultiSub
.ascent
= bmMultiSup
.ascent
= -0x7FFFFFFF;
275 bmMultiSub
.descent
= bmMultiSup
.descent
= -0x7FFFFFFF;
276 nscoord italicCorrection
= 0;
278 nsBoundingMetrics boundingMetrics
;
279 boundingMetrics
.width
= 0;
280 boundingMetrics
.ascent
= boundingMetrics
.descent
= -0x7FFFFFFF;
281 aDesiredSize
.Width() = aDesiredSize
.Height() = 0;
285 // Boolean to determine whether the current child is a subscript.
286 // Note that only msup starts with a superscript.
287 bool isSubScript
= (tag
!= nsGkAtoms::msup_
);
289 nsIFrame
* childFrame
= aFrame
->PrincipalChildList().FirstChild();
291 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
292 if (tag
!= nsGkAtoms::mmultiscripts_
) {
294 aFrame
->ReportInvalidChildError(nsGkAtoms::mprescripts_
);
296 return aFrame
->PlaceAsMrow(aDrawTarget
, aPlaceOrigin
, aDesiredSize
);
298 if (prescriptsFrame
) {
299 // duplicate <mprescripts/> found
300 // report an error, encourage people to get their markups in order
302 aFrame
->ReportErrorToConsole("DuplicateMprescripts");
304 return aFrame
->PlaceAsMrow(aDrawTarget
, aPlaceOrigin
, aDesiredSize
);
308 aFrame
->ReportErrorToConsole("SubSupMismatch");
310 return aFrame
->PlaceAsMrow(aDrawTarget
, aPlaceOrigin
, aDesiredSize
);
313 prescriptsFrame
= childFrame
;
314 firstPrescriptsPair
= true;
315 } else if (0 == count
) {
317 baseFrame
= childFrame
;
318 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
320 if (tag
!= nsGkAtoms::msub_
) {
321 // Apply italics correction if there is the potential for a
323 GetItalicCorrection(bmBase
, italicCorrection
);
324 // If italics correction is applied, we always add "a little to spare"
325 // (see TeXbook Ch.11, p.64), as we estimate the italic creation
326 // ourselves and it isn't the same as TeX.
327 italicCorrection
+= onePixel
;
330 // we update boundingMetrics.{ascent,descent} with that
331 // of the baseFrame only after processing all the sup/sub pairs
332 boundingMetrics
.width
= bmBase
.width
;
333 boundingMetrics
.rightBearing
= bmBase
.rightBearing
;
334 boundingMetrics
.leftBearing
= bmBase
.leftBearing
; // until overwritten
336 // super/subscript block
339 subScriptFrame
= childFrame
;
340 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
,
343 // get the subdrop from the subscript font
344 GetSubDropFromChild(subScriptFrame
, subDrop
, aFontSizeInflation
);
347 // parameter v, Rule 18a, App. G, TeXbook
348 minSubScriptShift
= bmBase
.descent
+ subDrop
;
349 trySubScriptShift
= std::max(minSubScriptShift
, subScriptShift
);
350 multiSubSize
.SetBlockStartAscent(std::max(
351 multiSubSize
.BlockStartAscent(), subScriptSize
.BlockStartAscent()));
352 bmMultiSub
.ascent
= std::max(bmMultiSub
.ascent
, bmSubScript
.ascent
);
353 bmMultiSub
.descent
= std::max(bmMultiSub
.descent
, bmSubScript
.descent
);
354 multiSubSize
.Height() =
355 std::max(multiSubSize
.Height(),
356 subScriptSize
.Height() - subScriptSize
.BlockStartAscent());
357 if (bmSubScript
.width
) width
= bmSubScript
.width
+ scriptSpace
;
358 rightBearing
= bmSubScript
.rightBearing
;
360 if (tag
== nsGkAtoms::msub_
) {
361 boundingMetrics
.rightBearing
= boundingMetrics
.width
+ rightBearing
;
362 boundingMetrics
.width
+= width
;
364 nscoord subscriptTopMax
;
366 subscriptTopMax
= mathFont
->MathTable()->Constant(
367 gfxMathTable::SubscriptTopMax
, oneDevPixel
);
369 // get min subscript shift limit from x-height
370 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
371 subscriptTopMax
= NSToCoordRound((4.0f
/ 5.0f
) * xHeight
);
373 nscoord minShiftFromXHeight
= bmSubScript
.ascent
- subscriptTopMax
;
374 maxSubScriptShift
= std::max(trySubScriptShift
, minShiftFromXHeight
);
376 maxSubScriptShift
= std::max(maxSubScriptShift
, trySubScriptShift
);
377 trySubScriptShift
= subScriptShift
;
381 supScriptFrame
= childFrame
;
382 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
,
385 // get the supdrop from the supscript font
386 GetSupDropFromChild(supScriptFrame
, supDrop
, aFontSizeInflation
);
388 // parameter u, Rule 18a, App. G, TeXbook
389 minSupScriptShift
= bmBase
.ascent
- supDrop
;
390 nscoord superscriptBottomMin
;
392 superscriptBottomMin
= mathFont
->MathTable()->Constant(
393 gfxMathTable::SuperscriptBottomMin
, oneDevPixel
);
395 // get min supscript shift limit from x-height
396 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
397 superscriptBottomMin
= NSToCoordRound((1.0f
/ 4.0f
) * xHeight
);
399 minShiftFromXHeight
= bmSupScript
.descent
+ superscriptBottomMin
;
400 trySupScriptShift
= std::max(
401 minSupScriptShift
, std::max(minShiftFromXHeight
, supScriptShift
));
402 multiSupSize
.SetBlockStartAscent(std::max(
403 multiSupSize
.BlockStartAscent(), supScriptSize
.BlockStartAscent()));
404 bmMultiSup
.ascent
= std::max(bmMultiSup
.ascent
, bmSupScript
.ascent
);
405 bmMultiSup
.descent
= std::max(bmMultiSup
.descent
, bmSupScript
.descent
);
406 multiSupSize
.Height() =
407 std::max(multiSupSize
.Height(),
408 supScriptSize
.Height() - supScriptSize
.BlockStartAscent());
410 if (bmSupScript
.width
)
411 width
= std::max(width
, bmSupScript
.width
+ scriptSpace
);
413 if (!prescriptsFrame
) { // we are still looping over base & postscripts
414 rightBearing
= std::max(rightBearing
,
415 italicCorrection
+ bmSupScript
.rightBearing
);
416 boundingMetrics
.rightBearing
= boundingMetrics
.width
+ rightBearing
;
417 boundingMetrics
.width
+= width
;
419 prescriptsWidth
+= width
;
420 if (firstPrescriptsPair
) {
421 firstPrescriptsPair
= false;
422 boundingMetrics
.leftBearing
=
423 std::min(bmSubScript
.leftBearing
, bmSupScript
.leftBearing
);
426 width
= rightBearing
= 0;
428 // negotiate between the various shifts so that
429 // there is enough gap between the sup and subscripts
430 // Rule 18e, App. G, TeXbook
431 if (tag
== nsGkAtoms::mmultiscripts_
|| tag
== nsGkAtoms::msubsup_
) {
432 nscoord subSuperscriptGapMin
;
434 subSuperscriptGapMin
= mathFont
->MathTable()->Constant(
435 gfxMathTable::SubSuperscriptGapMin
, oneDevPixel
);
438 GetRuleThickness(aDrawTarget
, fm
, ruleSize
);
439 subSuperscriptGapMin
= 4 * ruleSize
;
441 nscoord gap
= (trySupScriptShift
- bmSupScript
.descent
) -
442 (bmSubScript
.ascent
- trySubScriptShift
);
443 if (gap
< subSuperscriptGapMin
) {
444 // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
445 trySubScriptShift
+= subSuperscriptGapMin
- gap
;
448 // next we want to ensure that the bottom of the superscript
449 // will be > superscriptBottomMaxWithSubscript
450 nscoord superscriptBottomMaxWithSubscript
;
452 superscriptBottomMaxWithSubscript
= mathFont
->MathTable()->Constant(
453 gfxMathTable::SuperscriptBottomMaxWithSubscript
, oneDevPixel
);
455 superscriptBottomMaxWithSubscript
=
456 NSToCoordRound((4.0f
/ 5.0f
) * xHeight
);
458 gap
= superscriptBottomMaxWithSubscript
-
459 (trySupScriptShift
- bmSupScript
.descent
);
461 trySupScriptShift
+= gap
;
462 trySubScriptShift
-= gap
;
466 maxSubScriptShift
= std::max(maxSubScriptShift
, trySubScriptShift
);
467 maxSupScriptShift
= std::max(maxSupScriptShift
, trySupScriptShift
);
469 trySubScriptShift
= subScriptShift
;
470 trySupScriptShift
= supScriptShift
;
473 isSubScript
= !isSubScript
;
476 childFrame
= childFrame
->GetNextSibling();
479 // NoBase error may also have been reported above
480 if ((count
!= 2 && (tag
== nsGkAtoms::msup_
|| tag
== nsGkAtoms::msub_
)) ||
481 (count
!= 3 && tag
== nsGkAtoms::msubsup_
) || !baseFrame
||
482 (!isSubScript
&& tag
== nsGkAtoms::mmultiscripts_
)) {
483 // report an error, encourage people to get their markups in order
486 (tag
== nsGkAtoms::msup_
|| tag
== nsGkAtoms::msub_
)) ||
487 (count
!= 3 && tag
== nsGkAtoms::msubsup_
)) {
488 aFrame
->ReportChildCountError();
489 } else if (!baseFrame
) {
490 aFrame
->ReportErrorToConsole("NoBase");
492 aFrame
->ReportErrorToConsole("SubSupMismatch");
495 return aFrame
->PlaceAsMrow(aDrawTarget
, aPlaceOrigin
, aDesiredSize
);
498 // we left out the width of prescripts, so ...
499 boundingMetrics
.rightBearing
+= prescriptsWidth
;
500 boundingMetrics
.width
+= prescriptsWidth
;
502 // Zero out the shifts in where a frame isn't present to avoid the potential
504 if (!subScriptFrame
) maxSubScriptShift
= 0;
505 if (!supScriptFrame
) maxSupScriptShift
= 0;
507 // we left out the base during our bounding box updates, so ...
508 if (tag
== nsGkAtoms::msub_
) {
509 boundingMetrics
.ascent
=
510 std::max(bmBase
.ascent
, bmMultiSub
.ascent
- maxSubScriptShift
);
512 boundingMetrics
.ascent
=
513 std::max(bmBase
.ascent
, (bmMultiSup
.ascent
+ maxSupScriptShift
));
515 if (tag
== nsGkAtoms::msup_
) {
516 boundingMetrics
.descent
=
517 std::max(bmBase
.descent
, bmMultiSup
.descent
- maxSupScriptShift
);
519 boundingMetrics
.descent
=
520 std::max(bmBase
.descent
, (bmMultiSub
.descent
+ maxSubScriptShift
));
522 aFrame
->SetBoundingMetrics(boundingMetrics
);
524 // get the reflow metrics ...
525 aDesiredSize
.SetBlockStartAscent(
526 std::max(baseSize
.BlockStartAscent(),
527 std::max(multiSubSize
.BlockStartAscent() - maxSubScriptShift
,
528 multiSupSize
.BlockStartAscent() + maxSupScriptShift
)));
529 aDesiredSize
.Height() =
530 aDesiredSize
.BlockStartAscent() +
531 std::max(baseSize
.Height() - baseSize
.BlockStartAscent(),
532 std::max(multiSubSize
.Height() + maxSubScriptShift
,
533 multiSupSize
.Height() - maxSupScriptShift
));
534 aDesiredSize
.Width() = boundingMetrics
.width
;
535 aDesiredSize
.mBoundingMetrics
= boundingMetrics
;
537 aFrame
->SetReference(nsPoint(0, aDesiredSize
.BlockStartAscent()));
542 // Place prescripts, followed by base, and then postscripts.
543 // The list of frames is in the order: {base} {postscripts} {prescripts}
544 // We go over the list in a circular manner, starting at <prescripts/>
547 nscoord dx
= 0, dy
= 0;
549 // With msub and msup there is only one element and
550 // subscriptFrame/supScriptFrame have already been set above where
551 // relevant. In these cases we skip to the reflow part.
552 if (tag
== nsGkAtoms::msub_
|| tag
== nsGkAtoms::msup_
)
556 childFrame
= prescriptsFrame
;
557 bool isPreScript
= true;
559 if (!childFrame
) { // end of prescripts,
561 // place the base ...
562 childFrame
= baseFrame
;
563 dy
= aDesiredSize
.BlockStartAscent() - baseSize
.BlockStartAscent();
565 baseFrame
, aPresContext
, baseSize
, nullptr,
566 aFrame
->MirrorIfRTL(aDesiredSize
.Width(), baseSize
.Width(), dx
), dy
,
567 ReflowChildFlags::Default
);
569 } else if (prescriptsFrame
== childFrame
) {
570 // Clear reflow flags of prescripts frame.
571 prescriptsFrame
->DidReflow(aPresContext
, nullptr);
573 // process each sup/sub pair
575 subScriptFrame
= childFrame
;
577 } else if (1 == count
) {
578 if (tag
!= nsGkAtoms::msub_
) supScriptFrame
= childFrame
;
581 // get the ascent/descent of sup/subscripts stored in their rects
582 // rect.x = descent, rect.y = ascent
584 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
,
587 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
,
590 width
= std::max(subScriptSize
.Width(), supScriptSize
.Width());
592 if (subScriptFrame
) {
594 // prescripts should be right aligned
595 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
596 if (isPreScript
) x
+= width
- subScriptSize
.Width();
597 dy
= aDesiredSize
.BlockStartAscent() -
598 subScriptSize
.BlockStartAscent() + maxSubScriptShift
;
599 FinishReflowChild(subScriptFrame
, aPresContext
, subScriptSize
,
601 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
602 subScriptSize
.Width(), x
),
603 dy
, ReflowChildFlags::Default
);
606 if (supScriptFrame
) {
609 x
+= width
- supScriptSize
.Width();
611 // post superscripts are shifted by the italic correction value
612 x
+= italicCorrection
;
614 dy
= aDesiredSize
.BlockStartAscent() -
615 supScriptSize
.BlockStartAscent() - maxSupScriptShift
;
616 FinishReflowChild(supScriptFrame
, aPresContext
, supScriptSize
,
618 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
619 supScriptSize
.Width(), x
),
620 dy
, ReflowChildFlags::Default
);
622 dx
+= width
+ scriptSpace
;
625 childFrame
= childFrame
->GetNextSibling();
626 } while (prescriptsFrame
!= childFrame
);