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"
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
22 NS_NewMathMLmmultiscriptsFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
24 return new (aPresShell
) nsMathMLmmultiscriptsFrame(aContext
);
27 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame
)
29 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
34 nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame
* aFrame
)
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
45 return 0; //not a child
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.
60 bool isSubScript
= !mContent
->IsMathMLElement(nsGkAtoms::msup_
);
62 nsAutoTArray
<nsIFrame
*, 8> subScriptFrames
;
63 nsIFrame
* childFrame
= mFrames
.FirstChild();
65 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
67 } else if (0 == count
) {
70 // super/subscript block
73 subScriptFrames
.AppendElement(childFrame
);
77 PropagateFrameFlagFor(childFrame
, NS_FRAME_MATHML_SCRIPT_DESCENDANT
);
78 isSubScript
= !isSubScript
;
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
);
92 /* virtual */ nsresult
93 nsMathMLmmultiscriptsFrame::Place(DrawTarget
* aDrawTarget
,
95 nsHTMLReflowMetrics
& aDesiredSize
)
97 nscoord subScriptShift
= 0;
98 nscoord supScriptShift
= 0;
99 float fontSizeInflation
= nsLayoutUtils::FontSizeInflationFor(this);
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."
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.
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
);
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."
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
,
143 // exported routine that both munderover and mmultiscripts share.
144 // munderover uses this when movablelimits is set.
146 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext
* aPresContext
,
147 DrawTarget
* aDrawTarget
,
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();
179 if (tag
== nsGkAtoms::mmultiscripts_
)
180 aFrame
->ReportErrorToConsole("NoBase");
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
),
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
200 mathFont
->GetMathConstant(gfxFontEntry::SpaceAfterScript
, oneDevPixel
);
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
;
215 // Try and get the sub script shift from the MATH table. Note that contrary
216 // to TeX we only have one parameter.
218 mathFont
->GetMathConstant(gfxFontEntry::SubscriptShiftDown
, oneDevPixel
);
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
;
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
);
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
,
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
;
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
);
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;
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();
327 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::mprescripts_
)) {
328 if (tag
!= nsGkAtoms::mmultiscripts_
) {
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
338 aFrame
->ReportErrorToConsole("DuplicateMprescripts");
340 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
344 aFrame
->ReportErrorToConsole("SubSupMismatch");
346 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
349 prescriptsFrame
= childFrame
;
350 firstPrescriptsPair
= true;
351 } else if (0 == count
) {
354 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::none
)) {
355 if (tag
== nsGkAtoms::mmultiscripts_
) {
357 aFrame
->ReportErrorToConsole("NoBase");
359 return aFrame
->ReflowError(aDrawTarget
, aDesiredSize
);
361 //A different error message is triggered later for the other tags
365 baseFrame
= childFrame
;
366 GetReflowAndBoundingMetricsFor(baseFrame
, baseSize
, bmBase
);
368 if (tag
!= nsGkAtoms::msub_
) {
369 // Apply italics correction if there is the potential for a
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
384 // super/subscript block
385 if (childFrame
->GetContent()->IsMathMLElement(nsGkAtoms::none
)) {
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
;
417 mathFont
->GetMathConstant(gfxFontEntry::SubscriptTopMax
,
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
;
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
;
440 superscriptBottomMin
=
441 mathFont
->GetMathConstant(gfxFontEntry::SuperscriptBottomMin
,
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
,
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
;
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
;
486 subSuperscriptGapMin
=
487 mathFont
->GetMathConstant(gfxFontEntry::SubSuperscriptGapMin
,
491 GetRuleThickness(aDrawTarget
, fm
, ruleSize
);
492 subSuperscriptGapMin
= 4 * ruleSize
;
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
;
506 superscriptBottomMaxWithSubscript
= mathFont
->
507 GetMathConstant(gfxFontEntry::SuperscriptBottomMaxWithSubscript
,
510 superscriptBottomMaxWithSubscript
=
511 NSToCoordRound((4.0f
/ 5.0f
) * xHeight
);
513 gap
= superscriptBottomMaxWithSubscript
-
514 (trySupScriptShift
- bmSupScript
.descent
);
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
;
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
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");
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
563 maxSubScriptShift
= 0;
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
);
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
);
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()));
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/>
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_
)
615 childFrame
= prescriptsFrame
;
616 bool isPreScript
= true;
618 if (!childFrame
) { // end of prescripts,
620 // place the base ...
621 childFrame
= baseFrame
;
622 dy
= aDesiredSize
.BlockStartAscent() - baseSize
.BlockStartAscent();
623 FinishReflowChild (baseFrame
, aPresContext
, baseSize
, nullptr,
624 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
629 } else if (prescriptsFrame
== childFrame
) {
630 // Clear reflow flags of prescripts frame.
631 prescriptsFrame
->DidReflow(aPresContext
, nullptr, nsDidReflowStatus::FINISHED
);
633 // process each sup/sub pair
635 subScriptFrame
= childFrame
;
637 } else if (1 == count
) {
638 if (tag
!= nsGkAtoms::msub_
)
639 supScriptFrame
= childFrame
;
642 // get the ascent/descent of sup/subscripts stored in their rects
643 // rect.x = descent, rect.y = ascent
645 GetReflowAndBoundingMetricsFor(subScriptFrame
, subScriptSize
, bmSubScript
);
647 GetReflowAndBoundingMetricsFor(supScriptFrame
, supScriptSize
, bmSupScript
);
649 width
= std::max(subScriptSize
.Width(), supScriptSize
.Width());
651 if (subScriptFrame
) {
653 // prescripts should be right aligned
654 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
656 x
+= width
- subScriptSize
.Width();
657 dy
= aDesiredSize
.BlockStartAscent() - subScriptSize
.BlockStartAscent() +
659 FinishReflowChild (subScriptFrame
, aPresContext
, subScriptSize
,
661 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
662 subScriptSize
.Width(),
667 if (supScriptFrame
) {
670 x
+= width
- supScriptSize
.Width();
672 // post superscripts are shifted by the italic correction value
673 x
+= italicCorrection
;
675 dy
= aDesiredSize
.BlockStartAscent() - supScriptSize
.BlockStartAscent() -
677 FinishReflowChild (supScriptFrame
, aPresContext
, supScriptSize
,
679 aFrame
->MirrorIfRTL(aDesiredSize
.Width(),
680 supScriptSize
.Width(),
684 dx
+= width
+ scriptSpace
;
687 childFrame
= childFrame
->GetNextSibling();
688 } while (prescriptsFrame
!= childFrame
);