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/. */
8 #include "nsMathMLmmultiscriptsFrame.h"
9 #include "nsPresContext.h"
11 #include "gfxContext.h"
12 #include "gfxMathTable.h"
14 using mozilla::WritingMode
;
17 // <mmultiscripts> -- attach prescripts and tensor indices to a base - implementation
18 // <msub> -- attach a subscript to a base - implementation
19 // <msubsup> -- attach a subscript-superscript pair to a base - implementation
20 // <msup> -- attach a superscript to a base - implementation
24 NS_NewMathMLmmultiscriptsFrame(nsIPresShell
* aPresShell
, ComputedStyle
* aStyle
)
26 return new (aPresShell
) nsMathMLmmultiscriptsFrame(aStyle
);
29 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame
)
31 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
36 nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame
* aFrame
)
40 if (mFrames
.ContainsFrame(aFrame
)) {
41 if (mFrames
.FirstChild() == aFrame
||
42 aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
43 return 0; // No script increment for base frames or prescript markers
47 return 0; //not a child
51 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
,
88 NS_MATHML_COMPRESSED
, NS_MATHML_COMPRESSED
);
94 /* virtual */ nsresult
95 nsMathMLmmultiscriptsFrame::Place(DrawTarget
* aDrawTarget
,
97 ReflowOutput
& aDesiredSize
)
99 nscoord subScriptShift
= 0;
100 nscoord supScriptShift
= 0;
101 float fontSizeInflation
= nsLayoutUtils::FontSizeInflationFor(this);
105 // "Specifies the minimum amount to shift the baseline of subscript down; the
106 // default is for the rendering agent to use its own positioning rules."
109 // default: automatic
111 // We use 0 as the default value so unitless values can be ignored.
112 // As a minimum, negative values can be ignored.
115 if (!mContent
->IsMathMLElement(nsGkAtoms::msup_
)) {
116 mContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::subscriptshift_
, value
);
117 if (!value
.IsEmpty()) {
118 ParseNumericValue(value
, &subScriptShift
, 0, PresContext(),
119 mComputedStyle
, fontSizeInflation
);
124 // "Specifies the minimum amount to shift the baseline of superscript up; the
125 // default is for the rendering agent to use its own positioning rules."
128 // default: automatic
130 // We use 0 as the default value so unitless values can be ignored.
131 // As a minimum, negative values can be ignored.
133 if (!mContent
->IsMathMLElement(nsGkAtoms::msub_
)) {
134 mContent
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::superscriptshift_
, value
);
135 if (!value
.IsEmpty()) {
136 ParseNumericValue(value
, &supScriptShift
, 0, PresContext(),
137 mComputedStyle
, fontSizeInflation
);
140 return PlaceMultiScript(PresContext(), aDrawTarget
, aPlaceOrigin
,
141 aDesiredSize
, this, subScriptShift
, supScriptShift
,
145 // exported routine that both munderover and mmultiscripts share.
146 // munderover uses this when movablelimits is set.
148 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext
* aPresContext
,
149 DrawTarget
* aDrawTarget
,
151 ReflowOutput
& aDesiredSize
,
152 nsMathMLContainerFrame
* aFrame
,
153 nscoord aUserSubScriptShift
,
154 nscoord aUserSupScriptShift
,
155 float aFontSizeInflation
)
157 nsAtom
* tag
= aFrame
->GetContent()->NodeInfo()->NameAtom();
159 // This function deals with both munderover etc. as well as msubsup etc.
160 // As the former behaves identically to the later, we treat it as such
161 // to avoid additional checks later.
162 if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mover_
))
163 tag
= nsGkAtoms::msup_
;
164 else if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::munder_
))
165 tag
= nsGkAtoms::msub_
;
166 else if (aFrame
->GetContent()->IsMathMLElement(nsGkAtoms::munderover_
))
167 tag
= nsGkAtoms::msubsup_
;
169 nsBoundingMetrics bmFrame
;
171 nscoord minShiftFromXHeight
, subDrop
, supDrop
;
173 ////////////////////////////////////////
174 // Initialize super/sub shifts that
175 // depend only on the current font
176 ////////////////////////////////////////
178 nsIFrame
* baseFrame
= aFrame
->PrincipalChildList().FirstChild();
181 if (tag
== nsGkAtoms::mmultiscripts_
)
182 aFrame
->ReportErrorToConsole("NoBase");
184 aFrame
->ReportChildCountError();
185 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
188 // get x-height (an ex)
189 const nsStyleFont
* font
= aFrame
->StyleFont();
190 RefPtr
<nsFontMetrics
> fm
=
191 nsLayoutUtils::GetFontMetricsForFrame(baseFrame
, aFontSizeInflation
);
193 nscoord xHeight
= fm
->XHeight();
195 nscoord oneDevPixel
= fm
->AppUnitsPerDevPixel();
196 gfxFont
* mathFont
= fm
->GetThebesFontGroup()->GetFirstMathFont();
197 // scriptspace from TeX for extra spacing after sup/subscript
200 scriptSpace
= mathFont
->MathTable()->
201 Constant(gfxMathTable::SpaceAfterScript
, oneDevPixel
);
203 // (0.5pt in plain TeX)
204 scriptSpace
= nsPresContext::CSSPointsToAppUnits(0.5f
);
207 // Try and read sub and sup drops from the MATH table.
209 subDrop
= mathFont
->MathTable()->
210 Constant(gfxMathTable::SubscriptBaselineDropMin
, oneDevPixel
);
211 supDrop
= mathFont
->MathTable()->
212 Constant(gfxMathTable::SuperscriptBaselineDropMax
, oneDevPixel
);
215 // force the scriptSpace to be at least 1 pixel
216 nscoord onePixel
= nsPresContext::CSSPixelsToAppUnits(1);
217 scriptSpace
= std::max(onePixel
, scriptSpace
);
219 /////////////////////////////////////
220 // first the shift for the subscript
222 nscoord subScriptShift
;
224 // Try and get the sub script shift from the MATH table. Note that contrary
225 // to TeX we only have one parameter.
226 subScriptShift
= mathFont
->MathTable()->
227 Constant(gfxMathTable::SubscriptShiftDown
, oneDevPixel
);
229 // subScriptShift{1,2}
230 // = minimum amount to shift the subscript down
231 // = sub{1,2} in TeXbook
232 // subScriptShift1 = subscriptshift attribute * x-height
233 nscoord subScriptShift1
, subScriptShift2
;
234 // Get subScriptShift{1,2} default from font
235 GetSubScriptShifts (fm
, subScriptShift1
, subScriptShift2
);
236 if (tag
== nsGkAtoms::msub_
) {
237 subScriptShift
= subScriptShift1
;
239 subScriptShift
= std::max(subScriptShift1
, subScriptShift2
);
243 if (0 < aUserSubScriptShift
) {
244 // the user has set the subscriptshift attribute
245 subScriptShift
= std::max(subScriptShift
, aUserSubScriptShift
);
248 /////////////////////////////////////
249 // next the shift for the superscript
251 nscoord supScriptShift
;
252 nsPresentationData presentationData
;
253 aFrame
->GetPresentationData(presentationData
);
255 // Try and get the super script shift from the MATH table. Note that
256 // contrary to TeX we only have two parameters.
257 supScriptShift
= mathFont
->
258 MathTable()->Constant(NS_MATHML_IS_COMPRESSED(presentationData
.flags
) ?
259 gfxMathTable::SuperscriptShiftUpCramped
:
260 gfxMathTable::SuperscriptShiftUp
,
263 // supScriptShift{1,2,3}
264 // = minimum amount to shift the supscript up
265 // = sup{1,2,3} in TeX
266 // supScriptShift1 = superscriptshift attribute * x-height
267 // Note that there are THREE values for supscript shifts depending
268 // on the current style
269 nscoord supScriptShift1
, supScriptShift2
, supScriptShift3
;
270 // Set supScriptShift{1,2,3} default from font
271 GetSupScriptShifts (fm
, supScriptShift1
, supScriptShift2
, supScriptShift3
);
273 // get sup script shift depending on current script level and display style
274 // Rule 18c, App. G, TeXbook
275 if (font
->mScriptLevel
== 0 &&
276 font
->mMathDisplay
== NS_MATHML_DISPLAYSTYLE_BLOCK
&&
277 !NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
278 // Style D in TeXbook
279 supScriptShift
= supScriptShift1
;
280 } else if (NS_MATHML_IS_COMPRESSED(presentationData
.flags
)) {
281 // Style C' in TeXbook = D',T',S',SS'
282 supScriptShift
= supScriptShift3
;
284 // everything else = T,S,SS
285 supScriptShift
= supScriptShift2
;
289 if (0 < aUserSupScriptShift
) {
290 // the user has set the supscriptshift attribute
291 supScriptShift
= std::max(supScriptShift
, aUserSupScriptShift
);
294 ////////////////////////////////////
295 // Get the children's sizes
296 ////////////////////////////////////
298 const WritingMode
wm(aDesiredSize
.GetWritingMode());
299 nscoord width
= 0, prescriptsWidth
= 0, rightBearing
= 0;
300 nscoord minSubScriptShift
= 0, minSupScriptShift
= 0;
301 nscoord trySubScriptShift
= subScriptShift
;
302 nscoord trySupScriptShift
= supScriptShift
;
303 nscoord maxSubScriptShift
= subScriptShift
;
304 nscoord maxSupScriptShift
= supScriptShift
;
305 ReflowOutput
baseSize(wm
);
306 ReflowOutput
subScriptSize(wm
);
307 ReflowOutput
supScriptSize(wm
);
308 ReflowOutput
multiSubSize(wm
), multiSupSize(wm
);
310 nsIFrame
* subScriptFrame
= nullptr;
311 nsIFrame
* supScriptFrame
= nullptr;
312 nsIFrame
* prescriptsFrame
= nullptr; // frame of <mprescripts/>, if there.
314 bool firstPrescriptsPair
= false;
315 nsBoundingMetrics bmBase
, bmSubScript
, bmSupScript
, bmMultiSub
, bmMultiSup
;
316 multiSubSize
.SetBlockStartAscent(-0x7FFFFFFF);
317 multiSupSize
.SetBlockStartAscent(-0x7FFFFFFF);
318 bmMultiSub
.ascent
= bmMultiSup
.ascent
= -0x7FFFFFFF;
319 bmMultiSub
.descent
= bmMultiSup
.descent
= -0x7FFFFFFF;
320 nscoord italicCorrection
= 0;
322 nsBoundingMetrics boundingMetrics
;
323 boundingMetrics
.width
= 0;
324 boundingMetrics
.ascent
= boundingMetrics
.descent
= -0x7FFFFFFF;
325 aDesiredSize
.Width() = aDesiredSize
.Height() = 0;
328 bool foundNoneTag
= false;
330 // Boolean to determine whether the current child is a subscript.
331 // Note that only msup starts with a superscript.
332 bool isSubScript
= (tag
!= nsGkAtoms::msup_
);
334 nsIFrame
* childFrame
= aFrame
->PrincipalChildList().FirstChild();
336 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
337 if (tag
!= nsGkAtoms::mmultiscripts_
) {
339 aFrame
->ReportInvalidChildError(nsGkAtoms::mprescripts_
);
341 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
343 if (prescriptsFrame
) {
344 // duplicate <mprescripts/> found
345 // report an error, encourage people to get their markups in order
347 aFrame
->ReportErrorToConsole("DuplicateMprescripts");
349 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
353 aFrame
->ReportErrorToConsole("SubSupMismatch");
355 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
358 prescriptsFrame
= childFrame
;
359 firstPrescriptsPair
= true;
360 } else if (0 == count
) {
363 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::none
)) {
364 if (tag
== nsGkAtoms::mmultiscripts_
) {
366 aFrame
->ReportErrorToConsole("NoBase");
368 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
370 //A different error message is triggered later for the other tags
374 baseFrame
= childFrame
;
375 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
377 if (tag
!= nsGkAtoms::msub_
) {
378 // Apply italics correction if there is the potential for a
380 GetItalicCorrection(bmBase
, italicCorrection
);
381 // If italics correction is applied, we always add "a little to spare"
382 // (see TeXbook Ch.11, p.64), as we estimate the italic creation
383 // ourselves and it isn't the same as TeX.
384 italicCorrection
+= onePixel
;
387 // we update boundingMetrics.{ascent,descent} with that
388 // of the baseFrame only after processing all the sup/sub pairs
389 boundingMetrics
.width
= bmBase
.width
;
390 boundingMetrics
.rightBearing
= bmBase
.rightBearing
;
391 boundingMetrics
.leftBearing
= bmBase
.leftBearing
; // until overwritten
393 // super/subscript block
394 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::none
)) {
400 subScriptFrame
= childFrame
;
401 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
, bmSubScript
);
403 // get the subdrop from the subscript font
404 GetSubDropFromChild (subScriptFrame
, subDrop
, aFontSizeInflation
);
407 // parameter v, Rule 18a, App. G, TeXbook
408 minSubScriptShift
= bmBase
.descent
+ subDrop
;
409 trySubScriptShift
= std::max(minSubScriptShift
,subScriptShift
);
410 multiSubSize
.SetBlockStartAscent(
411 std::max(multiSubSize
.BlockStartAscent(),
412 subScriptSize
.BlockStartAscent()));
413 bmMultiSub
.ascent
= std::max(bmMultiSub
.ascent
, bmSubScript
.ascent
);
414 bmMultiSub
.descent
= std::max(bmMultiSub
.descent
, bmSubScript
.descent
);
415 multiSubSize
.Height() =
416 std::max(multiSubSize
.Height(),
417 subScriptSize
.Height() - subScriptSize
.BlockStartAscent());
418 if (bmSubScript
.width
)
419 width
= bmSubScript
.width
+ scriptSpace
;
420 rightBearing
= bmSubScript
.rightBearing
;
422 if (tag
== nsGkAtoms::msub_
) {
423 boundingMetrics
.rightBearing
= boundingMetrics
.width
+ rightBearing
;
424 boundingMetrics
.width
+= width
;
426 nscoord subscriptTopMax
;
429 mathFont
->MathTable()->Constant(gfxMathTable::SubscriptTopMax
,
432 // get min subscript shift limit from x-height
433 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
434 subscriptTopMax
= NSToCoordRound((4.0f
/5.0f
) * xHeight
);
436 nscoord minShiftFromXHeight
= bmSubScript
.ascent
- subscriptTopMax
;
437 maxSubScriptShift
= std::max(trySubScriptShift
,minShiftFromXHeight
);
439 maxSubScriptShift
= std::max(maxSubScriptShift
, trySubScriptShift
);
440 trySubScriptShift
= subScriptShift
;
444 supScriptFrame
= childFrame
;
445 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
, bmSupScript
);
447 // get the supdrop from the supscript font
448 GetSupDropFromChild (supScriptFrame
, supDrop
, aFontSizeInflation
);
450 // parameter u, Rule 18a, App. G, TeXbook
451 minSupScriptShift
= bmBase
.ascent
- supDrop
;
452 nscoord superscriptBottomMin
;
454 superscriptBottomMin
=
455 mathFont
->MathTable()->Constant(gfxMathTable::SuperscriptBottomMin
,
458 // get min supscript shift limit from x-height
459 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
460 superscriptBottomMin
= NSToCoordRound((1.0f
/ 4.0f
) * xHeight
);
462 minShiftFromXHeight
= bmSupScript
.descent
+ superscriptBottomMin
;
463 trySupScriptShift
= std::max(minSupScriptShift
,
464 std::max(minShiftFromXHeight
,
466 multiSupSize
.SetBlockStartAscent(
467 std::max(multiSupSize
.BlockStartAscent(),
468 supScriptSize
.BlockStartAscent()));
469 bmMultiSup
.ascent
= std::max(bmMultiSup
.ascent
, bmSupScript
.ascent
);
470 bmMultiSup
.descent
= std::max(bmMultiSup
.descent
, bmSupScript
.descent
);
471 multiSupSize
.Height() =
472 std::max(multiSupSize
.Height(),
473 supScriptSize
.Height() - supScriptSize
.BlockStartAscent());
475 if (bmSupScript
.width
)
476 width
= std::max(width
, bmSupScript
.width
+ scriptSpace
);
478 if (!prescriptsFrame
) { // we are still looping over base & postscripts
479 rightBearing
= std::max(rightBearing
,
480 italicCorrection
+ bmSupScript
.rightBearing
);
481 boundingMetrics
.rightBearing
= boundingMetrics
.width
+ rightBearing
;
482 boundingMetrics
.width
+= width
;
484 prescriptsWidth
+= width
;
485 if (firstPrescriptsPair
) {
486 firstPrescriptsPair
= false;
487 boundingMetrics
.leftBearing
=
488 std::min(bmSubScript
.leftBearing
, bmSupScript
.leftBearing
);
491 width
= rightBearing
= 0;
493 // negotiate between the various shifts so that
494 // there is enough gap between the sup and subscripts
495 // Rule 18e, App. G, TeXbook
496 if (tag
== nsGkAtoms::mmultiscripts_
||
497 tag
== nsGkAtoms::msubsup_
) {
498 nscoord subSuperscriptGapMin
;
500 subSuperscriptGapMin
= mathFont
->MathTable()->
501 Constant(gfxMathTable::SubSuperscriptGapMin
, oneDevPixel
);
504 GetRuleThickness(aDrawTarget
, fm
, ruleSize
);
505 subSuperscriptGapMin
= 4 * ruleSize
;
508 (trySupScriptShift
- bmSupScript
.descent
) -
509 (bmSubScript
.ascent
- trySubScriptShift
);
510 if (gap
< subSuperscriptGapMin
) {
511 // adjust trySubScriptShift to get a gap of subSuperscriptGapMin
512 trySubScriptShift
+= subSuperscriptGapMin
- gap
;
515 // next we want to ensure that the bottom of the superscript
516 // will be > superscriptBottomMaxWithSubscript
517 nscoord superscriptBottomMaxWithSubscript
;
519 superscriptBottomMaxWithSubscript
= mathFont
->MathTable()->
520 Constant(gfxMathTable::SuperscriptBottomMaxWithSubscript
,
523 superscriptBottomMaxWithSubscript
=
524 NSToCoordRound((4.0f
/ 5.0f
) * xHeight
);
526 gap
= superscriptBottomMaxWithSubscript
-
527 (trySupScriptShift
- bmSupScript
.descent
);
529 trySupScriptShift
+= gap
;
530 trySubScriptShift
-= gap
;
534 maxSubScriptShift
= std::max(maxSubScriptShift
, trySubScriptShift
);
535 maxSupScriptShift
= std::max(maxSupScriptShift
, trySupScriptShift
);
537 trySubScriptShift
= subScriptShift
;
538 trySupScriptShift
= supScriptShift
;
541 isSubScript
= !isSubScript
;
544 childFrame
= childFrame
->GetNextSibling();
547 //NoBase error may also have been reported above
548 if ((count
!= 2 && (tag
== nsGkAtoms::msup_
|| tag
== nsGkAtoms::msub_
)) ||
549 (count
!= 3 && tag
== nsGkAtoms::msubsup_
) || !baseFrame
||
550 (foundNoneTag
&& tag
!= nsGkAtoms::mmultiscripts_
) ||
551 (!isSubScript
&& tag
== nsGkAtoms::mmultiscripts_
)) {
552 // report an error, encourage people to get their markups in order
554 if ((count
!= 2 && (tag
== nsGkAtoms::msup_
||
555 tag
== nsGkAtoms::msub_
)) ||
556 (count
!= 3 && tag
== nsGkAtoms::msubsup_
)) {
557 aFrame
->ReportChildCountError();
558 } else if (foundNoneTag
&& tag
!= nsGkAtoms::mmultiscripts_
) {
559 aFrame
->ReportInvalidChildError(nsGkAtoms::none
);
560 } else if (!baseFrame
) {
561 aFrame
->ReportErrorToConsole("NoBase");
563 aFrame
->ReportErrorToConsole("SubSupMismatch");
566 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
569 // we left out the width of prescripts, so ...
570 boundingMetrics
.rightBearing
+= prescriptsWidth
;
571 boundingMetrics
.width
+= prescriptsWidth
;
573 // Zero out the shifts in where a frame isn't present to avoid the potential
576 maxSubScriptShift
= 0;
578 maxSupScriptShift
= 0;
580 // we left out the base during our bounding box updates, so ...
581 if (tag
== nsGkAtoms::msub_
) {
582 boundingMetrics
.ascent
= std::max(bmBase
.ascent
,
583 bmMultiSub
.ascent
- maxSubScriptShift
);
585 boundingMetrics
.ascent
=
586 std::max(bmBase
.ascent
, (bmMultiSup
.ascent
+ maxSupScriptShift
));
588 if (tag
== nsGkAtoms::msup_
) {
589 boundingMetrics
.descent
= std::max(bmBase
.descent
,
590 bmMultiSup
.descent
- maxSupScriptShift
);
592 boundingMetrics
.descent
=
593 std::max(bmBase
.descent
, (bmMultiSub
.descent
+ maxSubScriptShift
));
595 aFrame
->SetBoundingMetrics(boundingMetrics
);
597 // get the reflow metrics ...
598 aDesiredSize
.SetBlockStartAscent(
599 std::max(baseSize
.BlockStartAscent(),
600 std::max(multiSubSize
.BlockStartAscent() - maxSubScriptShift
,
601 multiSupSize
.BlockStartAscent() + maxSupScriptShift
)));
602 aDesiredSize
.Height() = aDesiredSize
.BlockStartAscent() +
603 std::max(baseSize
.Height() - baseSize
.BlockStartAscent(),
604 std::max(multiSubSize
.Height() + maxSubScriptShift
,
605 multiSupSize
.Height() - maxSupScriptShift
));
606 aDesiredSize
.Width() = boundingMetrics
.width
;
607 aDesiredSize
.mBoundingMetrics
= boundingMetrics
;
609 aFrame
->SetReference(nsPoint(0, aDesiredSize
.BlockStartAscent()));
614 // Place prescripts, followed by base, and then postscripts.
615 // The list of frames is in the order: {base} {postscripts} {prescripts}
616 // We go over the list in a circular manner, starting at <prescripts/>
619 nscoord dx
= 0, dy
= 0;
621 // With msub and msup there is only one element and
622 // subscriptFrame/supScriptFrame have already been set above where
623 // relevant. In these cases we skip to the reflow part.
624 if (tag
== nsGkAtoms::msub_
|| tag
== nsGkAtoms::msup_
)
628 childFrame
= prescriptsFrame
;
629 bool isPreScript
= true;
631 if (!childFrame
) { // end of prescripts,
633 // place the base ...
634 childFrame
= baseFrame
;
635 dy
= aDesiredSize
.BlockStartAscent() - baseSize
.BlockStartAscent();
636 FinishReflowChild (baseFrame
, aPresContext
, baseSize
, nullptr,
637 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
642 } else if (prescriptsFrame
== childFrame
) {
643 // Clear reflow flags of prescripts frame.
644 prescriptsFrame
->DidReflow(aPresContext
, nullptr);
646 // process each sup/sub pair
648 subScriptFrame
= childFrame
;
650 } else if (1 == count
) {
651 if (tag
!= nsGkAtoms::msub_
)
652 supScriptFrame
= childFrame
;
655 // get the ascent/descent of sup/subscripts stored in their rects
656 // rect.x = descent, rect.y = ascent
658 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
, bmSubScript
);
660 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
, bmSupScript
);
662 width
= std::max(subScriptSize
.Width(), supScriptSize
.Width());
664 if (subScriptFrame
) {
666 // prescripts should be right aligned
667 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
669 x
+= width
- subScriptSize
.Width();
670 dy
= aDesiredSize
.BlockStartAscent() - subScriptSize
.BlockStartAscent() +
672 FinishReflowChild (subScriptFrame
, aPresContext
, subScriptSize
,
674 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
675 subScriptSize
.Width(),
680 if (supScriptFrame
) {
683 x
+= width
- supScriptSize
.Width();
685 // post superscripts are shifted by the italic correction value
686 x
+= italicCorrection
;
688 dy
= aDesiredSize
.BlockStartAscent() - supScriptSize
.BlockStartAscent() -
690 FinishReflowChild (supScriptFrame
, aPresContext
, supScriptSize
,
692 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
693 supScriptSize
.Width(),
697 dx
+= width
+ scriptSpace
;
700 childFrame
= childFrame
->GetNextSibling();
701 } while (prescriptsFrame
!= childFrame
);