LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLContainerFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 658 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 66 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #include "nsMathMLContainerFrame.h"
       7             : 
       8             : #include "gfxContext.h"
       9             : #include "gfxUtils.h"
      10             : #include "mozilla/gfx/2D.h"
      11             : #include "nsLayoutUtils.h"
      12             : #include "nsPresContext.h"
      13             : #include "nsIPresShell.h"
      14             : #include "nsStyleContext.h"
      15             : #include "nsNameSpaceManager.h"
      16             : #include "nsIDOMMutationEvent.h"
      17             : #include "nsGkAtoms.h"
      18             : #include "nsDisplayList.h"
      19             : #include "mozilla/Likely.h"
      20             : #include "nsIScriptError.h"
      21             : #include "nsContentUtils.h"
      22             : #include "nsMathMLElement.h"
      23             : 
      24             : using namespace mozilla;
      25             : using namespace mozilla::gfx;
      26             : 
      27             : //
      28             : // nsMathMLContainerFrame implementation
      29             : //
      30             : 
      31           0 : NS_QUERYFRAME_HEAD(nsMathMLContainerFrame)
      32           0 :   NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
      33           0 :   NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame)
      34           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
      35             : 
      36             : // =============================================================================
      37             : 
      38             : // error handlers
      39             : // provide a feedback to the user when a frame with bad markup can not be rendered
      40             : nsresult
      41           0 : nsMathMLContainerFrame::ReflowError(DrawTarget* aDrawTarget,
      42             :                                     ReflowOutput& aDesiredSize)
      43             : {
      44             :   // clear all other flags and record that there is an error with this frame
      45           0 :   mEmbellishData.flags = 0;
      46           0 :   mPresentationData.flags = NS_MATHML_ERROR;
      47             : 
      48             :   ///////////////
      49             :   // Set font
      50             :   RefPtr<nsFontMetrics> fm =
      51           0 :     nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
      52             : 
      53             :   // bounding metrics
      54           0 :   nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
      55             :   mBoundingMetrics =
      56             :     nsLayoutUtils::AppUnitBoundsOfString(errorMsg.get(), errorMsg.Length(),
      57           0 :                                          *fm, aDrawTarget);
      58             : 
      59             :   // reflow metrics
      60           0 :   WritingMode wm = aDesiredSize.GetWritingMode();
      61           0 :   aDesiredSize.SetBlockStartAscent(fm->MaxAscent());
      62           0 :   nscoord descent = fm->MaxDescent();
      63           0 :   aDesiredSize.BSize(wm) = aDesiredSize.BlockStartAscent() + descent;
      64           0 :   aDesiredSize.ISize(wm) = mBoundingMetrics.width;
      65             : 
      66             :   // Also return our bounding metrics
      67           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
      68             : 
      69           0 :   return NS_OK;
      70             : }
      71             : 
      72             : class nsDisplayMathMLError : public nsDisplayItem {
      73             : public:
      74           0 :   nsDisplayMathMLError(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
      75           0 :     : nsDisplayItem(aBuilder, aFrame) {
      76           0 :     MOZ_COUNT_CTOR(nsDisplayMathMLError);
      77           0 :   }
      78             : #ifdef NS_BUILD_REFCNT_LOGGING
      79           0 :   virtual ~nsDisplayMathMLError() {
      80           0 :     MOZ_COUNT_DTOR(nsDisplayMathMLError);
      81           0 :   }
      82             : #endif
      83             : 
      84             :   virtual void Paint(nsDisplayListBuilder* aBuilder,
      85             :                      gfxContext* aCtx) override;
      86           0 :   NS_DISPLAY_DECL_NAME("MathMLError", TYPE_MATHML_ERROR)
      87             : };
      88             : 
      89           0 : void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder,
      90             :                                  gfxContext* aCtx)
      91             : {
      92             :   // Set color and font ...
      93             :   RefPtr<nsFontMetrics> fm =
      94           0 :     nsLayoutUtils::GetFontMetricsForFrame(mFrame, 1.0f);
      95             : 
      96           0 :   nsPoint pt = ToReferenceFrame();
      97           0 :   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
      98           0 :   DrawTarget* drawTarget = aCtx->GetDrawTarget();
      99           0 :   Rect rect = NSRectToSnappedRect(nsRect(pt, mFrame->GetSize()),
     100             :                                   appUnitsPerDevPixel,
     101           0 :                                   *drawTarget);
     102           0 :   ColorPattern red(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
     103           0 :   drawTarget->FillRect(rect, red);
     104             : 
     105           0 :   aCtx->SetColor(Color(1.f, 1.f, 1.f));
     106           0 :   nscoord ascent = fm->MaxAscent();
     107           0 :   NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup");
     108           0 :   nsLayoutUtils::DrawUniDirString(errorMsg.get(), uint32_t(errorMsg.Length()),
     109           0 :                                   nsPoint(pt.x, pt.y + ascent), *fm, *aCtx);
     110           0 : }
     111             : 
     112             : /* /////////////
     113             :  * nsIMathMLFrame - support methods for stretchy elements
     114             :  * =============================================================================
     115             :  */
     116             : 
     117             : static bool
     118           0 : IsForeignChild(const nsIFrame* aFrame)
     119             : {
     120             :   // This counts nsMathMLmathBlockFrame as a foreign child, because it
     121             :   // uses block reflow
     122           0 :   return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) || aFrame->IsBlockFrame();
     123             : }
     124             : 
     125           0 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(HTMLReflowOutputProperty,
     126             :                                     ReflowOutput)
     127             : 
     128             : /* static */ void
     129           0 : nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame*                  aFrame,
     130             :                                                         const ReflowOutput& aReflowOutput,
     131             :                                                         const nsBoundingMetrics&   aBoundingMetrics)
     132             : {
     133           0 :   ReflowOutput* reflowOutput = new ReflowOutput(aReflowOutput);
     134           0 :   reflowOutput->mBoundingMetrics = aBoundingMetrics;
     135           0 :   aFrame->SetProperty(HTMLReflowOutputProperty(), reflowOutput);
     136           0 : }
     137             : 
     138             : // helper method to facilitate getting the reflow and bounding metrics
     139             : /* static */ void
     140           0 : nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame*            aFrame,
     141             :                                                        ReflowOutput& aReflowOutput,
     142             :                                                        nsBoundingMetrics&   aBoundingMetrics,
     143             :                                                        eMathMLFrameType*    aMathMLFrameType)
     144             : {
     145           0 :   NS_PRECONDITION(aFrame, "null arg");
     146             : 
     147             :   ReflowOutput* reflowOutput =
     148           0 :     aFrame->GetProperty(HTMLReflowOutputProperty());
     149             : 
     150             :   // IMPORTANT: This function is only meant to be called in Place() methods
     151             :   // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the
     152             :   // information.
     153           0 :   NS_ASSERTION(reflowOutput, "Didn't SaveReflowAndBoundingMetricsFor frame!");
     154           0 :   if (reflowOutput) {
     155           0 :     aReflowOutput = *reflowOutput;
     156           0 :     aBoundingMetrics = reflowOutput->mBoundingMetrics;
     157             :   }
     158             : 
     159           0 :   if (aMathMLFrameType) {
     160           0 :     if (!IsForeignChild(aFrame)) {
     161           0 :       nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
     162           0 :       if (mathMLFrame) {
     163           0 :         *aMathMLFrameType = mathMLFrame->GetMathMLFrameType();
     164           0 :         return;
     165             :       }
     166             :     }
     167           0 :     *aMathMLFrameType = eMathMLFrameType_UNKNOWN;
     168             :   }
     169             : 
     170             : }
     171             : 
     172             : void
     173           0 : nsMathMLContainerFrame::ClearSavedChildMetrics()
     174             : {
     175           0 :   nsIFrame* childFrame = mFrames.FirstChild();
     176           0 :   while (childFrame) {
     177           0 :     childFrame->DeleteProperty(HTMLReflowOutputProperty());
     178           0 :     childFrame = childFrame->GetNextSibling();
     179             :   }
     180           0 : }
     181             : 
     182             : // helper to get the preferred size that a container frame should use to fire
     183             : // the stretch on its stretchy child frames.
     184             : void
     185           0 : nsMathMLContainerFrame::GetPreferredStretchSize(DrawTarget*          aDrawTarget,
     186             :                                                 uint32_t             aOptions,
     187             :                                                 nsStretchDirection   aStretchDirection,
     188             :                                                 nsBoundingMetrics&   aPreferredStretchSize)
     189             : {
     190           0 :   if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) {
     191             :     // when our actual size is ok, just use it
     192           0 :     aPreferredStretchSize = mBoundingMetrics;
     193             :   }
     194           0 :   else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
     195             :     // compute our up-to-date size using Place()
     196           0 :     ReflowOutput reflowOutput(GetWritingMode());
     197           0 :     Place(aDrawTarget, false, reflowOutput);
     198           0 :     aPreferredStretchSize = reflowOutput.mBoundingMetrics;
     199             :   }
     200             :   else {
     201             :     // compute a size that includes embellishments iff the container stretches
     202             :     // in the same direction as the embellished operator.
     203           0 :     bool stretchAll = aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL ?
     204           0 :                       NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) :
     205           0 :                       NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
     206           0 :     NS_ASSERTION(aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL ||
     207             :                  aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL,
     208             :                  "You must specify a direction in which to stretch");
     209           0 :     NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
     210             :                  stretchAll,
     211             :                  "invalid call to GetPreferredStretchSize");
     212           0 :     bool firstTime = true;
     213           0 :     nsBoundingMetrics bm, bmChild;
     214             :     nsIFrame* childFrame =
     215           0 :       stretchAll ? PrincipalChildList().FirstChild() : mPresentationData.baseFrame;
     216           0 :     while (childFrame) {
     217             :       // initializations in case this child happens not to be a MathML frame
     218           0 :       nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
     219           0 :       if (mathMLFrame) {
     220           0 :         nsEmbellishData embellishData;
     221           0 :         nsPresentationData presentationData;
     222           0 :         mathMLFrame->GetEmbellishData(embellishData);
     223           0 :         mathMLFrame->GetPresentationData(presentationData);
     224           0 :         if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) &&
     225           0 :             embellishData.direction == aStretchDirection &&
     226           0 :             presentationData.baseFrame) {
     227             :           // embellishements are not included, only consider the inner first child itself
     228             :           // XXXkt Does that mean the core descendent frame should be used
     229             :           // instead of the base child?
     230           0 :           nsIMathMLFrame* mathMLchildFrame = do_QueryFrame(presentationData.baseFrame);
     231           0 :           if (mathMLchildFrame) {
     232           0 :             mathMLFrame = mathMLchildFrame;
     233             :           }
     234             :         }
     235           0 :         mathMLFrame->GetBoundingMetrics(bmChild);
     236             :       }
     237             :       else {
     238           0 :         ReflowOutput unused(GetWritingMode());
     239           0 :         GetReflowAndBoundingMetricsFor(childFrame, unused, bmChild);
     240             :       }
     241             : 
     242           0 :       if (firstTime) {
     243           0 :         firstTime = false;
     244           0 :         bm = bmChild;
     245           0 :         if (!stretchAll) {
     246             :           // we may get here for cases such as <msup><mo>...</mo> ... </msup>,
     247             :           // or <maction>...<mo>...</mo></maction>.
     248           0 :           break;
     249             :         }
     250             :       }
     251             :       else {
     252           0 :         if (aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL) {
     253             :           // if we get here, it means this is container that will stack its children
     254             :           // vertically and fire an horizontal stretch on each them. This is the case
     255             :           // for \munder, \mover, \munderover. We just sum-up the size vertically.
     256           0 :           bm.descent += bmChild.ascent + bmChild.descent;
     257             :           // Sometimes non-spacing marks (when width is zero) are positioned
     258             :           // to the left of the origin, but it is the distance between left
     259             :           // and right bearing that is important rather than the offsets from
     260             :           // the origin.
     261           0 :           if (bmChild.width == 0) {
     262           0 :             bmChild.rightBearing -= bmChild.leftBearing;
     263           0 :             bmChild.leftBearing = 0;
     264             :           }
     265           0 :           if (bm.leftBearing > bmChild.leftBearing)
     266           0 :             bm.leftBearing = bmChild.leftBearing;
     267           0 :           if (bm.rightBearing < bmChild.rightBearing)
     268           0 :             bm.rightBearing = bmChild.rightBearing;
     269             :         }
     270           0 :         else if (aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) {
     271             :           // just sum-up the sizes horizontally.
     272           0 :           bm += bmChild;
     273             :         }
     274             :         else {
     275           0 :           NS_ERROR("unexpected case in GetPreferredStretchSize");
     276           0 :           break;
     277             :         }
     278             :       }
     279           0 :       childFrame = childFrame->GetNextSibling();
     280             :     }
     281           0 :     aPreferredStretchSize = bm;
     282             :   }
     283           0 : }
     284             : 
     285             : NS_IMETHODIMP
     286           0 : nsMathMLContainerFrame::Stretch(DrawTarget*          aDrawTarget,
     287             :                                 nsStretchDirection   aStretchDirection,
     288             :                                 nsBoundingMetrics&   aContainerSize,
     289             :                                 ReflowOutput& aDesiredStretchSize)
     290             : {
     291           0 :   if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
     292             : 
     293           0 :     if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
     294           0 :       NS_WARNING("it is wrong to fire stretch more than once on a frame");
     295           0 :       return NS_OK;
     296             :     }
     297           0 :     mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
     298             : 
     299           0 :     if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
     300           0 :       NS_WARNING("it is wrong to fire stretch on a erroneous frame");
     301           0 :       return NS_OK;
     302             :     }
     303             : 
     304             :     // Pass the stretch to the base child ...
     305             : 
     306           0 :     nsIFrame* baseFrame = mPresentationData.baseFrame;
     307           0 :     if (baseFrame) {
     308           0 :       nsIMathMLFrame* mathMLFrame = do_QueryFrame(baseFrame);
     309           0 :       NS_ASSERTION(mathMLFrame, "Something is wrong somewhere");
     310           0 :       if (mathMLFrame) {
     311             : 
     312             :         // And the trick is that the child's rect.x is still holding the descent,
     313             :         // and rect.y is still holding the ascent ...
     314           0 :         ReflowOutput childSize(aDesiredStretchSize);
     315           0 :         GetReflowAndBoundingMetricsFor(baseFrame, childSize, childSize.mBoundingMetrics);
     316             : 
     317             :         // See if we should downsize and confine the stretch to us...
     318             :         // XXX there may be other cases where we can downsize the stretch,
     319             :         // e.g., the first &Sum; might appear big in the following situation
     320             :         // <math xmlns='http://www.w3.org/1998/Math/MathML'>
     321             :         //   <mstyle>
     322             :         //     <msub>
     323             :         //        <msub><mo>&Sum;</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
     324             :         //        <msub><mo>&Sum;</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
     325             :         //      </msub>
     326             :         //   </mstyle>
     327             :         // </math>
     328           0 :         nsBoundingMetrics containerSize = aContainerSize;
     329           0 :         if (aStretchDirection != mEmbellishData.direction &&
     330           0 :             mEmbellishData.direction != NS_STRETCH_DIRECTION_UNSUPPORTED) {
     331           0 :           NS_ASSERTION(mEmbellishData.direction != NS_STRETCH_DIRECTION_DEFAULT,
     332             :                        "Stretches may have a default direction, operators can not.");
     333           0 :           if (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL ?
     334           0 :               NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) :
     335           0 :               NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
     336           0 :             GetPreferredStretchSize(aDrawTarget, 0,
     337           0 :                                     mEmbellishData.direction, containerSize);
     338             :             // Stop further recalculations
     339           0 :             aStretchDirection = mEmbellishData.direction;
     340             :           } else {
     341             :             // We aren't going to stretch the child, so just use the child metrics.
     342           0 :             containerSize = childSize.mBoundingMetrics;
     343             :           }
     344             :         }
     345             : 
     346             :         // do the stretching...
     347             :         mathMLFrame->Stretch(aDrawTarget,
     348           0 :                              aStretchDirection, containerSize, childSize);
     349             :         // store the updated metrics
     350             :         SaveReflowAndBoundingMetricsFor(baseFrame, childSize,
     351           0 :                                         childSize.mBoundingMetrics);
     352             : 
     353             :         // Remember the siblings which were _deferred_.
     354             :         // Now that this embellished child may have changed, we need to
     355             :         // fire the stretch on its siblings using our updated size
     356             : 
     357           0 :         if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
     358           0 :             NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
     359             : 
     360             :           nsStretchDirection stretchDir =
     361           0 :             NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ?
     362           0 :               NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL;
     363             : 
     364             :           GetPreferredStretchSize(aDrawTarget, STRETCH_CONSIDER_EMBELLISHMENTS,
     365           0 :                                   stretchDir, containerSize);
     366             : 
     367           0 :           nsIFrame* childFrame = mFrames.FirstChild();
     368           0 :           while (childFrame) {
     369           0 :             if (childFrame != mPresentationData.baseFrame) {
     370           0 :               mathMLFrame = do_QueryFrame(childFrame);
     371           0 :               if (mathMLFrame) {
     372             :                 // retrieve the metrics that was stored at the previous pass
     373             :                 GetReflowAndBoundingMetricsFor(childFrame,
     374           0 :                   childSize, childSize.mBoundingMetrics);
     375             :                 // do the stretching...
     376             :                 mathMLFrame->Stretch(aDrawTarget, stretchDir,
     377           0 :                                      containerSize, childSize);
     378             :                 // store the updated metrics
     379             :                 SaveReflowAndBoundingMetricsFor(childFrame, childSize,
     380           0 :                                                 childSize.mBoundingMetrics);
     381             :               }
     382             :             }
     383           0 :             childFrame = childFrame->GetNextSibling();
     384             :           }
     385             :         }
     386             : 
     387             :         // re-position all our children
     388           0 :         nsresult rv = Place(aDrawTarget, true, aDesiredStretchSize);
     389           0 :         if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
     390             :           // Make sure the child frames get their DidReflow() calls.
     391           0 :           DidReflowChildren(mFrames.FirstChild());
     392             :         }
     393             : 
     394             :         // If our parent is not embellished, it means we are the outermost embellished
     395             :         // container and so we put the spacing, otherwise we don't include the spacing,
     396             :         // the outermost embellished container will take care of it.
     397             : 
     398           0 :         nsEmbellishData parentData;
     399           0 :         GetEmbellishDataFrom(GetParent(), parentData);
     400             :         // ensure that we are the embellished child, not just a sibling
     401             :         // (need to test coreFrame since <mfrac> resets other things)
     402           0 :         if (parentData.coreFrame != mEmbellishData.coreFrame) {
     403             :           // (we fetch values from the core since they may use units that depend
     404             :           // on style data, and style changes could have occurred in the core since
     405             :           // our last visit there)
     406           0 :           nsEmbellishData coreData;
     407           0 :           GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
     408             : 
     409           0 :           mBoundingMetrics.width +=
     410           0 :             coreData.leadingSpace + coreData.trailingSpace;
     411           0 :           aDesiredStretchSize.Width() = mBoundingMetrics.width;
     412           0 :           aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
     413             : 
     414           0 :           nscoord dx = (StyleVisibility()->mDirection ?
     415           0 :                         coreData.trailingSpace : coreData.leadingSpace);
     416           0 :           if (dx != 0) {
     417           0 :             mBoundingMetrics.leftBearing += dx;
     418           0 :             mBoundingMetrics.rightBearing += dx;
     419           0 :             aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
     420           0 :             aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
     421             : 
     422           0 :             nsIFrame* childFrame = mFrames.FirstChild();
     423           0 :             while (childFrame) {
     424           0 :               childFrame->SetPosition(childFrame->GetPosition()
     425           0 :                                       + nsPoint(dx, 0));
     426           0 :               childFrame = childFrame->GetNextSibling();
     427             :             }
     428             :           }
     429             :         }
     430             : 
     431             :         // Finished with these:
     432           0 :         ClearSavedChildMetrics();
     433             :         // Set our overflow area
     434           0 :         GatherAndStoreOverflow(&aDesiredStretchSize);
     435             :       }
     436             :     }
     437             :   }
     438           0 :   return NS_OK;
     439             : }
     440             : 
     441             : nsresult
     442           0 : nsMathMLContainerFrame::FinalizeReflow(DrawTarget* aDrawTarget,
     443             :                                        ReflowOutput& aDesiredSize)
     444             : {
     445             :   // During reflow, we use rect.x and rect.y as placeholders for the child's ascent
     446             :   // and descent in expectation of a stretch command. Hence we need to ensure that
     447             :   // a stretch command will actually be fired later on, after exiting from our
     448             :   // reflow. If the stretch is not fired, the rect.x, and rect.y will remain
     449             :   // with inappropriate data causing children to be improperly positioned.
     450             :   // This helper method checks to see if our parent will fire a stretch command
     451             :   // targeted at us. If not, we go ahead and fire an involutive stretch on
     452             :   // ourselves. This will clear all the rect.x and rect.y, and return our
     453             :   // desired size.
     454             : 
     455             : 
     456             :   // First, complete the post-reflow hook.
     457             :   // We use the information in our children rectangles to position them.
     458             :   // If placeOrigin==false, then Place() will not touch rect.x, and rect.y.
     459             :   // They will still be holding the ascent and descent for each child.
     460             : 
     461             :   // The first clause caters for any non-embellished container.
     462             :   // The second clause is for a container which won't fire stretch even though it is
     463             :   // embellished, e.g., as in <mfrac><mo>...</mo> ... </mfrac>, the test is convoluted
     464             :   // because it excludes the particular case of the core <mo>...</mo> itself.
     465             :   // (<mo> needs to fire stretch on its MathMLChar in any case to initialize it)
     466           0 :   bool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
     467           0 :                        (mEmbellishData.coreFrame != this && !mPresentationData.baseFrame &&
     468           0 :                         mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED);
     469           0 :   nsresult rv = Place(aDrawTarget, placeOrigin, aDesiredSize);
     470             : 
     471             :   // Place() will call FinishReflowChild() when placeOrigin is true but if
     472             :   // it returns before reaching FinishReflowChild() due to errors we need
     473             :   // to fulfill the reflow protocol by calling DidReflow for the child frames
     474             :   // that still needs it here (or we may crash - bug 366012).
     475             :   // If placeOrigin is false we should reach Place() with aPlaceOrigin == true
     476             :   // through Stretch() eventually.
     477           0 :   if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
     478           0 :     GatherAndStoreOverflow(&aDesiredSize);
     479           0 :     DidReflowChildren(PrincipalChildList().FirstChild());
     480           0 :     return rv;
     481             :   }
     482             : 
     483           0 :   bool parentWillFireStretch = false;
     484           0 :   if (!placeOrigin) {
     485             :     // This means the rect.x and rect.y of our children were not set!!
     486             :     // Don't go without checking to see if our parent will later fire a Stretch() command
     487             :     // targeted at us. The Stretch() will cause the rect.x and rect.y to clear...
     488           0 :     nsIMathMLFrame* mathMLFrame = do_QueryFrame(GetParent());
     489           0 :     if (mathMLFrame) {
     490           0 :       nsEmbellishData embellishData;
     491           0 :       nsPresentationData presentationData;
     492           0 :       mathMLFrame->GetEmbellishData(embellishData);
     493           0 :       mathMLFrame->GetPresentationData(presentationData);
     494           0 :       if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) ||
     495           0 :           NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) ||
     496           0 :           (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)
     497           0 :             && presentationData.baseFrame == this))
     498             :       {
     499           0 :         parentWillFireStretch = true;
     500             :       }
     501             :     }
     502           0 :     if (!parentWillFireStretch) {
     503             :       // There is nobody who will fire the stretch for us, we do it ourselves!
     504             : 
     505             :       bool stretchAll =
     506             :         /* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */
     507           0 :         NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
     508             : 
     509             :       nsStretchDirection stretchDir;
     510           0 :       if (mEmbellishData.coreFrame == this || /* case of a bare <mo>...</mo> itself */
     511           0 :           (mEmbellishData.direction == NS_STRETCH_DIRECTION_HORIZONTAL &&
     512           0 :            stretchAll) || /* or <mover><mo>...</mo>...</mover>, or friends */
     513           0 :           mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) { /* Doesn't stretch */
     514           0 :         stretchDir = mEmbellishData.direction;
     515             :       } else {
     516             :         // Let the Stretch() call decide the direction.
     517           0 :         stretchDir = NS_STRETCH_DIRECTION_DEFAULT;
     518             :       }
     519             :       // Use our current size as computed earlier by Place()
     520             :       // The stretch call will detect if this is incorrect and recalculate the size.
     521           0 :       nsBoundingMetrics defaultSize = aDesiredSize.mBoundingMetrics;
     522             : 
     523           0 :       Stretch(aDrawTarget, stretchDir, defaultSize, aDesiredSize);
     524             : #ifdef DEBUG
     525             :       {
     526             :         // The Place() call above didn't request FinishReflowChild(),
     527             :         // so let's check that we eventually did through Stretch().
     528           0 :         for (nsIFrame* childFrame : PrincipalChildList()) {
     529           0 :           NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
     530             :                        "DidReflow() was never called");
     531             :         }
     532             :       }
     533             : #endif
     534             :     }
     535             :   }
     536             : 
     537             :   // Also return our bounding metrics
     538           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     539             : 
     540             :   // see if we should fix the spacing
     541           0 :   FixInterFrameSpacing(aDesiredSize);
     542             : 
     543           0 :   if (!parentWillFireStretch) {
     544             :     // Not expecting a stretch.
     545             :     // Finished with these:
     546           0 :     ClearSavedChildMetrics();
     547             :     // Set our overflow area.
     548           0 :     GatherAndStoreOverflow(&aDesiredSize);
     549             :   }
     550             : 
     551           0 :   return NS_OK;
     552             : }
     553             : 
     554             : 
     555             : /* /////////////
     556             :  * nsIMathMLFrame - support methods for scripting elements (nested frames
     557             :  * within msub, msup, msubsup, munder, mover, munderover, mmultiscripts,
     558             :  * mfrac, mroot, mtable).
     559             :  * =============================================================================
     560             :  */
     561             : 
     562             : // helper to let the update of presentation data pass through
     563             : // a subtree that may contain non-mathml container frames
     564             : /* static */ void
     565           0 : nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame*       aFrame,
     566             :                                                      uint32_t        aFlagsValues,
     567             :                                                      uint32_t        aFlagsToUpdate)
     568             : {
     569           0 :   if (!aFrame || !aFlagsToUpdate)
     570           0 :     return;
     571           0 :   nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
     572           0 :   if (mathMLFrame) {
     573             :     // update
     574             :     mathMLFrame->UpdatePresentationData(aFlagsValues,
     575           0 :                                         aFlagsToUpdate);
     576             :     // propagate using the base method to make sure that the control
     577             :     // is passed on to MathML frames that may be overloading the method
     578             :     mathMLFrame->UpdatePresentationDataFromChildAt(0, -1,
     579           0 :       aFlagsValues, aFlagsToUpdate);
     580             :   }
     581             :   else {
     582             :     // propagate down the subtrees
     583           0 :     for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
     584             :       PropagatePresentationDataFor(childFrame,
     585           0 :         aFlagsValues, aFlagsToUpdate);
     586             :     }
     587             :   }
     588             : }
     589             : 
     590             : /* static */ void
     591           0 : nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame*       aParentFrame,
     592             :                                                              int32_t         aFirstChildIndex,
     593             :                                                              int32_t         aLastChildIndex,
     594             :                                                              uint32_t        aFlagsValues,
     595             :                                                              uint32_t        aFlagsToUpdate)
     596             : {
     597           0 :   if (!aParentFrame || !aFlagsToUpdate)
     598           0 :     return;
     599           0 :   int32_t index = 0;
     600           0 :   for (nsIFrame* childFrame : aParentFrame->PrincipalChildList()) {
     601           0 :     if ((index >= aFirstChildIndex) &&
     602           0 :         ((aLastChildIndex <= 0) || ((aLastChildIndex > 0) &&
     603             :          (index <= aLastChildIndex)))) {
     604             :       PropagatePresentationDataFor(childFrame,
     605           0 :         aFlagsValues, aFlagsToUpdate);
     606             :     }
     607           0 :     index++;
     608             :   }
     609             : }
     610             : 
     611             : /* //////////////////
     612             :  * Frame construction
     613             :  * =============================================================================
     614             :  */
     615             : 
     616             : 
     617             : void
     618           0 : nsMathMLContainerFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     619             :                                          const nsRect&           aDirtyRect,
     620             :                                          const nsDisplayListSet& aLists)
     621             : {
     622             :   // report an error if something wrong was found in this frame
     623           0 :   if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
     624           0 :     if (!IsVisibleForPainting(aBuilder))
     625           0 :       return;
     626             : 
     627           0 :     aLists.Content()->AppendNewToTop(
     628           0 :       new (aBuilder) nsDisplayMathMLError(aBuilder, this));
     629           0 :     return;
     630             :   }
     631             : 
     632           0 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
     633             : 
     634           0 :   BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
     635           0 :                                       DISPLAY_CHILD_INLINE);
     636             : 
     637             : #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
     638             :   // for visual debug
     639             :   // ----------------
     640             :   // if you want to see your bounding box, make sure to properly fill
     641             :   // your mBoundingMetrics and mReference point, and set
     642             :   // mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS
     643             :   // in the Init() of your sub-class
     644             :   DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
     645             : #endif
     646             : }
     647             : 
     648             : // Note that this method re-builds the automatic data in the children -- not
     649             : // in aParentFrame itself (except for those particular operations that the
     650             : // parent frame may do in its TransmitAutomaticData()).
     651             : /* static */ void
     652           0 : nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame)
     653             : {
     654             :   // 1. As we descend the tree, make each child frame inherit data from
     655             :   // the parent
     656             :   // 2. As we ascend the tree, transmit any specific change that we want
     657             :   // down the subtrees
     658           0 :   for (nsIFrame* childFrame : aParentFrame->PrincipalChildList()) {
     659           0 :     nsIMathMLFrame* childMathMLFrame = do_QueryFrame(childFrame);
     660           0 :     if (childMathMLFrame) {
     661           0 :       childMathMLFrame->InheritAutomaticData(aParentFrame);
     662             :     }
     663           0 :     RebuildAutomaticDataForChildren(childFrame);
     664             :   }
     665           0 :   nsIMathMLFrame* mathMLFrame = do_QueryFrame(aParentFrame);
     666           0 :   if (mathMLFrame) {
     667           0 :     mathMLFrame->TransmitAutomaticData();
     668             :   }
     669           0 : }
     670             : 
     671             : /* static */ nsresult
     672           0 : nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
     673             : {
     674           0 :   if (!aParentFrame)
     675           0 :     return NS_OK;
     676             : 
     677             :   // walk-up to the first frame that is a MathML frame, stop if we reach <math>
     678           0 :   nsIFrame* frame = aParentFrame;
     679             :   while (1) {
     680           0 :      nsIFrame* parent = frame->GetParent();
     681           0 :      if (!parent || !parent->GetContent())
     682           0 :        break;
     683             : 
     684             :     // stop if it is a MathML frame
     685           0 :     nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame);
     686           0 :     if (mathMLFrame)
     687           0 :       break;
     688             : 
     689             :     // stop if we reach the root <math> tag
     690           0 :     nsIContent* content = frame->GetContent();
     691           0 :     NS_ASSERTION(content, "dangling frame without a content node");
     692           0 :     if (!content)
     693           0 :       break;
     694           0 :     if (content->IsMathMLElement(nsGkAtoms::math))
     695           0 :       break;
     696             : 
     697           0 :     frame = parent;
     698           0 :   }
     699             : 
     700             :   // re-sync the presentation data and embellishment data of our children
     701           0 :   RebuildAutomaticDataForChildren(frame);
     702             : 
     703             :   // Ask our parent frame to reflow us
     704           0 :   nsIFrame* parent = frame->GetParent();
     705           0 :   NS_ASSERTION(parent, "No parent to pass the reflow request up to");
     706           0 :   if (!parent)
     707           0 :     return NS_OK;
     708             : 
     709           0 :   frame->PresContext()->PresShell()->
     710           0 :     FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     711             : 
     712           0 :   return NS_OK;
     713             : }
     714             : 
     715             : // There are precise rules governing children of a MathML frame,
     716             : // and properties such as the scriptlevel depends on those rules.
     717             : // Hence for things to work, callers must use Append/Insert/etc wisely.
     718             : 
     719             : nsresult
     720           0 : nsMathMLContainerFrame::ChildListChanged(int32_t aModType)
     721             : {
     722             :   // If this is an embellished frame we need to rebuild the
     723             :   // embellished hierarchy by walking-up to the parent of the
     724             :   // outermost embellished container.
     725           0 :   nsIFrame* frame = this;
     726           0 :   if (mEmbellishData.coreFrame) {
     727           0 :     nsIFrame* parent = GetParent();
     728           0 :     nsEmbellishData embellishData;
     729           0 :     for ( ; parent; frame = parent, parent = parent->GetParent()) {
     730           0 :       GetEmbellishDataFrom(parent, embellishData);
     731           0 :       if (embellishData.coreFrame != mEmbellishData.coreFrame)
     732           0 :         break;
     733             :     }
     734             :   }
     735           0 :   return ReLayoutChildren(frame);
     736             : }
     737             : 
     738             : void
     739           0 : nsMathMLContainerFrame::AppendFrames(ChildListID     aListID,
     740             :                                      nsFrameList&    aFrameList)
     741             : {
     742           0 :   MOZ_ASSERT(aListID == kPrincipalList);
     743           0 :   mFrames.AppendFrames(this, aFrameList);
     744           0 :   ChildListChanged(nsIDOMMutationEvent::ADDITION);
     745           0 : }
     746             : 
     747             : void
     748           0 : nsMathMLContainerFrame::InsertFrames(ChildListID     aListID,
     749             :                                      nsIFrame*       aPrevFrame,
     750             :                                      nsFrameList&    aFrameList)
     751             : {
     752           0 :   MOZ_ASSERT(aListID == kPrincipalList);
     753           0 :   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
     754           0 :   ChildListChanged(nsIDOMMutationEvent::ADDITION);
     755           0 : }
     756             : 
     757             : void
     758           0 : nsMathMLContainerFrame::RemoveFrame(ChildListID     aListID,
     759             :                                     nsIFrame*       aOldFrame)
     760             : {
     761           0 :   MOZ_ASSERT(aListID == kPrincipalList);
     762           0 :   mFrames.DestroyFrame(aOldFrame);
     763           0 :   ChildListChanged(nsIDOMMutationEvent::REMOVAL);
     764           0 : }
     765             : 
     766             : nsresult
     767           0 : nsMathMLContainerFrame::AttributeChanged(int32_t         aNameSpaceID,
     768             :                                          nsIAtom*        aAttribute,
     769             :                                          int32_t         aModType)
     770             : {
     771             :   // XXX Since they are numerous MathML attributes that affect layout, and
     772             :   // we can't check all of them here, play safe by requesting a reflow.
     773             :   // XXXldb This should only do work for attributes that cause changes!
     774           0 :   PresContext()->PresShell()->
     775           0 :     FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     776             : 
     777           0 :   return NS_OK;
     778             : }
     779             : 
     780             : void
     781           0 : nsMathMLContainerFrame::GatherAndStoreOverflow(ReflowOutput* aMetrics)
     782             : {
     783           0 :   mBlockStartAscent = aMetrics->BlockStartAscent();
     784             : 
     785             :   // nsIFrame::FinishAndStoreOverflow likes the overflow area to include the
     786             :   // frame rectangle.
     787           0 :   aMetrics->SetOverflowAreasToDesiredBounds();
     788             : 
     789           0 :   ComputeCustomOverflow(aMetrics->mOverflowAreas);
     790             : 
     791             :   // mBoundingMetrics does not necessarily include content of <mpadded>
     792             :   // elements whose mBoundingMetrics may not be representative of the true
     793             :   // bounds, and doesn't include the CSS2 outline rectangles of children, so
     794             :   // make such to include child overflow areas.
     795           0 :   UnionChildOverflow(aMetrics->mOverflowAreas);
     796             : 
     797           0 :   FinishAndStoreOverflow(aMetrics);
     798           0 : }
     799             : 
     800             : bool
     801           0 : nsMathMLContainerFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
     802             : {
     803             :   // All non-child-frame content such as nsMathMLChars (and most child-frame
     804             :   // content) is included in mBoundingMetrics.
     805             :   nsRect boundingBox(mBoundingMetrics.leftBearing,
     806           0 :                      mBlockStartAscent - mBoundingMetrics.ascent,
     807           0 :                      mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing,
     808           0 :                      mBoundingMetrics.ascent + mBoundingMetrics.descent);
     809             : 
     810             :   // REVIEW: Maybe this should contribute only to visual overflow
     811             :   // and not scrollable?
     812           0 :   aOverflowAreas.UnionAllWith(boundingBox);
     813           0 :   return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
     814             : }
     815             : 
     816             : void
     817           0 : nsMathMLContainerFrame::ReflowChild(nsIFrame*                aChildFrame,
     818             :                                     nsPresContext*           aPresContext,
     819             :                                     ReflowOutput&     aDesiredSize,
     820             :                                     const ReflowInput& aReflowInput,
     821             :                                     nsReflowStatus&          aStatus)
     822             : {
     823             :   // Having foreign/hybrid children, e.g., from html markups, is not defined by
     824             :   // the MathML spec. But it can happen in practice, e.g., <html:img> allows us
     825             :   // to do some cool demos... or we may have a child that is an nsInlineFrame
     826             :   // from a generated content such as :before { content: open-quote } or
     827             :   // :after { content: close-quote }. Unfortunately, the other frames out-there
     828             :   // may expect their own invariants that are not met when we mix things.
     829             :   // Hence we do not claim their support, but we will nevertheless attempt to keep
     830             :   // them in the flow, if we can get their desired size. We observed that most
     831             :   // frames may be reflowed generically, but nsInlineFrames need extra care.
     832             : 
     833             : #ifdef DEBUG
     834           0 :   nsInlineFrame* inlineFrame = do_QueryFrame(aChildFrame);
     835           0 :   NS_ASSERTION(!inlineFrame, "Inline frames should be wrapped in blocks");
     836             : #endif
     837             : 
     838             :   nsContainerFrame::
     839           0 :          ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowInput,
     840           0 :                      0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
     841             : 
     842           0 :   if (aDesiredSize.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) {
     843             :     // This will be suitable for inline frames, which are wrapped in a block.
     844             :     nscoord ascent;
     845           0 :     WritingMode wm = aDesiredSize.GetWritingMode();
     846           0 :     if (!nsLayoutUtils::GetLastLineBaseline(wm, aChildFrame, &ascent)) {
     847             :       // We don't expect any other block children so just place the frame on
     848             :       // the baseline instead of going through DidReflow() and
     849             :       // GetBaseline().  This is what nsFrame::GetBaseline() will do anyway.
     850           0 :       aDesiredSize.SetBlockStartAscent(aDesiredSize.BSize(wm));
     851             :     } else {
     852           0 :       aDesiredSize.SetBlockStartAscent(ascent);
     853             :     }
     854             :   }
     855           0 :   if (IsForeignChild(aChildFrame)) {
     856             :     // use ComputeTightBounds API as aDesiredSize.mBoundingMetrics is not set.
     857           0 :     nsRect r = aChildFrame->ComputeTightBounds(aReflowInput.mRenderingContext->GetDrawTarget());
     858           0 :     aDesiredSize.mBoundingMetrics.leftBearing = r.x;
     859           0 :     aDesiredSize.mBoundingMetrics.rightBearing = r.XMost();
     860           0 :     aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent() - r.y;
     861           0 :     aDesiredSize.mBoundingMetrics.descent = r.YMost() - aDesiredSize.BlockStartAscent();
     862           0 :     aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width();
     863             :   }
     864           0 : }
     865             : 
     866             : void
     867           0 : nsMathMLContainerFrame::Reflow(nsPresContext*           aPresContext,
     868             :                                ReflowOutput&     aDesiredSize,
     869             :                                const ReflowInput& aReflowInput,
     870             :                                nsReflowStatus&          aStatus)
     871             : {
     872           0 :   MarkInReflow();
     873           0 :   mPresentationData.flags &= ~NS_MATHML_ERROR;
     874           0 :   aDesiredSize.Width() = aDesiredSize.Height() = 0;
     875           0 :   aDesiredSize.SetBlockStartAscent(0);
     876           0 :   aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
     877             : 
     878             :   /////////////
     879             :   // Reflow children
     880             :   // Asking each child to cache its bounding metrics
     881             : 
     882           0 :   nsReflowStatus childStatus;
     883           0 :   nsIFrame* childFrame = mFrames.FirstChild();
     884           0 :   while (childFrame) {
     885             :     ReflowOutput childDesiredSize(aReflowInput, // ???
     886           0 :                                          aDesiredSize.mFlags);
     887           0 :     WritingMode wm = childFrame->GetWritingMode();
     888           0 :     LogicalSize availSize = aReflowInput.ComputedSize(wm);
     889           0 :     availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     890             :     ReflowInput childReflowInput(aPresContext, aReflowInput,
     891           0 :                                        childFrame, availSize);
     892             :     ReflowChild(childFrame, aPresContext, childDesiredSize,
     893           0 :                 childReflowInput, childStatus);
     894             :     //NS_ASSERTION(childStatus.IsComplete(), "bad status");
     895             :     SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
     896           0 :                                     childDesiredSize.mBoundingMetrics);
     897           0 :     childFrame = childFrame->GetNextSibling();
     898             :   }
     899             : 
     900             :   /////////////
     901             :   // If we are a container which is entitled to stretch its children, then we
     902             :   // ask our stretchy children to stretch themselves
     903             : 
     904             :   // The stretching of siblings of an embellished child is _deferred_ until
     905             :   // after finishing the stretching of the embellished child - bug 117652
     906             : 
     907           0 :   DrawTarget* drawTarget = aReflowInput.mRenderingContext->GetDrawTarget();
     908             : 
     909           0 :   if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) &&
     910           0 :       (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
     911           0 :        NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) {
     912             : 
     913             :     // get the stretchy direction
     914             :     nsStretchDirection stretchDir =
     915           0 :       NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)
     916           0 :       ? NS_STRETCH_DIRECTION_VERTICAL
     917           0 :       : NS_STRETCH_DIRECTION_HORIZONTAL;
     918             : 
     919             :     // what size should we use to stretch our stretchy children
     920             :     // We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet
     921             :     // We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to
     922             :     // include them in the caculations of the size of stretchy elements
     923           0 :     nsBoundingMetrics containerSize;
     924           0 :     GetPreferredStretchSize(drawTarget, 0, stretchDir, containerSize);
     925             : 
     926             :     // fire the stretch on each child
     927           0 :     childFrame = mFrames.FirstChild();
     928           0 :     while (childFrame) {
     929           0 :       nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
     930           0 :       if (mathMLFrame) {
     931             :         // retrieve the metrics that was stored at the previous pass
     932           0 :         ReflowOutput childDesiredSize(aReflowInput);
     933             :         GetReflowAndBoundingMetricsFor(childFrame,
     934           0 :           childDesiredSize, childDesiredSize.mBoundingMetrics);
     935             : 
     936             :         mathMLFrame->Stretch(drawTarget, stretchDir,
     937           0 :                              containerSize, childDesiredSize);
     938             :         // store the updated metrics
     939             :         SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
     940           0 :                                         childDesiredSize.mBoundingMetrics);
     941             :       }
     942           0 :       childFrame = childFrame->GetNextSibling();
     943             :     }
     944             :   }
     945             : 
     946             :   /////////////
     947             :   // Place children now by re-adjusting the origins to align the baselines
     948           0 :   FinalizeReflow(drawTarget, aDesiredSize);
     949             : 
     950           0 :   aStatus.Reset();
     951           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
     952           0 : }
     953             : 
     954             : static nscoord AddInterFrameSpacingToSize(ReflowOutput&    aDesiredSize,
     955             :                                           nsMathMLContainerFrame* aFrame);
     956             : 
     957             : /* virtual */ void
     958           0 : nsMathMLContainerFrame::MarkIntrinsicISizesDirty()
     959             : {
     960           0 :   mIntrinsicWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
     961           0 :   nsContainerFrame::MarkIntrinsicISizesDirty();
     962           0 : }
     963             : 
     964             : void
     965           0 : nsMathMLContainerFrame::UpdateIntrinsicWidth(gfxContext* aRenderingContext)
     966             : {
     967           0 :   if (mIntrinsicWidth == NS_INTRINSIC_WIDTH_UNKNOWN) {
     968           0 :     ReflowOutput desiredSize(GetWritingMode());
     969           0 :     GetIntrinsicISizeMetrics(aRenderingContext, desiredSize);
     970             : 
     971             :     // Include the additional width added by FixInterFrameSpacing to ensure
     972             :     // consistent width calculations.
     973           0 :     AddInterFrameSpacingToSize(desiredSize, this);
     974           0 :     mIntrinsicWidth = desiredSize.ISize(GetWritingMode());
     975             :   }
     976           0 : }
     977             : 
     978             : /* virtual */ nscoord
     979           0 : nsMathMLContainerFrame::GetMinISize(gfxContext* aRenderingContext)
     980             : {
     981             :   nscoord result;
     982           0 :   DISPLAY_MIN_WIDTH(this, result);
     983           0 :   UpdateIntrinsicWidth(aRenderingContext);
     984           0 :   result = mIntrinsicWidth;
     985           0 :   return result;
     986             : }
     987             : 
     988             : /* virtual */ nscoord
     989           0 : nsMathMLContainerFrame::GetPrefISize(gfxContext* aRenderingContext)
     990             : {
     991             :   nscoord result;
     992           0 :   DISPLAY_PREF_WIDTH(this, result);
     993           0 :   UpdateIntrinsicWidth(aRenderingContext);
     994           0 :   result = mIntrinsicWidth;
     995           0 :   return result;
     996             : }
     997             : 
     998             : /* virtual */ void
     999           0 : nsMathMLContainerFrame::GetIntrinsicISizeMetrics(gfxContext* aRenderingContext,
    1000             :                                                  ReflowOutput& aDesiredSize)
    1001             : {
    1002             :   // Get child widths
    1003           0 :   nsIFrame* childFrame = mFrames.FirstChild();
    1004           0 :   while (childFrame) {
    1005           0 :     ReflowOutput childDesiredSize(GetWritingMode()); // ???
    1006             : 
    1007           0 :     nsMathMLContainerFrame* containerFrame = do_QueryFrame(childFrame);
    1008           0 :     if (containerFrame) {
    1009             :       containerFrame->GetIntrinsicISizeMetrics(aRenderingContext,
    1010           0 :                                                childDesiredSize);
    1011             :     } else {
    1012             :       // XXX This includes margin while Reflow currently doesn't consider
    1013             :       // margin, so we may end up with too much space, but, with stretchy
    1014             :       // characters, this is an approximation anyway.
    1015             :       nscoord width =
    1016             :         nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
    1017           0 :                                              nsLayoutUtils::PREF_ISIZE);
    1018             : 
    1019           0 :       childDesiredSize.Width() = width;
    1020           0 :       childDesiredSize.mBoundingMetrics.width = width;
    1021           0 :       childDesiredSize.mBoundingMetrics.leftBearing = 0;
    1022           0 :       childDesiredSize.mBoundingMetrics.rightBearing = width;
    1023             : 
    1024             :       nscoord x, xMost;
    1025           0 :       if (NS_SUCCEEDED(childFrame->GetPrefWidthTightBounds(aRenderingContext,
    1026             :                                                            &x, &xMost))) {
    1027           0 :         childDesiredSize.mBoundingMetrics.leftBearing = x;
    1028           0 :         childDesiredSize.mBoundingMetrics.rightBearing = xMost;
    1029             :       }
    1030             :     }
    1031             : 
    1032             :     SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
    1033           0 :                                     childDesiredSize.mBoundingMetrics);
    1034             : 
    1035           0 :     childFrame = childFrame->GetNextSibling();
    1036             :   }
    1037             : 
    1038             :   // Measure
    1039           0 :   nsresult rv = MeasureForWidth(aRenderingContext->GetDrawTarget(), aDesiredSize);
    1040           0 :   if (NS_FAILED(rv)) {
    1041           0 :     ReflowError(aRenderingContext->GetDrawTarget(), aDesiredSize);
    1042             :   }
    1043             : 
    1044           0 :   ClearSavedChildMetrics();
    1045           0 : }
    1046             : 
    1047             : /* virtual */ nsresult
    1048           0 : nsMathMLContainerFrame::MeasureForWidth(DrawTarget* aDrawTarget,
    1049             :                                         ReflowOutput& aDesiredSize)
    1050             : {
    1051           0 :   return Place(aDrawTarget, false, aDesiredSize);
    1052             : }
    1053             : 
    1054             : 
    1055             : // see spacing table in Chapter 18, TeXBook (p.170)
    1056             : // Our table isn't quite identical to TeX because operators have
    1057             : // built-in values for lspace & rspace in the Operator Dictionary.
    1058             : static int32_t kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] =
    1059             : {
    1060             :   // in units of muspace.
    1061             :   // upper half of the byte is set if the
    1062             :   // spacing is not to be used for scriptlevel > 0
    1063             : 
    1064             :   /*           Ord  OpOrd OpInv OpUsr Inner Italic Upright */
    1065             :   /*Ord  */   {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00},
    1066             :   /*OpOrd*/   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    1067             :   /*OpInv*/   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    1068             :   /*OpUsr*/   {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
    1069             :   /*Inner*/   {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
    1070             :   /*Italic*/  {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01},
    1071             :   /*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00}
    1072             : };
    1073             : 
    1074             : #define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_)  \
    1075             :    /* no space if there is a frame that we know nothing about */        \
    1076             :    if (frametype1_ == eMathMLFrameType_UNKNOWN ||                       \
    1077             :        frametype2_ == eMathMLFrameType_UNKNOWN)                         \
    1078             :     space_ = 0;                                                         \
    1079             :   else {                                                                \
    1080             :     space_ = kInterFrameSpacingTable[frametype1_][frametype2_];         \
    1081             :     space_ = (scriptlevel_ > 0 && (space_ & 0xF0))                      \
    1082             :       ? 0 /* spacing is disabled */                                     \
    1083             :       : space_ & 0x0F;                                                  \
    1084             :   }                                                                     \
    1085             : 
    1086             : // This function computes the inter-space between two frames. However,
    1087             : // since invisible operators need special treatment, the inter-space may
    1088             : // be delayed when an invisible operator is encountered. In this case,
    1089             : // the function will carry the inter-space forward until it is determined
    1090             : // that it can be applied properly (i.e., until we encounter a visible
    1091             : // frame where to decide whether to accept or reject the inter-space).
    1092             : // aFromFrameType: remembers the frame when the carry-forward initiated.
    1093             : // aCarrySpace: keeps track of the inter-space that is delayed.
    1094             : // @returns: current inter-space (which is 0 when the true inter-space is
    1095             : // delayed -- and thus has no effect since the frame is invisible anyway).
    1096             : static nscoord
    1097           0 : GetInterFrameSpacing(int32_t           aScriptLevel,
    1098             :                      eMathMLFrameType  aFirstFrameType,
    1099             :                      eMathMLFrameType  aSecondFrameType,
    1100             :                      eMathMLFrameType* aFromFrameType, // IN/OUT
    1101             :                      int32_t*          aCarrySpace)    // IN/OUT
    1102             : {
    1103           0 :   eMathMLFrameType firstType = aFirstFrameType;
    1104           0 :   eMathMLFrameType secondType = aSecondFrameType;
    1105             : 
    1106             :   int32_t space;
    1107           0 :   GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
    1108             : 
    1109             :   // feedback control to avoid the inter-space to be added when not necessary
    1110           0 :   if (secondType == eMathMLFrameType_OperatorInvisible) {
    1111             :     // see if we should start to carry the space forward until we
    1112             :     // encounter a visible frame
    1113           0 :     if (*aFromFrameType == eMathMLFrameType_UNKNOWN) {
    1114           0 :       *aFromFrameType = firstType;
    1115           0 :       *aCarrySpace = space;
    1116             :     }
    1117             :     // keep carrying *aCarrySpace forward, while returning 0 for this stage
    1118           0 :     space = 0;
    1119             :   }
    1120           0 :   else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) {
    1121             :     // no carry-forward anymore, get the real inter-space between
    1122             :     // the two frames of interest
    1123             : 
    1124           0 :     firstType = *aFromFrameType;
    1125             : 
    1126             :     // But... the invisible operator that we encountered earlier could
    1127             :     // be sitting between italic and upright identifiers, e.g.,
    1128             :     //
    1129             :     // 1. <mi>sin</mi> <mo>&ApplyFunction;</mo> <mi>x</mi>
    1130             :     // 2. <mi>x</mi> <mo>&InvisibileTime;</mo> <mi>sin</mi>
    1131             :     //
    1132             :     // the trick to get the inter-space in either situation
    1133             :     // is to promote "<mi>sin</mi><mo>&ApplyFunction;</mo>" and
    1134             :     // "<mo>&InvisibileTime;</mo><mi>sin</mi>" to user-defined operators...
    1135           0 :     if (firstType == eMathMLFrameType_UprightIdentifier) {
    1136           0 :       firstType = eMathMLFrameType_OperatorUserDefined;
    1137             :     }
    1138           0 :     else if (secondType == eMathMLFrameType_UprightIdentifier) {
    1139           0 :       secondType = eMathMLFrameType_OperatorUserDefined;
    1140             :     }
    1141             : 
    1142           0 :     GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
    1143             : 
    1144             :     // Now, we have two values: the computed space and the space that
    1145             :     // has been carried forward until now. Which value do we pick?
    1146             :     // If the second type is an operator (e.g., fence), it already has
    1147             :     // built-in lspace & rspace, so we let them win. Otherwise we pick
    1148             :     // the max between the two values that we have.
    1149           0 :     if (secondType != eMathMLFrameType_OperatorOrdinary &&
    1150           0 :         space < *aCarrySpace)
    1151           0 :       space = *aCarrySpace;
    1152             : 
    1153             :     // reset everything now that the carry-forward is done
    1154           0 :     *aFromFrameType = eMathMLFrameType_UNKNOWN;
    1155           0 :     *aCarrySpace = 0;
    1156             :   }
    1157             : 
    1158           0 :   return space;
    1159             : }
    1160             : 
    1161           0 : static nscoord GetThinSpace(const nsStyleFont* aStyleFont)
    1162             : {
    1163           0 :   return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18));
    1164             : }
    1165             : 
    1166           0 : class nsMathMLContainerFrame::RowChildFrameIterator {
    1167             : public:
    1168           0 :   explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) :
    1169             :     mParentFrame(aParentFrame),
    1170             :     mReflowOutput(aParentFrame->GetWritingMode()),
    1171             :     mX(0),
    1172             :     mCarrySpace(0),
    1173             :     mFromFrameType(eMathMLFrameType_UNKNOWN),
    1174           0 :     mRTL(aParentFrame->StyleVisibility()->mDirection)
    1175             :   {
    1176           0 :     if (!mRTL) {
    1177           0 :       mChildFrame = aParentFrame->mFrames.FirstChild();
    1178             :     } else {
    1179           0 :       mChildFrame = aParentFrame->mFrames.LastChild();
    1180             :     }
    1181             : 
    1182           0 :     if (!mChildFrame)
    1183           0 :       return;
    1184             : 
    1185           0 :     InitMetricsForChild();
    1186             :   }
    1187             : 
    1188           0 :   RowChildFrameIterator& operator++()
    1189             :   {
    1190             :     // add child size + italic correction
    1191           0 :     mX += mReflowOutput.mBoundingMetrics.width + mItalicCorrection;
    1192             : 
    1193           0 :     if (!mRTL) {
    1194           0 :       mChildFrame = mChildFrame->GetNextSibling();
    1195             :     } else {
    1196           0 :       mChildFrame = mChildFrame->GetPrevSibling();
    1197             :     }
    1198             : 
    1199           0 :     if (!mChildFrame)
    1200           0 :       return *this;
    1201             : 
    1202           0 :     eMathMLFrameType prevFrameType = mChildFrameType;
    1203           0 :     InitMetricsForChild();
    1204             : 
    1205             :     // add inter frame spacing
    1206           0 :     const nsStyleFont* font = mParentFrame->StyleFont();
    1207             :     nscoord space =
    1208           0 :       GetInterFrameSpacing(font->mScriptLevel,
    1209             :                            prevFrameType, mChildFrameType,
    1210           0 :                            &mFromFrameType, &mCarrySpace);
    1211           0 :     mX += space * GetThinSpace(font);
    1212           0 :     return *this;
    1213             :   }
    1214             : 
    1215           0 :   nsIFrame* Frame() const { return mChildFrame; }
    1216           0 :   nscoord X() const { return mX; }
    1217           0 :   const ReflowOutput& GetReflowOutput() const { return mReflowOutput; }
    1218           0 :   nscoord Ascent() const { return mReflowOutput.BlockStartAscent(); }
    1219           0 :   nscoord Descent() const { return mReflowOutput.Height() - mReflowOutput.BlockStartAscent(); }
    1220           0 :   const nsBoundingMetrics& BoundingMetrics() const {
    1221           0 :     return mReflowOutput.mBoundingMetrics;
    1222             :   }
    1223             : 
    1224             : private:
    1225             :   const nsMathMLContainerFrame* mParentFrame;
    1226             :   nsIFrame* mChildFrame;
    1227             :   ReflowOutput mReflowOutput;
    1228             :   nscoord mX;
    1229             : 
    1230             :   nscoord mItalicCorrection;
    1231             :   eMathMLFrameType mChildFrameType;
    1232             :   int32_t mCarrySpace;
    1233             :   eMathMLFrameType mFromFrameType;
    1234             : 
    1235             :   bool mRTL;
    1236             : 
    1237           0 :   void InitMetricsForChild()
    1238             :   {
    1239           0 :     GetReflowAndBoundingMetricsFor(mChildFrame, mReflowOutput, mReflowOutput.mBoundingMetrics,
    1240           0 :                                    &mChildFrameType);
    1241             :     nscoord leftCorrection, rightCorrection;
    1242           0 :     GetItalicCorrection(mReflowOutput.mBoundingMetrics,
    1243           0 :                         leftCorrection, rightCorrection);
    1244           0 :     if (!mChildFrame->GetPrevSibling() &&
    1245           0 :         mParentFrame->GetContent()->IsMathMLElement(nsGkAtoms::msqrt_)) {
    1246             :       // Remove leading correction in <msqrt> because the sqrt glyph itself is
    1247             :       // there first.
    1248           0 :       if (!mRTL) {
    1249           0 :         leftCorrection = 0;
    1250             :       } else {
    1251           0 :         rightCorrection = 0;
    1252             :       }
    1253             :     }
    1254             :     // add left correction -- this fixes the problem of the italic 'f'
    1255             :     // e.g., <mo>q</mo> <mi>f</mi> <mo>I</mo>
    1256           0 :     mX += leftCorrection;
    1257           0 :     mItalicCorrection = rightCorrection;
    1258           0 :   }
    1259             : };
    1260             : 
    1261             : /* virtual */ nsresult
    1262           0 : nsMathMLContainerFrame::Place(DrawTarget*          aDrawTarget,
    1263             :                               bool                 aPlaceOrigin,
    1264             :                               ReflowOutput& aDesiredSize)
    1265             : {
    1266             :   // This is needed in case this frame is empty (i.e., no child frames)
    1267           0 :   mBoundingMetrics = nsBoundingMetrics();
    1268             : 
    1269           0 :   RowChildFrameIterator child(this);
    1270           0 :   nscoord ascent = 0, descent = 0;
    1271           0 :   while (child.Frame()) {
    1272           0 :     if (descent < child.Descent())
    1273           0 :       descent = child.Descent();
    1274           0 :     if (ascent < child.Ascent())
    1275           0 :       ascent = child.Ascent();
    1276             :     // add the child size
    1277           0 :     mBoundingMetrics.width = child.X();
    1278           0 :     mBoundingMetrics += child.BoundingMetrics();
    1279           0 :     ++child;
    1280             :   }
    1281             :   // Add the italic correction at the end (including the last child).
    1282             :   // This gives a nice gap between math and non-math frames, and still
    1283             :   // gives the same math inter-spacing in case this frame connects to
    1284             :   // another math frame
    1285           0 :   mBoundingMetrics.width = child.X();
    1286             : 
    1287           0 :   aDesiredSize.Width() = std::max(0, mBoundingMetrics.width);
    1288           0 :   aDesiredSize.Height() = ascent + descent;
    1289           0 :   aDesiredSize.SetBlockStartAscent(ascent);
    1290           0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
    1291             : 
    1292           0 :   mReference.x = 0;
    1293           0 :   mReference.y = aDesiredSize.BlockStartAscent();
    1294             : 
    1295             :   //////////////////
    1296             :   // Place Children
    1297             : 
    1298           0 :   if (aPlaceOrigin) {
    1299           0 :     PositionRowChildFrames(0, aDesiredSize.BlockStartAscent());
    1300             :   }
    1301             : 
    1302           0 :   return NS_OK;
    1303             : }
    1304             : 
    1305             : void
    1306           0 : nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX,
    1307             :                                                nscoord aBaseline)
    1308             : {
    1309           0 :   RowChildFrameIterator child(this);
    1310           0 :   while (child.Frame()) {
    1311           0 :     nscoord dx = aOffsetX + child.X();
    1312           0 :     nscoord dy = aBaseline - child.Ascent();
    1313           0 :     FinishReflowChild(child.Frame(), PresContext(), child.GetReflowOutput(),
    1314           0 :                       nullptr, dx, dy, 0);
    1315           0 :     ++child;
    1316             :   }
    1317           0 : }
    1318             : 
    1319             : // helpers to fix the inter-spacing when <math> is the only parent
    1320             : // e.g., it fixes <math> <mi>f</mi> <mo>q</mo> <mi>f</mi> <mo>I</mo> </math>
    1321             : 
    1322             : static nscoord
    1323           0 : GetInterFrameSpacingFor(int32_t         aScriptLevel,
    1324             :                         nsIFrame*       aParentFrame,
    1325             :                         nsIFrame*       aChildFrame)
    1326             : {
    1327           0 :   nsIFrame* childFrame = aParentFrame->PrincipalChildList().FirstChild();
    1328           0 :   if (!childFrame || aChildFrame == childFrame)
    1329           0 :     return 0;
    1330             : 
    1331           0 :   int32_t carrySpace = 0;
    1332           0 :   eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN;
    1333           0 :   eMathMLFrameType prevFrameType = eMathMLFrameType_UNKNOWN;
    1334           0 :   eMathMLFrameType childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
    1335           0 :   childFrame = childFrame->GetNextSibling();
    1336           0 :   while (childFrame) {
    1337           0 :     prevFrameType = childFrameType;
    1338           0 :     childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
    1339             :     nscoord space = GetInterFrameSpacing(aScriptLevel,
    1340           0 :       prevFrameType, childFrameType, &fromFrameType, &carrySpace);
    1341           0 :     if (aChildFrame == childFrame) {
    1342             :       // get thinspace
    1343           0 :       nsStyleContext* parentContext = aParentFrame->StyleContext();
    1344           0 :       nscoord thinSpace = GetThinSpace(parentContext->StyleFont());
    1345             :       // we are done
    1346           0 :       return space * thinSpace;
    1347             :     }
    1348           0 :     childFrame = childFrame->GetNextSibling();
    1349             :   }
    1350             : 
    1351           0 :   NS_NOTREACHED("child not in the childlist of its parent");
    1352           0 :   return 0;
    1353             : }
    1354             : 
    1355             : static nscoord
    1356           0 : AddInterFrameSpacingToSize(ReflowOutput&    aDesiredSize,
    1357             :                            nsMathMLContainerFrame* aFrame)
    1358             : {
    1359           0 :   nscoord gap = 0;
    1360           0 :   nsIFrame* parent = aFrame->GetParent();
    1361           0 :   nsIContent* parentContent = parent->GetContent();
    1362           0 :   if (MOZ_UNLIKELY(!parentContent)) {
    1363           0 :     return 0;
    1364             :   }
    1365           0 :   if (parentContent->IsAnyOfMathMLElements(nsGkAtoms::math,
    1366             :                                            nsGkAtoms::mtd_)) {
    1367           0 :     gap = GetInterFrameSpacingFor(aFrame->StyleFont()->mScriptLevel,
    1368           0 :                                   parent, aFrame);
    1369             :     // add our own italic correction
    1370           0 :     nscoord leftCorrection = 0, italicCorrection = 0;
    1371           0 :     aFrame->GetItalicCorrection(aDesiredSize.mBoundingMetrics,
    1372           0 :                                 leftCorrection, italicCorrection);
    1373           0 :     gap += leftCorrection;
    1374           0 :     if (gap) {
    1375           0 :       aDesiredSize.mBoundingMetrics.leftBearing += gap;
    1376           0 :       aDesiredSize.mBoundingMetrics.rightBearing += gap;
    1377           0 :       aDesiredSize.mBoundingMetrics.width += gap;
    1378           0 :       aDesiredSize.Width() += gap;
    1379             :     }
    1380           0 :     aDesiredSize.mBoundingMetrics.width += italicCorrection;
    1381           0 :     aDesiredSize.Width() += italicCorrection;
    1382             :   }
    1383           0 :   return gap;
    1384             : }
    1385             : 
    1386             : nscoord
    1387           0 : nsMathMLContainerFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
    1388             : {
    1389           0 :   nscoord gap = 0;
    1390           0 :   gap = AddInterFrameSpacingToSize(aDesiredSize, this);
    1391           0 :   if (gap) {
    1392             :     // Shift our children to account for the correction
    1393           0 :     nsIFrame* childFrame = mFrames.FirstChild();
    1394           0 :     while (childFrame) {
    1395           0 :       childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0));
    1396           0 :       childFrame = childFrame->GetNextSibling();
    1397             :     }
    1398             :   }
    1399           0 :   return gap;
    1400             : }
    1401             : 
    1402             : /* static */ void
    1403           0 : nsMathMLContainerFrame::DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop)
    1404             : 
    1405             : {
    1406           0 :   if (MOZ_UNLIKELY(!aFirst))
    1407           0 :     return;
    1408             : 
    1409           0 :   for (nsIFrame* frame = aFirst;
    1410           0 :        frame != aStop;
    1411             :        frame = frame->GetNextSibling()) {
    1412           0 :     NS_ASSERTION(frame, "aStop isn't a sibling");
    1413           0 :     if (frame->GetStateBits() & NS_FRAME_IN_REFLOW) {
    1414             :       // finish off principal descendants, too
    1415           0 :       nsIFrame* grandchild = frame->PrincipalChildList().FirstChild();
    1416           0 :       if (grandchild)
    1417           0 :         DidReflowChildren(grandchild, nullptr);
    1418             : 
    1419           0 :       frame->DidReflow(frame->PresContext(), nullptr,
    1420           0 :                        nsDidReflowStatus::FINISHED);
    1421             :     }
    1422             :   }
    1423             : }
    1424             : 
    1425             : // helper used by mstyle, mphantom, mpadded and mrow in their implementations
    1426             : // of TransmitAutomaticData().
    1427             : nsresult
    1428           0 : nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement()
    1429             : {
    1430             :   //
    1431             :   // One loop to check both conditions below:
    1432             :   //
    1433             :   // 1) whether all the children of the mrow-like element are space-like.
    1434             :   //
    1435             :   //   The REC defines the following elements to be "space-like":
    1436             :   //   * an mstyle, mphantom, or mpadded element, all of whose direct
    1437             :   //     sub-expressions are space-like;
    1438             :   //   * an mrow all of whose direct sub-expressions are space-like.
    1439             :   //
    1440             :   // 2) whether all but one child of the mrow-like element are space-like and
    1441             :   //    this non-space-like child is an embellished operator.
    1442             :   //
    1443             :   //   The REC defines the following elements to be embellished operators:
    1444             :   //   * one of the elements mstyle, mphantom, or mpadded, such that an mrow
    1445             :   //     containing the same arguments would be an embellished operator;
    1446             :   //   * an mrow whose arguments consist (in any order) of one embellished
    1447             :   //     operator and zero or more space-like elements.
    1448             :   //
    1449             :   nsIFrame *childFrame, *baseFrame;
    1450           0 :   bool embellishedOpFound = false;
    1451           0 :   nsEmbellishData embellishData;
    1452             : 
    1453           0 :   for (childFrame = PrincipalChildList().FirstChild();
    1454           0 :        childFrame;
    1455             :        childFrame = childFrame->GetNextSibling()) {
    1456           0 :     nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
    1457           0 :     if (!mathMLFrame) break;
    1458           0 :     if (!mathMLFrame->IsSpaceLike()) {
    1459           0 :       if (embellishedOpFound) break;
    1460           0 :       baseFrame = childFrame;
    1461           0 :       GetEmbellishDataFrom(baseFrame, embellishData);
    1462           0 :       if (!NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)) break;
    1463           0 :       embellishedOpFound = true;
    1464             :     }
    1465             :   }
    1466             : 
    1467           0 :   if (!childFrame) {
    1468             :     // we successfully went to the end of the loop. This means that one of
    1469             :     // condition 1) or 2) holds.
    1470           0 :     if (!embellishedOpFound) {
    1471             :       // the mrow-like element is space-like.
    1472           0 :       mPresentationData.flags |= NS_MATHML_SPACE_LIKE;
    1473             :     } else {
    1474             :       // the mrow-like element is an embellished operator.
    1475             :       // let the state of the embellished operator found bubble to us.
    1476           0 :       mPresentationData.baseFrame = baseFrame;
    1477           0 :       mEmbellishData = embellishData;
    1478             :     }
    1479             :   }
    1480             : 
    1481           0 :   if (childFrame || !embellishedOpFound) {
    1482             :     // The element is not embellished operator
    1483           0 :     mPresentationData.baseFrame = nullptr;
    1484           0 :     mEmbellishData.flags = 0;
    1485           0 :     mEmbellishData.coreFrame = nullptr;
    1486           0 :     mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
    1487           0 :     mEmbellishData.leadingSpace = 0;
    1488           0 :     mEmbellishData.trailingSpace = 0;
    1489             :   }
    1490             : 
    1491           0 :   if (childFrame || embellishedOpFound) {
    1492             :     // The element is not space-like
    1493           0 :     mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE;
    1494             :   }
    1495             : 
    1496           0 :   return NS_OK;
    1497             : }
    1498             : 
    1499             : /*static*/ void
    1500           0 : nsMathMLContainerFrame::PropagateFrameFlagFor(nsIFrame* aFrame,
    1501             :                                               nsFrameState  aFlags)
    1502             : {
    1503           0 :   if (!aFrame || !aFlags)
    1504           0 :     return;
    1505             : 
    1506           0 :   aFrame->AddStateBits(aFlags);
    1507           0 :   for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
    1508           0 :     PropagateFrameFlagFor(childFrame, aFlags);
    1509             :   }
    1510             : }
    1511             : 
    1512             : nsresult
    1513           0 : nsMathMLContainerFrame::ReportErrorToConsole(const char*       errorMsgId,
    1514             :                                              const char16_t** aParams,
    1515             :                                              uint32_t          aParamCount)
    1516             : {
    1517           0 :   return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
    1518           0 :                                          NS_LITERAL_CSTRING("Layout: MathML"), mContent->OwnerDoc(),
    1519             :                                          nsContentUtils::eMATHML_PROPERTIES,
    1520           0 :                                          errorMsgId, aParams, aParamCount);
    1521             : }
    1522             : 
    1523             : nsresult
    1524           0 : nsMathMLContainerFrame::ReportParseError(const char16_t* aAttribute,
    1525             :                                          const char16_t* aValue)
    1526             : {
    1527             :   const char16_t* argv[] =
    1528           0 :     { aValue, aAttribute, mContent->NodeInfo()->NameAtom()->GetUTF16String() };
    1529           0 :   return ReportErrorToConsole("AttributeParsingError", argv, 3);
    1530             : }
    1531             : 
    1532             : nsresult
    1533           0 : nsMathMLContainerFrame::ReportChildCountError()
    1534             : {
    1535           0 :   const char16_t* arg = mContent->NodeInfo()->NameAtom()->GetUTF16String();
    1536           0 :   return ReportErrorToConsole("ChildCountIncorrect", &arg, 1);
    1537             : }
    1538             : 
    1539             : nsresult
    1540           0 : nsMathMLContainerFrame::ReportInvalidChildError(nsIAtom* aChildTag)
    1541             : {
    1542             :   const char16_t* argv[] =
    1543           0 :     { aChildTag->GetUTF16String(),
    1544           0 :       mContent->NodeInfo()->NameAtom()->GetUTF16String() };
    1545           0 :   return ReportErrorToConsole("InvalidChild", argv, 2);
    1546             : }
    1547             : 
    1548             : //==========================
    1549             : 
    1550             : nsContainerFrame*
    1551           0 : NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1552             : {
    1553           0 :   return new (aPresShell) nsMathMLmathBlockFrame(aContext);
    1554             : }
    1555             : 
    1556           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathBlockFrame)
    1557             : 
    1558           0 : NS_QUERYFRAME_HEAD(nsMathMLmathBlockFrame)
    1559           0 :   NS_QUERYFRAME_ENTRY(nsMathMLmathBlockFrame)
    1560           0 : NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
    1561             : 
    1562             : nsContainerFrame*
    1563           0 : NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1564             : {
    1565           0 :   return new (aPresShell) nsMathMLmathInlineFrame(aContext);
    1566             : }
    1567             : 
    1568           0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathInlineFrame)
    1569             : 
    1570           0 : NS_QUERYFRAME_HEAD(nsMathMLmathInlineFrame)
    1571           0 :   NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
    1572           0 : NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame)

Generated by: LCOV version 1.13