Bug 348577 - Implement MathML <mtable> with display:inline-table (mtable has incorrect baseline). Patch by Bill Gianopoulos <wgianopoulos@yahoo.com>, r=rbs, sr=bzbarsky.
authorkarlt+@karlt.net
Tue, 08 Jan 2008 18:14:35 -0800
changeset 10035 be20678b7a2e29052beaaeab6de0482b5f7d6942
parent 10034 cc9d1af1733f9061c8d0458fbfdf237c42cf4559
child 10036 5701f888686628e488855235c884182f0f14c24b
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrbs, bzbarsky
bugs348577
milestone1.9b3pre
Bug 348577 - Implement MathML <mtable> with display:inline-table (mtable has incorrect baseline). Patch by Bill Gianopoulos <wgianopoulos@yahoo.com>, r=rbs, sr=bzbarsky.
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/mathml/base/src/nsMathMLmrowFrame.cpp
layout/mathml/base/src/nsMathMLmrowFrame.h
layout/mathml/base/src/nsMathMLmtableFrame.cpp
layout/mathml/content/src/mathml.css
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2855,17 +2855,17 @@ nsCSSFrameConstructor::CreatePseudoTable
 
   nsPseudoFrameData& pseudoOuter = aState.mPseudoFrames.mTableOuter;
   nsPseudoFrameData& pseudoInner = aState.mPseudoFrames.mTableInner;
 
   // construct the pseudo outer and inner as part of the pseudo frames
   nsFrameItems items;
   rv = ConstructTableFrame(aState, parentContent,
                            parentFrame, childStyle, aNameSpaceID,
-                           PR_TRUE, items, PR_TRUE, pseudoOuter.mFrame, 
+                           PR_TRUE, items, pseudoOuter.mFrame, 
                            pseudoInner.mFrame);
 
   if (NS_FAILED(rv)) return rv;
 
   // set pseudo data for the newly created frames
   pseudoOuter.mChildList.AddChild(pseudoInner.mFrame);
   aState.mPseudoFrames.mLowestType = nsGkAtoms::tableFrame;
 
@@ -3484,18 +3484,16 @@ IsSpecialContent(nsIContent*     aConten
       aTag == nsGkAtoms::mstyle_ ||
       aTag == nsGkAtoms::msqrt_ ||
       aTag == nsGkAtoms::mroot_ ||
       aTag == nsGkAtoms::maction_ ||
       aTag == nsGkAtoms::mrow_   ||
       aTag == nsGkAtoms::merror_ ||
       aTag == nsGkAtoms::none   ||
       aTag == nsGkAtoms::mprescripts_ ||
-      (aTag == nsGkAtoms::mtable_ &&
-       aStyleContext->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_TABLE) ||
       aTag == nsGkAtoms::math;
 #endif
   return PR_FALSE;
 }
                                       
 nsresult
 nsCSSFrameConstructor::AdjustParentFrame(nsFrameConstructorState&     aState,
                                          nsIContent*                  aChildContent,
@@ -3590,17 +3588,16 @@ PullOutCaptionFrames(nsFrameItems& aItem
 nsresult
 nsCSSFrameConstructor::ConstructTableFrame(nsFrameConstructorState& aState,
                                            nsIContent*              aContent,
                                            nsIFrame*                aContentParent,
                                            nsStyleContext*          aStyleContext,
                                            PRInt32                  aNameSpaceID,
                                            PRBool                   aIsPseudo,
                                            nsFrameItems&            aChildItems,
-                                           PRBool                   aAllowOutOfFlow,
                                            nsIFrame*&               aNewOuterFrame,
                                            nsIFrame*&               aNewInnerFrame)
 {
   nsresult rv = NS_OK;
 
 
   // create the pseudo SC for the outer table as a child of the inner SC
   nsRefPtr<nsStyleContext> outerStyleContext;
@@ -3633,24 +3630,19 @@ nsCSSFrameConstructor::ConstructTableFra
                                       PR_FALSE, PR_FALSE);
       frameItems = &aState.mPseudoFrames.mCellInner.mChildList;
       if (aState.mPseudoFrames.mTableOuter.mFrame) {
         ProcessPseudoFrames(aState, nsGkAtoms::tableOuterFrame);
       }
     }
   }
 
-  // We need the aAllowOutOfFlow thing for MathML.  See bug 355993.
-  // Once bug 348577 is fixed, we should remove this code.  At that
-  // point, the aAllowOutOfFlow arg can go away.
-  nsIFrame* geometricParent =
-    aAllowOutOfFlow ?
-      aState.GetGeometricParent(outerStyleContext->GetStyleDisplay(),
-                                parentFrame) :
-      parentFrame;
+  nsIFrame* geometricParent = aState.GetGeometricParent
+                                (outerStyleContext->GetStyleDisplay(),
+                                 parentFrame);
 
   // Init the table outer frame and see if we need to create a view, e.g.
   // the frame is absolutely positioned  
   InitAndRestoreFrame(aState, aContent, geometricParent, nsnull, aNewOuterFrame);  
   nsHTMLContainerFrame::CreateViewForFrame(aNewOuterFrame, aContentParent,
                                            PR_FALSE);
 
   // Create the inner table frame
@@ -3664,18 +3656,17 @@ nsCSSFrameConstructor::ConstructTableFra
   InitAndRestoreFrame(aState, aContent, aNewOuterFrame, nsnull,
                       aNewInnerFrame);
 
   if (!aIsPseudo) {
     // Put the newly created frames into the right child list
     aNewOuterFrame->SetInitialChildList(nsnull, aNewInnerFrame);
 
     rv = aState.AddChild(aNewOuterFrame, *frameItems, aContent,
-                         aStyleContext, parentFrame, aAllowOutOfFlow,
-                         aAllowOutOfFlow);
+                         aStyleContext, parentFrame);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     nsFrameItems childItems;
     rv = ProcessChildren(aState, aContent, aNewInnerFrame, PR_FALSE, childItems,
                          PR_FALSE);
     // XXXbz what about cleaning up?
@@ -6656,18 +6647,18 @@ nsCSSFrameConstructor::ConstructFrameByD
     // Use the 'display' property to choose a frame type
     switch (aDisplay->mDisplay) {
     case NS_STYLE_DISPLAY_TABLE:
     case NS_STYLE_DISPLAY_INLINE_TABLE:
     {
       nsIFrame* innerTable;
       rv = ConstructTableFrame(aState, aContent, 
                                aParentFrame, aStyleContext,
-                               aNameSpaceID, PR_FALSE, aFrameItems, PR_TRUE,
-                               newFrame, innerTable);
+                               aNameSpaceID, PR_FALSE, aFrameItems, newFrame,
+                               innerTable);
       addedToFrameList = PR_TRUE;
       // Note: table construction function takes care of initializing
       // the frame, processing children, and setting the initial child
       // list
       break;
     }
   
     // the next 5 cases are only relevant if the parent is not a table, ConstructTableFrame handles children
@@ -6951,103 +6942,16 @@ nsCSSFrameConstructor::ConstructMathMLFr
     newFrame = NS_NewMathMLmsqrtFrame(mPresShell, aStyleContext);
   else if (aTag == nsGkAtoms::mroot_)
     newFrame = NS_NewMathMLmrootFrame(mPresShell, aStyleContext);
   else if (aTag == nsGkAtoms::maction_)
     newFrame = NS_NewMathMLmactionFrame(mPresShell, aStyleContext);
   else if (aTag == nsGkAtoms::mrow_ ||
            aTag == nsGkAtoms::merror_)
     newFrame = NS_NewMathMLmrowFrame(mPresShell, aStyleContext);
-  // CONSTRUCTION of MTABLE elements
-  else if (aTag == nsGkAtoms::mtable_ &&
-           disp->mDisplay == NS_STYLE_DISPLAY_TABLE) {
-    // <mtable> is an inline-table -- but this isn't yet supported.
-    // What we do here is to wrap the table in an anonymous containing
-    // block so that it can mix better with other surrounding MathML markups
-    // This assumes that the <mtable> is not positioned or floated.
-    // (MathML does not allow/support positioned or floated elements at all.)
-    // XXXbz once we stop doing this mess, fix IsSpecialContent accordingly.
-
-    nsStyleContext* parentContext = aParentFrame->GetStyleContext();
-    nsStyleSet *styleSet = mPresShell->StyleSet();
-
-    // first, create a MathML mrow frame that will wrap the block frame
-    nsRefPtr<nsStyleContext> mrowContext;
-    mrowContext = styleSet->ResolvePseudoStyleFor(aContent,
-                                                  nsCSSAnonBoxes::mozMathInline,
-                                                  parentContext);
-    newFrame = NS_NewMathMLmrowFrame(mPresShell, mrowContext);
-    if (NS_UNLIKELY(!newFrame)) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    InitAndRestoreFrame(aState, aContent, aParentFrame, nsnull, newFrame);
-
-    
-    nsRefPtr<nsStyleContext> blockContext;
-    blockContext = styleSet->ResolvePseudoStyleFor(aContent,
-                                                   nsCSSAnonBoxes::mozMathMLAnonymousBlock,
-                                                   mrowContext);
-    
-    // then, create a block frame that will wrap the table frame
-    nsIFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockContext,
-                                            NS_BLOCK_SPACE_MGR |
-                                            NS_BLOCK_MARGIN_ROOT);
-    if (NS_UNLIKELY(!blockFrame)) {
-      newFrame->Destroy();
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-    InitAndRestoreFrame(aState, aContent, newFrame, nsnull, blockFrame);
-
-    // then, create the table frame itself
-    nsRefPtr<nsStyleContext> tableContext =
-      ResolveStyleContext(blockFrame, aContent);
-
-    nsFrameItems tempItems;
-    nsIFrame* outerTable;
-    nsIFrame* innerTable;
-    
-    // XXXbz note: since we're constructing a table frame, and it does things
-    // based on whether its parent is a pseudo or not, we need to save our
-    // pseudo state here.  This can go away if we switch to a direct
-    // construction of mtable as an inline-table.
-    nsPseudoFrames priorPseudoFrames; 
-    aState.mPseudoFrames.Reset(&priorPseudoFrames);
-
-    // Pass PR_FALSE for aAllowOutOfFlow so that the resulting table will be
-    // guaranteed to be in-flow (and in particular, a descendant of the <math>
-    // in the _frame_ tree).
-    rv = ConstructTableFrame(aState, aContent, blockFrame, tableContext,
-                             aNameSpaceID, PR_FALSE, tempItems, PR_FALSE,
-                             outerTable, innerTable);
-    // Note: table construction function takes care of initializing the frame,
-    // processing children, and setting the initial child list
-
-    NS_ASSERTION(aState.mPseudoFrames.IsEmpty(),
-                 "How did we end up with pseudo-frames here?");
-
-    // restore the incoming pseudo frame state.  Note that we MUST do this
-    // before adding things to aFrameItems.
-    aState.mPseudoFrames = priorPseudoFrames;
-    
-    // set the outerTable as the initial child of the anonymous block
-    blockFrame->SetInitialChildList(nsnull, outerTable);
-
-    // set the block frame as the initial child of the mrow frame
-    newFrame->SetInitialChildList(nsnull, blockFrame);
-
-    // add the new frame to the flow
-    // XXXbz this is wrong.  What if it's out-of-flow?  For that matter, this
-    // is putting the frame in the wrong child list in the "pseudoParent ==
-    // PR_TRUE" case, which I assume we can hit.
-    aFrameItems.AddChild(newFrame);
-
-    return rv; 
-  }
-  // End CONSTRUCTION of MTABLE elements 
-
   else if (aTag == nsGkAtoms::math) { 
     // root <math> element
     const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
     PRBool isBlock = (NS_STYLE_DISPLAY_BLOCK == display->mDisplay);
     newFrame = NS_NewMathMLmathFrame(mPresShell, isBlock, aStyleContext);
   }
   else {
     return NS_OK;
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -319,27 +319,25 @@ private:
   // BEGIN TABLE SECTION
   /**
    * ConstructTableFrame will construct the outer and inner table frames and
    * return them.  Unless aIsPseudo is PR_TRUE, it will put the inner frame in
    * the child list of the outer frame, and will put any pseudo frames it had
    * to create into aChildItems.  The newly-created outer frame will either be
    * in aChildItems or a descendant of a pseudo in aChildItems (unless it's
    * positioned or floated, in which case its placeholder will be in
-   * aChildItems).  If aAllowOutOfFlow is false, the table frame will be forced
-   * to be in-flow no matter what its float or position values are.
+   * aChildItems).
    */ 
   nsresult ConstructTableFrame(nsFrameConstructorState& aState,
                                nsIContent*              aContent,
                                nsIFrame*                aContentParent,
                                nsStyleContext*          aStyleContext,
                                PRInt32                  aNameSpaceID,
                                PRBool                   aIsPseudo,
                                nsFrameItems&            aChildItems,
-                               PRBool                   aAllowOutOfFlow,
                                nsIFrame*&               aNewOuterFrame,
                                nsIFrame*&               aNewInnerFrame);
 
   nsresult ConstructTableCaptionFrame(nsFrameConstructorState& aState,
                                       nsIContent*              aContent,
                                       nsIFrame*                aParent,
                                       nsStyleContext*          aStyleContext,
                                       PRInt32                  aNameSpaceID,
--- a/layout/mathml/base/src/nsMathMLmrowFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmrowFrame.cpp
@@ -88,28 +88,8 @@ nsMathMLmrowFrame::AttributeChanged(PRIn
       if (frame->GetType() == nsGkAtoms::tableOuterFrame)
         return frame->AttributeChanged(aNameSpaceID, aAttribute, aModType);
     }
     NS_NOTREACHED("mtable wrapper without the real table frame");
   }
 
   return nsMathMLContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
-
-nsIFrame*
-nsMathMLmrowFrame::GetContentInsertionFrame()
-{
-  // Special for <mtable>: In the frame construction code, we also use
-  // this frame class as a wrapper for mtable. Hence, if we are asked 
-  // for the insertion frame in the context where we are such a wrapper,
-  // we should return the real frame intended for mtable
-  if (mContent->Tag() == nsGkAtoms::mtable_) {
-    nsIFrame* frame = mFrames.FirstChild();
-    for ( ; frame; frame = frame->GetFirstChild(nsnull)) {
-      // drill down to the real mtable
-      if (frame->GetType() == nsGkAtoms::tableOuterFrame)
-        return frame->GetContentInsertionFrame();
-    }
-    NS_NOTREACHED("mtable wrapper without the real table frame");
-  }
-
-  return nsMathMLContainerFrame::GetContentInsertionFrame();
-}
--- a/layout/mathml/base/src/nsMathMLmrowFrame.h
+++ b/layout/mathml/base/src/nsMathMLmrowFrame.h
@@ -51,19 +51,16 @@ class nsMathMLmrowFrame : public nsMathM
 public:
   friend nsIFrame* NS_NewMathMLmrowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   NS_IMETHOD
   AttributeChanged(PRInt32  aNameSpaceID,
                    nsIAtom* aAttribute,
                    PRInt32  aModType);
 
-  virtual nsIFrame*
-  GetContentInsertionFrame();
-
   NS_IMETHOD
   InheritAutomaticData(nsIFrame* aParent);
 
 protected:
   nsMathMLmrowFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
   virtual ~nsMathMLmrowFrame();
 
   virtual PRIntn GetSkipSides() const { return 0; }
--- a/layout/mathml/base/src/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/base/src/nsMathMLmtableFrame.cpp
@@ -140,29 +140,41 @@ GetValueAt(nsIFrame* aTableOrRowFrame,
   }
   PRInt32 count = valueList->mArray.Count();
   return (aRowOrColIndex < count)
          ? (PRUnichar*)(valueList->mArray[aRowOrColIndex])
          : (PRUnichar*)(valueList->mArray[count-1]);
 }
 
 #ifdef NS_DEBUG
+static PRBool
+IsTable(PRUint8 aDisplay)
+{
+  if ((aDisplay == NS_STYLE_DISPLAY_TABLE) ||
+      (aDisplay == NS_STYLE_DISPLAY_INLINE_TABLE))
+    return PR_TRUE;
+  return PR_FALSE;
+}
+
 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
   NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->GetStyleDisplay()->mDisplay, "internal error");
+#define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame) \
+  NS_ASSERTION(IsTable(_frame->GetStyleDisplay()->mDisplay), "internal error");
 #else
 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
+#define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame)
 #endif
 
 // map attributes that depend on the index of the row:
 // rowalign, rowlines, XXX need rowspacing too
 static void
 MapRowAttributesIntoCSS(nsIFrame* aTableFrame,
                         nsIFrame* aRowFrame)
 {
-  DEBUG_VERIFY_THAT_FRAME_IS(aTableFrame, TABLE);
+  DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
   DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
   PRInt32 rowIndex = ((nsTableRowFrame*)aRowFrame)->GetRowIndex();
   nsIContent* rowContent = aRowFrame->GetContent();
   PRUnichar* attr;
 
   // see if the rowalign attribute is not already set
   if (!rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowalign_) &&
       !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::MOZrowalign)) {
@@ -193,17 +205,17 @@ MapRowAttributesIntoCSS(nsIFrame* aTable
 
 // map attributes that depend on the index of the column:
 // columnalign, columnlines, XXX need columnwidth and columnspacing too
 static void
 MapColAttributesIntoCSS(nsIFrame* aTableFrame,
                         nsIFrame* aRowFrame,
                         nsIFrame* aCellFrame)
 {
-  DEBUG_VERIFY_THAT_FRAME_IS(aTableFrame, TABLE);
+  DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
   DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
   DEBUG_VERIFY_THAT_FRAME_IS(aCellFrame, TABLE_CELL);
   PRInt32 rowIndex, colIndex;
   ((nsTableCellFrame*)aCellFrame)->GetCellIndexes(rowIndex, colIndex);
   nsIContent* cellContent = aCellFrame->GetContent();
   PRUnichar* attr;
 
   // see if the columnalign attribute is not already set
--- a/layout/mathml/content/src/mathml.css
+++ b/layout/mathml/content/src/mathml.css
@@ -266,17 +266,17 @@ merror {
   background-color: lightyellow;
 }
 
 /**************************************************************************/
 /* mtable and its related tags                                            */
 /**************************************************************************/
 
 mtable {
-  display: table;
+  display: inline-table;
   border-collapse: separate;
   border-spacing: 0;
 }
 mtable[frame="none"] {
   border: none;
 }
 mtable[frame="solid"] {
   border: solid thin;