layout/mathml/nsMathMLmmultiscriptsFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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 }

mercurial