LCOV - code coverage report
Current view: directory - layout/mathml - nsMathMLContainerFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 603 3 0.5 %
Date: 2012-06-02 Functions: 68 3 4.4 %

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

Generated by: LCOV version 1.7