Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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;
14 //
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
19 //
21 nsIFrame*
22 NS_NewMathMLmmultiscriptsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
23 {
24 return new (aPresShell) nsMathMLmmultiscriptsFrame(aContext);
25 }
27 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmmultiscriptsFrame)
29 nsMathMLmmultiscriptsFrame::~nsMathMLmmultiscriptsFrame()
30 {
31 }
33 uint8_t
34 nsMathMLmmultiscriptsFrame::ScriptIncrement(nsIFrame* aFrame)
35 {
36 if (!aFrame)
37 return 0;
38 if (mFrames.ContainsFrame(aFrame)) {
39 if (mFrames.FirstChild() == aFrame ||
40 aFrame->GetContent()->Tag() == nsGkAtoms::mprescripts_) {
41 return 0; // No script increment for base frames or prescript markers
42 }
43 return 1;
44 }
45 return 0; //not a child
46 }
48 NS_IMETHODIMP
49 nsMathMLmmultiscriptsFrame::TransmitAutomaticData()
50 {
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->Tag() != nsGkAtoms::msup_;
62 nsAutoTArray<nsIFrame*, 8> subScriptFrames;
63 nsIFrame* childFrame = mFrames.FirstChild();
64 while (childFrame) {
65 if (childFrame->GetContent()->Tag() == 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
76 }
77 PropagateFrameFlagFor(childFrame, NS_FRAME_MATHML_SCRIPT_DESCENDANT);
78 isSubScript = !isSubScript;
79 }
80 count++;
81 childFrame = childFrame->GetNextSibling();
82 }
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);
87 }
89 return NS_OK;
90 }
92 /* virtual */ nsresult
93 nsMathMLmmultiscriptsFrame::Place(nsRenderingContext& aRenderingContext,
94 bool aPlaceOrigin,
95 nsHTMLReflowMetrics& aDesiredSize)
96 {
97 nscoord subScriptShift = 0;
98 nscoord supScriptShift = 0;
99 nsIAtom* tag = mContent->Tag();
101 // subscriptshift
102 //
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."
105 //
106 // values: length
107 // default: automatic
108 //
109 // We use 0 as the default value so unitless values can be ignored.
110 // As a minimum, negative values can be ignored.
111 //
112 nsAutoString value;
113 if (tag != nsGkAtoms::msup_) {
114 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::subscriptshift_, value);
115 if (!value.IsEmpty()) {
116 ParseNumericValue(value, &subScriptShift, 0, PresContext(),
117 mStyleContext);
118 }
119 }
120 // superscriptshift
121 //
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."
124 //
125 // values: length
126 // default: automatic
127 //
128 // We use 0 as the default value so unitless values can be ignored.
129 // As a minimum, negative values can be ignored.
130 //
131 if (tag != nsGkAtoms::msub_) {
132 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::superscriptshift_, value);
133 if (!value.IsEmpty()) {
134 ParseNumericValue(value, &supScriptShift, 0, PresContext(),
135 mStyleContext);
136 }
137 }
138 // scriptspace from TeX for extra spacing after sup/subscript
139 // (0.5pt in plain TeX)
140 nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
142 return PlaceMultiScript(PresContext(), aRenderingContext, aPlaceOrigin,
143 aDesiredSize, this, subScriptShift, supScriptShift,
144 scriptSpace);
145 }
147 // exported routine that both munderover and mmultiscripts share.
148 // munderover uses this when movablelimits is set.
149 nsresult
150 nsMathMLmmultiscriptsFrame::PlaceMultiScript(nsPresContext* aPresContext,
151 nsRenderingContext& aRenderingContext,
152 bool aPlaceOrigin,
153 nsHTMLReflowMetrics& aDesiredSize,
154 nsMathMLContainerFrame* aFrame,
155 nscoord aUserSubScriptShift,
156 nscoord aUserSupScriptShift,
157 nscoord aScriptSpace)
158 {
159 nsIAtom* tag = aFrame->GetContent()->Tag();
161 // This function deals with both munderover etc. as well as msubsup etc.
162 // As the former behaves identically to the later, we treat it as such
163 // to avoid additional checks later.
164 if (tag == nsGkAtoms::mover_)
165 tag = nsGkAtoms::msup_;
166 else if (tag == nsGkAtoms::munder_)
167 tag = nsGkAtoms::msub_;
168 else if (tag == nsGkAtoms::munderover_)
169 tag = nsGkAtoms::msubsup_;
171 nsBoundingMetrics bmFrame;
173 nscoord minShiftFromXHeight, subDrop, supDrop;
175 ////////////////////////////////////////
176 // Initialize super/sub shifts that
177 // depend only on the current font
178 ////////////////////////////////////////
180 nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
182 if (!baseFrame) {
183 if (tag == nsGkAtoms::mmultiscripts_)
184 aFrame->ReportErrorToConsole("NoBase");
185 else
186 aFrame->ReportChildCountError();
187 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
188 }
191 // get x-height (an ex)
192 const nsStyleFont* font = aFrame->StyleFont();
193 nsRefPtr<nsFontMetrics> fm;
194 nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
195 aRenderingContext.SetFont(fm);
197 nscoord xHeight = fm->XHeight();
199 nscoord ruleSize;
200 GetRuleThickness (aRenderingContext, fm, ruleSize);
202 // force the scriptSpace to be at least 1 pixel
203 nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
204 aScriptSpace = std::max(onePixel, aScriptSpace);
206 /////////////////////////////////////
207 // first the shift for the subscript
209 // subScriptShift{1,2}
210 // = minimum amount to shift the subscript down
211 // = sub{1,2} in TeXbook
212 // subScriptShift1 = subscriptshift attribute * x-height
213 nscoord subScriptShift1, subScriptShift2;
215 // Get subScriptShift{1,2} default from font
216 GetSubScriptShifts (fm, subScriptShift1, subScriptShift2);
217 nscoord subScriptShift;
218 if (tag == nsGkAtoms::msub_) {
219 subScriptShift = subScriptShift1;
220 } else {
221 subScriptShift = std::max(subScriptShift1, subScriptShift2);
222 }
223 if (0 < aUserSubScriptShift) {
224 // the user has set the subscriptshift attribute
225 subScriptShift = std::max(subScriptShift, aUserSubScriptShift);
226 }
228 /////////////////////////////////////
229 // next the shift for the superscript
231 // supScriptShift{1,2,3}
232 // = minimum amount to shift the supscript up
233 // = sup{1,2,3} in TeX
234 // supScriptShift1 = superscriptshift attribute * x-height
235 // Note that there are THREE values for supscript shifts depending
236 // on the current style
237 nscoord supScriptShift1, supScriptShift2, supScriptShift3;
238 // Set supScriptShift{1,2,3} default from font
239 GetSupScriptShifts (fm, supScriptShift1, supScriptShift2, supScriptShift3);
241 // get sup script shift depending on current script level and display style
242 // Rule 18c, App. G, TeXbook
243 nsPresentationData presentationData;
244 aFrame->GetPresentationData(presentationData);
245 nscoord supScriptShift;
246 if (font->mScriptLevel == 0 &&
247 font->mMathDisplay == NS_MATHML_DISPLAYSTYLE_BLOCK &&
248 !NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
249 // Style D in TeXbook
250 supScriptShift = supScriptShift1;
251 } else if (NS_MATHML_IS_COMPRESSED(presentationData.flags)) {
252 // Style C' in TeXbook = D',T',S',SS'
253 supScriptShift = supScriptShift3;
254 } else {
255 // everything else = T,S,SS
256 supScriptShift = supScriptShift2;
257 }
259 if (0 < aUserSupScriptShift) {
260 // the user has set the supscriptshift attribute
261 supScriptShift = std::max(supScriptShift, aUserSupScriptShift);
262 }
264 ////////////////////////////////////
265 // Get the children's sizes
266 ////////////////////////////////////
268 const WritingMode wm(aDesiredSize.GetWritingMode());
269 nscoord width = 0, prescriptsWidth = 0, rightBearing = 0;
270 nscoord minSubScriptShift = 0, minSupScriptShift = 0;
271 nscoord trySubScriptShift = subScriptShift;
272 nscoord trySupScriptShift = supScriptShift;
273 nscoord maxSubScriptShift = subScriptShift;
274 nscoord maxSupScriptShift = supScriptShift;
275 nsHTMLReflowMetrics baseSize(wm);
276 nsHTMLReflowMetrics subScriptSize(wm);
277 nsHTMLReflowMetrics supScriptSize(wm);
278 nsHTMLReflowMetrics multiSubSize(wm), multiSupSize(wm);
279 baseFrame = nullptr;
280 nsIFrame* subScriptFrame = nullptr;
281 nsIFrame* supScriptFrame = nullptr;
282 nsIFrame* prescriptsFrame = nullptr; // frame of <mprescripts/>, if there.
284 bool firstPrescriptsPair = false;
285 nsBoundingMetrics bmBase, bmSubScript, bmSupScript, bmMultiSub, bmMultiSup;
286 multiSubSize.SetTopAscent(-0x7FFFFFFF);
287 multiSupSize.SetTopAscent(-0x7FFFFFFF);
288 bmMultiSub.ascent = bmMultiSup.ascent = -0x7FFFFFFF;
289 bmMultiSub.descent = bmMultiSup.descent = -0x7FFFFFFF;
290 nscoord italicCorrection = 0;
292 nsBoundingMetrics boundingMetrics;
293 boundingMetrics.width = 0;
294 boundingMetrics.ascent = boundingMetrics.descent = -0x7FFFFFFF;
295 aDesiredSize.Width() = aDesiredSize.Height() = 0;
297 int32_t count = 0;
298 bool foundNoneTag = false;
300 // Boolean to determine whether the current child is a subscript.
301 // Note that only msup starts with a superscript.
302 bool isSubScript = (tag != nsGkAtoms::msup_);
304 nsIFrame* childFrame = aFrame->GetFirstPrincipalChild();
305 while (childFrame) {
306 nsIAtom* childTag = childFrame->GetContent()->Tag();
307 if (childTag == nsGkAtoms::mprescripts_) {
308 if (tag != nsGkAtoms::mmultiscripts_) {
309 if (aPlaceOrigin) {
310 aFrame->ReportInvalidChildError(childTag);
311 }
312 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
313 }
314 if (prescriptsFrame) {
315 // duplicate <mprescripts/> found
316 // report an error, encourage people to get their markups in order
317 if (aPlaceOrigin) {
318 aFrame->ReportErrorToConsole("DuplicateMprescripts");
319 }
320 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
321 }
322 if (!isSubScript) {
323 if (aPlaceOrigin) {
324 aFrame->ReportErrorToConsole("SubSupMismatch");
325 }
326 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
327 }
329 prescriptsFrame = childFrame;
330 firstPrescriptsPair = true;
331 } else if (0 == count) {
332 // base
334 if (childTag == nsGkAtoms::none) {
335 if (tag == nsGkAtoms::mmultiscripts_) {
336 if (aPlaceOrigin) {
337 aFrame->ReportErrorToConsole("NoBase");
338 }
339 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
340 } else {
341 //A different error message is triggered later for the other tags
342 foundNoneTag = true;
343 }
344 }
345 baseFrame = childFrame;
346 GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
348 if (tag != nsGkAtoms::msub_) {
349 // Apply italics correction if there is the potential for a
350 // postsupscript.
351 GetItalicCorrection(bmBase, italicCorrection);
352 // If italics correction is applied, we always add "a little to spare"
353 // (see TeXbook Ch.11, p.64), as we estimate the italic creation
354 // ourselves and it isn't the same as TeX.
355 italicCorrection += onePixel;
356 }
358 // we update boundingMetrics.{ascent,descent} with that
359 // of the baseFrame only after processing all the sup/sub pairs
360 boundingMetrics.width = bmBase.width;
361 boundingMetrics.rightBearing = bmBase.rightBearing;
362 boundingMetrics.leftBearing = bmBase.leftBearing; // until overwritten
363 } else {
364 // super/subscript block
365 if ( childTag == nsGkAtoms::none) {
366 foundNoneTag = true;
367 }
369 if (isSubScript) {
370 // subscript
371 subScriptFrame = childFrame;
372 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
373 // get the subdrop from the subscript font
374 GetSubDropFromChild (subScriptFrame, subDrop);
375 // parameter v, Rule 18a, App. G, TeXbook
376 minSubScriptShift = bmBase.descent + subDrop;
377 trySubScriptShift = std::max(minSubScriptShift,subScriptShift);
378 multiSubSize.SetTopAscent(std::max(multiSubSize.TopAscent(),
379 subScriptSize.TopAscent()));
380 bmMultiSub.ascent = std::max(bmMultiSub.ascent, bmSubScript.ascent);
381 bmMultiSub.descent = std::max(bmMultiSub.descent, bmSubScript.descent);
382 multiSubSize.Height() =
383 std::max(multiSubSize.Height(),
384 subScriptSize.Height() - subScriptSize.TopAscent());
385 if (bmSubScript.width)
386 width = bmSubScript.width + aScriptSpace;
387 rightBearing = bmSubScript.rightBearing;
389 if (tag == nsGkAtoms::msub_) {
390 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
391 boundingMetrics.width += width;
393 // get min subscript shift limit from x-height
394 // = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
395 nscoord minShiftFromXHeight = (nscoord)
396 (bmSubScript.ascent - (4.0f/5.0f) * xHeight);
397 maxSubScriptShift = std::max(trySubScriptShift,minShiftFromXHeight);
399 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
400 trySubScriptShift = subScriptShift;
401 }
402 } else {
403 // supscript
404 supScriptFrame = childFrame;
405 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
406 // get the supdrop from the supscript font
407 GetSupDropFromChild (supScriptFrame, supDrop);
408 // parameter u, Rule 18a, App. G, TeXbook
409 minSupScriptShift = bmBase.ascent - supDrop;
410 // get min supscript shift limit from x-height
411 // = d(x) + 1/4 * sigma_5, Rule 18c, App. G, TeXbook
412 minShiftFromXHeight = NSToCoordRound
413 ((bmSupScript.descent + (1.0f/4.0f) * xHeight));
414 trySupScriptShift = std::max(minSupScriptShift,
415 std::max(minShiftFromXHeight,
416 supScriptShift));
417 multiSupSize.SetTopAscent(std::max(multiSupSize.TopAscent(),
418 supScriptSize.TopAscent()));
419 bmMultiSup.ascent = std::max(bmMultiSup.ascent, bmSupScript.ascent);
420 bmMultiSup.descent = std::max(bmMultiSup.descent, bmSupScript.descent);
421 multiSupSize.Height() =
422 std::max(multiSupSize.Height(),
423 supScriptSize.Height() - supScriptSize.TopAscent());
425 if (bmSupScript.width)
426 width = std::max(width, bmSupScript.width + aScriptSpace);
428 if (!prescriptsFrame) { // we are still looping over base & postscripts
429 rightBearing = std::max(rightBearing,
430 italicCorrection + bmSupScript.rightBearing);
431 boundingMetrics.rightBearing = boundingMetrics.width + rightBearing;
432 boundingMetrics.width += width;
433 } else {
434 prescriptsWidth += width;
435 if (firstPrescriptsPair) {
436 firstPrescriptsPair = false;
437 boundingMetrics.leftBearing =
438 std::min(bmSubScript.leftBearing, bmSupScript.leftBearing);
439 }
440 }
441 width = rightBearing = 0;
443 // negotiate between the various shifts so that
444 // there is enough gap between the sup and subscripts
445 // Rule 18e, App. G, TeXbook
446 if (tag == nsGkAtoms::mmultiscripts_ ||
447 tag == nsGkAtoms::msubsup_) {
448 nscoord gap =
449 (trySupScriptShift - bmSupScript.descent) -
450 (bmSubScript.ascent - trySubScriptShift);
451 if (gap < 4.0f * ruleSize) {
452 // adjust trySubScriptShift to get a gap of (4.0 * ruleSize)
453 trySubScriptShift += NSToCoordRound ((4.0f * ruleSize) - gap);
454 }
456 // next we want to ensure that the bottom of the superscript
457 // will be > (4/5) * x-height above baseline
458 gap = NSToCoordRound ((4.0f/5.0f) * xHeight -
459 (trySupScriptShift - bmSupScript.descent));
460 if (gap > 0) {
461 trySupScriptShift += gap;
462 trySubScriptShift -= gap;
463 }
464 }
466 maxSubScriptShift = std::max(maxSubScriptShift, trySubScriptShift);
467 maxSupScriptShift = std::max(maxSupScriptShift, trySupScriptShift);
469 trySubScriptShift = subScriptShift;
470 trySupScriptShift = supScriptShift;
471 }
473 isSubScript = !isSubScript;
474 }
475 count++;
476 childFrame = childFrame->GetNextSibling();
477 }
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 (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) ||
483 (!isSubScript && tag == nsGkAtoms::mmultiscripts_)) {
484 // report an error, encourage people to get their markups in order
485 if (aPlaceOrigin) {
486 if ((count != 2 && (tag == nsGkAtoms::msup_ ||
487 tag == nsGkAtoms::msub_)) ||
488 (count != 3 && tag == nsGkAtoms::msubsup_ )) {
489 aFrame->ReportChildCountError();
490 } else if (foundNoneTag && tag != nsGkAtoms::mmultiscripts_) {
491 aFrame->ReportInvalidChildError(nsGkAtoms::none);
492 } else if (!baseFrame) {
493 aFrame->ReportErrorToConsole("NoBase");
494 } else {
495 aFrame->ReportErrorToConsole("SubSupMismatch");
496 }
497 }
498 return aFrame->ReflowError(aRenderingContext, aDesiredSize);
499 }
501 // we left out the width of prescripts, so ...
502 boundingMetrics.rightBearing += prescriptsWidth;
503 boundingMetrics.width += prescriptsWidth;
505 // Zero out the shifts in where a frame isn't present to avoid the potential
506 // for overflow.
507 if (!subScriptFrame)
508 maxSubScriptShift = 0;
509 if (!supScriptFrame)
510 maxSupScriptShift = 0;
512 // we left out the base during our bounding box updates, so ...
513 if (tag == nsGkAtoms::msub_) {
514 boundingMetrics.ascent = std::max(bmBase.ascent,
515 bmMultiSub.ascent - maxSubScriptShift);
516 } else {
517 boundingMetrics.ascent =
518 std::max(bmBase.ascent, (bmMultiSup.ascent + maxSupScriptShift));
519 }
520 if (tag == nsGkAtoms::msup_) {
521 boundingMetrics.descent = std::max(bmBase.descent,
522 bmMultiSup.descent - maxSupScriptShift);
523 } else {
524 boundingMetrics.descent =
525 std::max(bmBase.descent, (bmMultiSub.descent + maxSubScriptShift));
526 }
527 aFrame->SetBoundingMetrics(boundingMetrics);
529 // get the reflow metrics ...
530 aDesiredSize.SetTopAscent(
531 std::max(baseSize.TopAscent(),
532 std::max(multiSubSize.TopAscent() - maxSubScriptShift,
533 multiSupSize.TopAscent() + maxSupScriptShift)));
534 aDesiredSize.Height() = aDesiredSize.TopAscent() +
535 std::max(baseSize.Height() - baseSize.TopAscent(),
536 std::max(multiSubSize.Height() + maxSubScriptShift,
537 multiSupSize.Height() - maxSupScriptShift));
538 aDesiredSize.Width() = boundingMetrics.width;
539 aDesiredSize.mBoundingMetrics = boundingMetrics;
541 aFrame->SetReference(nsPoint(0, aDesiredSize.TopAscent()));
543 //////////////////
544 // Place Children
546 // Place prescripts, followed by base, and then postscripts.
547 // The list of frames is in the order: {base} {postscripts} {prescripts}
548 // We go over the list in a circular manner, starting at <prescripts/>
550 if (aPlaceOrigin) {
551 nscoord dx = 0, dy = 0;
553 // With msub and msup there is only one element and
554 // subscriptFrame/supScriptFrame have already been set above where
555 // relevant. In these cases we skip to the reflow part.
556 if (tag == nsGkAtoms::msub_ || tag == nsGkAtoms::msup_)
557 count = 1;
558 else
559 count = 0;
560 childFrame = prescriptsFrame;
561 bool isPreScript = true;
562 do {
563 if (!childFrame) { // end of prescripts,
564 isPreScript = false;
565 // place the base ...
566 childFrame = baseFrame;
567 dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
568 FinishReflowChild (baseFrame, aPresContext, baseSize, nullptr,
569 aFrame->MirrorIfRTL(aDesiredSize.Width(),
570 baseSize.Width(),
571 dx),
572 dy, 0);
573 dx += bmBase.width;
574 } else if (prescriptsFrame == childFrame) {
575 // Clear reflow flags of prescripts frame.
576 prescriptsFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
577 } else {
578 // process each sup/sub pair
579 if (0 == count) {
580 subScriptFrame = childFrame;
581 count = 1;
582 } else if (1 == count) {
583 if (tag != nsGkAtoms::msub_)
584 supScriptFrame = childFrame;
585 count = 0;
587 // get the ascent/descent of sup/subscripts stored in their rects
588 // rect.x = descent, rect.y = ascent
589 if (subScriptFrame)
590 GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
591 if (supScriptFrame)
592 GetReflowAndBoundingMetricsFor(supScriptFrame, supScriptSize, bmSupScript);
594 width = std::max(subScriptSize.Width(), supScriptSize.Width());
596 if (subScriptFrame) {
597 nscoord x = dx;
598 // prescripts should be right aligned
599 // https://bugzilla.mozilla.org/show_bug.cgi?id=928675
600 if (isPreScript)
601 x += width - subScriptSize.Width();
602 dy = aDesiredSize.TopAscent() - subScriptSize.TopAscent() +
603 maxSubScriptShift;
604 FinishReflowChild (subScriptFrame, aPresContext, subScriptSize,
605 nullptr,
606 aFrame->MirrorIfRTL(aDesiredSize.Width(),
607 subScriptSize.Width(),
608 x),
609 dy, 0);
610 }
612 if (supScriptFrame) {
613 nscoord x = dx;
614 if (isPreScript) {
615 x += width - supScriptSize.Width();
616 } else {
617 // post superscripts are shifted by the italic correction value
618 x += italicCorrection;
619 }
620 dy = aDesiredSize.TopAscent() - supScriptSize.TopAscent() -
621 maxSupScriptShift;
622 FinishReflowChild (supScriptFrame, aPresContext, supScriptSize,
623 nullptr,
624 aFrame->MirrorIfRTL(aDesiredSize.Width(),
625 supScriptSize.Width(),
626 x),
627 dy, 0);
628 }
629 dx += width + aScriptSpace;
630 }
631 }
632 childFrame = childFrame->GetNextSibling();
633 } while (prescriptsFrame != childFrame);
634 }
636 return NS_OK;
637 }