layout/mathml/nsMathMLmunderoverFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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/. */
     6 #include "nsMathMLmunderoverFrame.h"
     7 #include "nsPresContext.h"
     8 #include "nsRenderingContext.h"
     9 #include "nsMathMLmmultiscriptsFrame.h"
    10 #include <algorithm>
    12 //
    13 // <munderover> -- attach an underscript-overscript pair to a base - implementation
    14 // <mover> -- attach an overscript to a base - implementation
    15 // <munder> -- attach an underscript to a base - implementation
    16 //
    18 nsIFrame*
    19 NS_NewMathMLmunderoverFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    20 {
    21   return new (aPresShell) nsMathMLmunderoverFrame(aContext);
    22 }
    24 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmunderoverFrame)
    26 nsMathMLmunderoverFrame::~nsMathMLmunderoverFrame()
    27 {
    28 }
    30 nsresult
    31 nsMathMLmunderoverFrame::AttributeChanged(int32_t         aNameSpaceID,
    32                                           nsIAtom*        aAttribute,
    33                                           int32_t         aModType)
    34 {
    35   if (nsGkAtoms::accent_ == aAttribute ||
    36       nsGkAtoms::accentunder_ == aAttribute) {
    37     // When we have automatic data to update within ourselves, we ask our
    38     // parent to re-layout its children
    39     return ReLayoutChildren(mParent);
    40   }
    42   return nsMathMLContainerFrame::
    43          AttributeChanged(aNameSpaceID, aAttribute, aModType);
    44 }
    46 NS_IMETHODIMP
    47 nsMathMLmunderoverFrame::UpdatePresentationData(uint32_t        aFlagsValues,
    48                                                 uint32_t        aFlagsToUpdate)
    49 {
    50   nsMathMLContainerFrame::UpdatePresentationData(aFlagsValues, aFlagsToUpdate);
    51   // disable the stretch-all flag if we are going to act like a subscript-superscript pair
    52   if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
    53       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
    54     mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
    55   }
    56   else {
    57     mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
    58   }
    59   return NS_OK;
    60 }
    62 NS_IMETHODIMP
    63 nsMathMLmunderoverFrame::InheritAutomaticData(nsIFrame* aParent)
    64 {
    65   // let the base class get the default from our parent
    66   nsMathMLContainerFrame::InheritAutomaticData(aParent);
    68   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
    70   return NS_OK;
    71 }
    73 uint8_t
    74 nsMathMLmunderoverFrame::ScriptIncrement(nsIFrame* aFrame)
    75 {
    76   nsIFrame* child = mFrames.FirstChild();
    77   if (!aFrame || aFrame == child) {
    78     return 0;
    79   }
    80   child = child->GetNextSibling();
    81   if (aFrame == child) {
    82     if (mContent->Tag() == nsGkAtoms::mover_) {
    83       return mIncrementOver ? 1 : 0;
    84     }
    85     return mIncrementUnder ? 1 : 0;
    86   }
    87   if (child && aFrame == child->GetNextSibling()) {
    88     // must be a over frame of munderover
    89     return mIncrementOver ? 1 : 0;
    90   }
    91   return 0;  // frame not found
    92 }
    94 NS_IMETHODIMP
    95 nsMathMLmunderoverFrame::TransmitAutomaticData()
    96 {
    97   // At this stage, all our children are in sync and we can fully
    98   // resolve our own mEmbellishData struct
    99   //---------------------------------------------------------------------
   101   /* 
   102   The REC says:
   104   As regards munder (respectively mover) :
   105   The default value of accentunder is false, unless underscript
   106   is an <mo> element or an embellished operator.  If underscript is 
   107   an <mo> element, the value of its accent attribute is used as the
   108   default value of accentunder. If underscript is an embellished
   109   operator, the accent attribute of the <mo> element at its
   110   core is used as the default value. As with all attributes, an
   111   explicitly given value overrides the default.
   113 XXX The winner is the outermost setting in conflicting settings like these:
   114 <munder accentunder='true'>
   115   <mi>...</mi>
   116   <mo accentunder='false'> ... </mo>
   117 </munder>
   119   As regards munderover:
   120   The accent and accentunder attributes have the same effect as
   121   the attributes with the same names on <mover>  and <munder>, 
   122   respectively. Their default values are also computed in the 
   123   same manner as described for those elements, with the default
   124   value of accent depending on overscript and the default value
   125   of accentunder depending on underscript.
   126   */
   128   nsIFrame* overscriptFrame = nullptr;
   129   nsIFrame* underscriptFrame = nullptr;
   130   nsIFrame* baseFrame = mFrames.FirstChild();
   131   nsIAtom* tag = mContent->Tag();
   133   if (baseFrame) {
   134     if (tag == nsGkAtoms::munder_ ||
   135         tag == nsGkAtoms::munderover_) {
   136       underscriptFrame = baseFrame->GetNextSibling();
   137     } else {
   138       NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
   139       overscriptFrame = baseFrame->GetNextSibling();
   140     }
   141   }
   142   if (underscriptFrame &&
   143       tag == nsGkAtoms::munderover_) {
   144     overscriptFrame = underscriptFrame->GetNextSibling();
   146   }
   148   // if our base is an embellished operator, let its state bubble to us (in particular,
   149   // this is where we get the flag for NS_MATHML_EMBELLISH_MOVABLELIMITS). Our flags
   150   // are reset to the default values of false if the base frame isn't embellished.
   151   mPresentationData.baseFrame = baseFrame;
   152   GetEmbellishDataFrom(baseFrame, mEmbellishData);
   154   // The default value of accentunder is false, unless the underscript is embellished
   155   // and its core <mo> is an accent
   156   nsEmbellishData embellishData;
   157   nsAutoString value;
   158   if (tag == nsGkAtoms::munder_ ||
   159       tag == nsGkAtoms::munderover_) {
   160     GetEmbellishDataFrom(underscriptFrame, embellishData);
   161     if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
   162       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
   163     } else {
   164       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
   165     }    
   167     // if we have an accentunder attribute, it overrides what the underscript said
   168     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accentunder_, value)) {
   169       if (value.EqualsLiteral("true")) {
   170         mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
   171       } else if (value.EqualsLiteral("false")) {
   172         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
   173       }
   174     }
   175   }
   177   // The default value of accent is false, unless the overscript is embellished
   178   // and its core <mo> is an accent
   179   if (tag == nsGkAtoms::mover_ ||
   180       tag == nsGkAtoms::munderover_) {
   181     GetEmbellishDataFrom(overscriptFrame, embellishData);
   182     if (NS_MATHML_EMBELLISH_IS_ACCENT(embellishData.flags)) {
   183       mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
   184     } else {
   185       mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
   186     }
   188     // if we have an accent attribute, it overrides what the overscript said
   189     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value)) {
   190       if (value.EqualsLiteral("true")) {
   191         mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
   192       } else if (value.EqualsLiteral("false")) {
   193         mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
   194       }
   195     }
   196   }
   198   bool subsupDisplay =
   199     NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
   200     StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE;
   202   // disable the stretch-all flag if we are going to act like a superscript
   203   if (subsupDisplay) {
   204     mPresentationData.flags &= ~NS_MATHML_STRETCH_ALL_CHILDREN_HORIZONTALLY;
   205   }
   207   // Now transmit any change that we want to our children so that they
   208   // can update their mPresentationData structs
   209   //---------------------------------------------------------------------
   211   /* The REC says:
   212      Within underscript, <munderover> always sets displaystyle to "false",
   213      but increments scriptlevel by 1 only when accentunder is "false". 
   215      Within overscript, <munderover> always sets displaystyle to "false", 
   216      but increments scriptlevel by 1 only when accent is "false".
   218      Within subscript and superscript it increments scriptlevel by 1, and 
   219      sets displaystyle to "false", but leaves both attributes unchanged within 
   220      base.
   222      The TeXBook treats 'over' like a superscript, so p.141 or Rule 13a
   223      say it shouldn't be compressed. However, The TeXBook says
   224      that math accents and \overline change uncramped styles to their
   225      cramped counterparts.
   226   */
   227   if (tag == nsGkAtoms::mover_ ||
   228       tag == nsGkAtoms::munderover_) {
   229     uint32_t compress = NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)
   230       ? NS_MATHML_COMPRESSED : 0;
   231     mIncrementOver =
   232       !NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags) ||
   233       subsupDisplay;
   234     SetIncrementScriptLevel(tag == nsGkAtoms::mover_ ? 1 : 2, mIncrementOver);
   235     if (mIncrementOver) {
   236       PropagateFrameFlagFor(overscriptFrame,
   237                             NS_FRAME_MATHML_SCRIPT_DESCENDANT);
   238     }
   239     PropagatePresentationDataFor(overscriptFrame, compress, compress);
   240   }
   241   /*
   242      The TeXBook treats 'under' like a subscript, so p.141 or Rule 13a 
   243      say it should be compressed
   244   */
   245   if (tag == nsGkAtoms::munder_ ||
   246       tag == nsGkAtoms::munderover_) {
   247     mIncrementUnder =
   248       !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags) ||
   249       subsupDisplay;
   250     SetIncrementScriptLevel(1, mIncrementUnder);
   251     if (mIncrementUnder) {
   252       PropagateFrameFlagFor(underscriptFrame,
   253                             NS_FRAME_MATHML_SCRIPT_DESCENDANT);
   254     }
   255     PropagatePresentationDataFor(underscriptFrame,
   256                                  NS_MATHML_COMPRESSED,
   257                                  NS_MATHML_COMPRESSED);
   258   }
   259   return NS_OK;
   260 }
   262 /*
   263 The REC says:
   264 *  If the base is an operator with movablelimits="true" (or an embellished
   265    operator whose <mo> element core has movablelimits="true"), and
   266    displaystyle="false", then underscript and overscript are drawn in
   267    a subscript and superscript position, respectively. In this case, 
   268    the accent and accentunder attributes are ignored. This is often
   269    used for limits on symbols such as &sum;.
   271 i.e.,:
   272  if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishDataflags) &&
   273      StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
   274   // place like subscript-superscript pair
   275  }
   276  else {
   277   // place like underscript-overscript pair
   278  }
   279 */
   281 /* virtual */ nsresult
   282 nsMathMLmunderoverFrame::Place(nsRenderingContext& aRenderingContext,
   283                                bool                 aPlaceOrigin,
   284                                nsHTMLReflowMetrics& aDesiredSize)
   285 {
   286   nsIAtom* tag = mContent->Tag();
   287   if (NS_MATHML_EMBELLISH_IS_MOVABLELIMITS(mEmbellishData.flags) &&
   288       StyleFont()->mMathDisplay == NS_MATHML_DISPLAYSTYLE_INLINE) {
   289     //place like sub sup or subsup
   290     nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f);
   291     if (tag == nsGkAtoms::munderover_) {
   292       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
   293                                                           aRenderingContext,
   294                                                           aPlaceOrigin,
   295                                                           aDesiredSize,
   296                                                           this, 0, 0,
   297                                                           scriptSpace);
   298     } else if (tag == nsGkAtoms::munder_) {
   299       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
   300                                                           aRenderingContext,
   301                                                           aPlaceOrigin,
   302                                                           aDesiredSize,
   303                                                           this, 0, 0,
   304                                                           scriptSpace);
   305     } else {
   306       NS_ASSERTION(tag == nsGkAtoms::mover_, "mContent->Tag() not recognized");
   307       return nsMathMLmmultiscriptsFrame::PlaceMultiScript(PresContext(),
   308                                                           aRenderingContext,
   309                                                           aPlaceOrigin,
   310                                                           aDesiredSize,
   311                                                           this, 0, 0,
   312                                                           scriptSpace);
   313     }
   315   }
   317   ////////////////////////////////////
   318   // Get the children's desired sizes
   320   nsBoundingMetrics bmBase, bmUnder, bmOver;
   321   nsHTMLReflowMetrics baseSize(aDesiredSize.GetWritingMode());
   322   nsHTMLReflowMetrics underSize(aDesiredSize.GetWritingMode());
   323   nsHTMLReflowMetrics overSize(aDesiredSize.GetWritingMode());
   324   nsIFrame* overFrame = nullptr;
   325   nsIFrame* underFrame = nullptr;
   326   nsIFrame* baseFrame = mFrames.FirstChild();
   327   underSize.SetTopAscent(0);
   328   overSize.SetTopAscent(0);
   329   bool haveError = false;
   330   if (baseFrame) {
   331     if (tag == nsGkAtoms::munder_ ||
   332         tag == nsGkAtoms::munderover_) {
   333       underFrame = baseFrame->GetNextSibling();
   334     } else if (tag == nsGkAtoms::mover_) {
   335       overFrame = baseFrame->GetNextSibling();
   336     }
   337   }
   338   if (underFrame && tag == nsGkAtoms::munderover_) {
   339     overFrame = underFrame->GetNextSibling();
   340   }
   342   if (tag == nsGkAtoms::munder_) {
   343     if (!baseFrame || !underFrame || underFrame->GetNextSibling()) {
   344       // report an error, encourage people to get their markups in order
   345       haveError = true;
   346     }
   347   }
   348   if (tag == nsGkAtoms::mover_) {
   349     if (!baseFrame || !overFrame || overFrame->GetNextSibling()) {
   350       // report an error, encourage people to get their markups in order
   351       haveError = true;
   352     }
   353   }
   354   if (tag == nsGkAtoms::munderover_) {
   355     if (!baseFrame || !underFrame || !overFrame || overFrame->GetNextSibling()) {
   356       // report an error, encourage people to get their markups in order
   357       haveError = true;
   358     }
   359   }
   360   if (haveError) {
   361     if (aPlaceOrigin) {
   362       ReportChildCountError();
   363     } 
   364     return ReflowError(aRenderingContext, aDesiredSize);
   365   }
   366   GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
   367   if (underFrame) {
   368     GetReflowAndBoundingMetricsFor(underFrame, underSize, bmUnder);
   369   }
   370   if (overFrame) {
   371     GetReflowAndBoundingMetricsFor(overFrame, overSize, bmOver);
   372   }
   374   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   376   ////////////////////
   377   // Place Children
   379   nsRefPtr<nsFontMetrics> fm;
   380   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
   381   aRenderingContext.SetFont(fm);
   383   nscoord xHeight = fm->XHeight();
   385   nscoord ruleThickness;
   386   GetRuleThickness (aRenderingContext, fm, ruleThickness);
   388   nscoord correction = 0;
   389   GetItalicCorrection (bmBase, correction);
   391   // there are 2 different types of placement depending on 
   392   // whether we want an accented under or not
   394   nscoord underDelta1 = 0; // gap between base and underscript
   395   nscoord underDelta2 = 0; // extra space beneath underscript
   397   if (!NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
   398     // Rule 13a, App. G, TeXbook
   399     nscoord bigOpSpacing2, bigOpSpacing4, bigOpSpacing5, dummy; 
   400     GetBigOpSpacings (fm, 
   401                       dummy, bigOpSpacing2, 
   402                       dummy, bigOpSpacing4, 
   403                       bigOpSpacing5);
   404     underDelta1 = std::max(bigOpSpacing2, (bigOpSpacing4 - bmUnder.ascent));
   405     underDelta2 = bigOpSpacing5;
   406   }
   407   else {
   408     // No corresponding rule in TeXbook - we are on our own here
   409     // XXX tune the gap delta between base and underscript 
   411     // Should we use Rule 10 like \underline does?
   412     underDelta1 = ruleThickness + onePixel/2;
   413     underDelta2 = ruleThickness;
   414   }
   415   // empty under?
   416   if (!(bmUnder.ascent + bmUnder.descent)) {
   417     underDelta1 = 0;
   418     underDelta2 = 0;
   419   }
   421   nscoord overDelta1 = 0; // gap between base and overscript
   422   nscoord overDelta2 = 0; // extra space above overscript
   424   if (!NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {    
   425     // Rule 13a, App. G, TeXbook
   426     nscoord bigOpSpacing1, bigOpSpacing3, bigOpSpacing5, dummy; 
   427     GetBigOpSpacings (fm, 
   428                       bigOpSpacing1, dummy, 
   429                       bigOpSpacing3, dummy, 
   430                       bigOpSpacing5);
   431     overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - bmOver.descent));
   432     overDelta2 = bigOpSpacing5;
   434     // XXX This is not a TeX rule... 
   435     // delta1 (as computed abvove) can become really big when bmOver.descent is
   436     // negative,  e.g., if the content is &OverBar. In such case, we use the height
   437     if (bmOver.descent < 0)    
   438       overDelta1 = std::max(bigOpSpacing1, (bigOpSpacing3 - (bmOver.ascent + bmOver.descent)));
   439   }
   440   else {
   441     // Rule 12, App. G, TeXbook
   442     // We are going to modify this rule to make it more general.
   443     // The idea behind Rule 12 in the TeXBook is to keep the accent
   444     // as close to the base as possible, while ensuring that the
   445     // distance between the *baseline* of the accent char and 
   446     // the *baseline* of the base is atleast x-height. 
   447     // The idea is that for normal use, we would like all the accents
   448     // on a line to line up atleast x-height above the baseline 
   449     // if possible. 
   450     // When the ascent of the base is >= x-height, 
   451     // the baseline of the accent char is placed just above the base
   452     // (specifically, the baseline of the accent char is placed 
   453     // above the baseline of the base by the ascent of the base).
   454     // For ease of implementation, 
   455     // this assumes that the font-designer designs accents 
   456     // in such a way that the bottom of the accent is atleast x-height
   457     // above its baseline, otherwise there will be collisions
   458     // with the base. Also there should be proper padding between
   459     // the bottom of the accent char and its baseline.
   460     // The above rule may not be obvious from a first
   461     // reading of rule 12 in the TeXBook !!!
   462     // The mathml <mover> tag can use accent chars that
   463     // do not follow this convention. So we modify TeX's rule 
   464     // so that TeX's rule gets subsumed for accents that follow 
   465     // TeX's convention,
   466     // while also allowing accents that do not follow the convention :
   467     // we try to keep the *bottom* of the accent char atleast x-height 
   468     // from the baseline of the base char. we also slap on an extra
   469     // padding between the accent and base chars.
   470     overDelta1 = ruleThickness + onePixel/2;
   471     if (bmBase.ascent < xHeight) {
   472       // also ensure at least x-height above the baseline of the base
   473       overDelta1 += xHeight - bmBase.ascent;
   474     }
   475     overDelta2 = ruleThickness;
   476   }
   477   // empty over?
   478   if (!(bmOver.ascent + bmOver.descent)) {
   479     overDelta1 = 0;
   480     overDelta2 = 0;
   481   }
   483   nscoord dxBase = 0, dxOver = 0, dxUnder = 0;
   484   nsAutoString valueAlign;
   485   enum {
   486     center,
   487     left,
   488     right
   489   } alignPosition = center;
   491   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, valueAlign)) {
   492     if (valueAlign.EqualsLiteral("left")) {
   493       alignPosition = left;
   494     } else if (valueAlign.EqualsLiteral("right")) {
   495       alignPosition = right;
   496     }
   497   }
   499   //////////
   500   // pass 1, do what <mover> does: attach the overscript on the base
   502   // Ad-hoc - This is to override fonts which have ready-made _accent_
   503   // glyphs with negative lbearing and rbearing. We want to position
   504   // the overscript ourselves
   505   nscoord overWidth = bmOver.width;
   506   if (!overWidth && (bmOver.rightBearing - bmOver.leftBearing > 0)) {
   507     overWidth = bmOver.rightBearing - bmOver.leftBearing;
   508     dxOver = -bmOver.leftBearing;
   509   }
   511   if (NS_MATHML_EMBELLISH_IS_ACCENTOVER(mEmbellishData.flags)) {
   512     mBoundingMetrics.width = bmBase.width; 
   513     if (alignPosition == center) {
   514       dxOver += correction;
   515     }
   516   }
   517   else {
   518     mBoundingMetrics.width = std::max(bmBase.width, overWidth);
   519     if (alignPosition == center) {
   520       dxOver += correction/2;
   521     }
   522   }
   524   if (alignPosition == center) {
   525     dxOver += (mBoundingMetrics.width - overWidth)/2;
   526     dxBase = (mBoundingMetrics.width - bmBase.width)/2;
   527   } else if (alignPosition == right) {
   528     dxOver += mBoundingMetrics.width - overWidth;
   529     dxBase = mBoundingMetrics.width - bmBase.width;
   530   }
   532   mBoundingMetrics.ascent = 
   533     bmBase.ascent + overDelta1 + bmOver.ascent + bmOver.descent;
   534   mBoundingMetrics.descent = bmBase.descent;
   535   mBoundingMetrics.leftBearing = 
   536     std::min(dxBase + bmBase.leftBearing, dxOver + bmOver.leftBearing);
   537   mBoundingMetrics.rightBearing = 
   538     std::max(dxBase + bmBase.rightBearing, dxOver + bmOver.rightBearing);
   540   //////////
   541   // pass 2, do what <munder> does: attach the underscript on the previous
   542   // result. We conceptually view the previous result as an "anynomous base" 
   543   // from where to attach the underscript. Hence if the underscript is empty,
   544   // we should end up like <mover>. If the overscript is empty, we should
   545   // end up like <munder>.
   547   nsBoundingMetrics bmAnonymousBase = mBoundingMetrics;
   548   nscoord ascentAnonymousBase =
   549     std::max(mBoundingMetrics.ascent + overDelta2,
   550            overSize.TopAscent() + bmOver.descent + overDelta1 + bmBase.ascent);
   551   ascentAnonymousBase = std::max(ascentAnonymousBase, baseSize.TopAscent());
   553   // Width of non-spacing marks is zero so use left and right bearing.
   554   nscoord underWidth = bmUnder.width;
   555   if (!underWidth) {
   556     underWidth = bmUnder.rightBearing - bmUnder.leftBearing;
   557     dxUnder = -bmUnder.leftBearing;
   558   }
   560   nscoord maxWidth = std::max(bmAnonymousBase.width, underWidth);
   561   if (alignPosition == center &&
   562       !NS_MATHML_EMBELLISH_IS_ACCENTUNDER(mEmbellishData.flags)) {
   563     GetItalicCorrection(bmAnonymousBase, correction);
   564     dxUnder += -correction/2;
   565   }
   566   nscoord dxAnonymousBase = 0;
   567   if (alignPosition == center) {
   568     dxUnder += (maxWidth - underWidth)/2;
   569     dxAnonymousBase = (maxWidth - bmAnonymousBase.width)/2;
   570   } else if (alignPosition == right) {
   571     dxUnder += maxWidth - underWidth;
   572     dxAnonymousBase = maxWidth - bmAnonymousBase.width;
   573   }
   575   // adjust the offsets of the real base and overscript since their
   576   // final offsets should be relative to us...
   577   dxOver += dxAnonymousBase;
   578   dxBase += dxAnonymousBase;
   580   mBoundingMetrics.width =
   581     std::max(dxAnonymousBase + bmAnonymousBase.width, dxUnder + bmUnder.width);
   582   // At this point, mBoundingMetrics.ascent = bmAnonymousBase.ascent 
   583   mBoundingMetrics.descent = 
   584     bmAnonymousBase.descent + underDelta1 + bmUnder.ascent + bmUnder.descent;
   585   mBoundingMetrics.leftBearing =
   586     std::min(dxAnonymousBase + bmAnonymousBase.leftBearing, dxUnder + bmUnder.leftBearing);
   587   mBoundingMetrics.rightBearing = 
   588     std::max(dxAnonymousBase + bmAnonymousBase.rightBearing, dxUnder + bmUnder.rightBearing);
   590   aDesiredSize.SetTopAscent(ascentAnonymousBase);
   591   aDesiredSize.Height() = aDesiredSize.TopAscent() +
   592     std::max(mBoundingMetrics.descent + underDelta2,
   593            bmAnonymousBase.descent + underDelta1 + bmUnder.ascent +
   594              underSize.Height() - underSize.TopAscent());
   595   aDesiredSize.Height() = std::max(aDesiredSize.Height(),
   596                                aDesiredSize.TopAscent() +
   597                                baseSize.Height() - baseSize.TopAscent());
   598   aDesiredSize.Width() = mBoundingMetrics.width;
   599   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
   601   mReference.x = 0;
   602   mReference.y = aDesiredSize.TopAscent();
   604   if (aPlaceOrigin) {
   605     nscoord dy;
   606     // place overscript
   607     if (overFrame) {
   608       dy = aDesiredSize.TopAscent() - mBoundingMetrics.ascent + bmOver.ascent 
   609         - overSize.TopAscent();
   610       FinishReflowChild (overFrame, PresContext(), overSize, nullptr, dxOver, dy, 0);
   611     }
   612     // place base
   613     dy = aDesiredSize.TopAscent() - baseSize.TopAscent();
   614     FinishReflowChild (baseFrame, PresContext(), baseSize, nullptr, dxBase, dy, 0);
   615     // place underscript
   616     if (underFrame) {
   617       dy = aDesiredSize.TopAscent() + mBoundingMetrics.descent - bmUnder.descent 
   618         - underSize.TopAscent();
   619       FinishReflowChild (underFrame, PresContext(), underSize, nullptr,
   620                          dxUnder, dy, 0);
   621     }
   622   }
   623   return NS_OK;
   624 }

mercurial