Bug 10209 - Part 5: Allow table elements to act as absolute positioning containers; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 09 May 2011 20:36:10 -0400
changeset 77840 34f184d2a6f8d1932016ac7cfb379b5bc60cb45b
parent 77839 d5ec6fead55bc937414a3f77dcdc97cf5ba7d2b5
child 77841 00f422b2cf36505e1ee8768e09997237be8294c0
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersroc
bugs10209
milestone10.0a1
Bug 10209 - Part 5: Allow table elements to act as absolute positioning containers; r=roc
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
layout/generic/crashtests/536692-1.xhtml
layout/generic/crashtests/crashtests.list
layout/generic/nsHTMLReflowState.cpp
layout/reftests/abs-pos/reftest.list
layout/reftests/abs-pos/table-1-ref.html
layout/reftests/abs-pos/table-1.html
layout/reftests/abs-pos/table-2-ref.html
layout/reftests/abs-pos/table-2.html
layout/reftests/bugs/reftest.list
layout/reftests/first-line/reftest.list
layout/tables/crashtests/512749-1.html
layout/tables/crashtests/crashtests.list
layout/tables/nsTableOuterFrame.cpp
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -27,17 +27,17 @@ load 191272-1.html
 load 199696-1.html
 load 217903-1.html
 load 223064-1.html
 load 234851-1.html
 load 234851-2.html
 load 241300-1.html
 load 243159-1.html
 load 243159-2.xhtml
-asserts(1) load 243519-1.html # bug 536692
+load 243519-1.html
 load 244490-1.html
 load 254367-1.html
 load 263359-1.html
 load 265027-1.html
 load 265736-1.html
 load 265736-2.html
 asserts(2) load 265899-1.html # bug 575011
 load 265973-1.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1749,17 +1749,16 @@ nsCSSFrameConstructor::CreateGeneratedCo
 // The term pseudo frame is being used instead of anonymous frame, since anonymous
 // frame has been used elsewhere to refer to frames that have generated content
 
 static bool
 IsTableRelated(nsIAtom* aParentType)
 {
   return
     nsGkAtoms::tableOuterFrame    == aParentType ||
-    nsGkAtoms::tableFrame         == aParentType ||
     nsGkAtoms::tableRowGroupFrame == aParentType ||
     nsGkAtoms::tableRowFrame      == aParentType ||
     nsGkAtoms::tableCaptionFrame  == aParentType ||
     nsGkAtoms::tableColGroupFrame == aParentType ||
     nsGkAtoms::tableColFrame      == aParentType ||
     IS_TABLE_CELL(aParentType);
 }
 
@@ -1939,16 +1938,25 @@ nsCSSFrameConstructor::ConstructTable(ns
 
   if (!mRootElementFrame) {
     // The frame we're constructing will be the root element frame.
     // Set mRootElementFrame before processing children.
     mRootElementFrame = newFrame;
   }
 
   nsFrameItems childItems;
+
+  // Process children
+  nsFrameConstructorSaveState absoluteSaveState;
+  const nsStyleDisplay* display = outerStyleContext->GetStyleDisplay();
+
+  // Mark the table frame as an absolute container if needed
+  if (display->IsPositioned()) {
+    aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
+  }
   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
     rv = ConstructFramesFromItemList(aState, aItem.mChildItems,
                                      innerFrame, childItems);
   } else {
     rv = ProcessChildren(aState, content, styleContext, innerFrame,
                          PR_TRUE, childItems, PR_FALSE, aItem.mPendingBinding);
   }
   // XXXbz what about cleaning up?
@@ -5529,17 +5537,25 @@ nsCSSFrameConstructor::GetAbsoluteContai
     }
     
     // Is it positioned?
     // If it's table-related then ignore it, because for the time
     // being table-related frames are not containers for absolutely
     // positioned child frames.
     const nsStyleDisplay* disp = frame->GetStyleDisplay();
 
-    if (disp->IsPositioned() && !IsTableRelated(frame->GetType())) {
+    if (disp->IsPositioned()) {
+      // For tables, return the outer frame table
+      if (frame->GetType() == nsGkAtoms::tableFrame) {
+        containingBlock = frame->GetParent();
+        break;
+      } else if (IsTableRelated(frame->GetType())) {
+        continue;
+      }
+
       // Find the outermost wrapped block under this frame
       for (nsIFrame* wrappedFrame = aFrame; wrappedFrame != frame->GetParent();
            wrappedFrame = wrappedFrame->GetParent()) {
         nsIAtom* frameType = wrappedFrame->GetType();
         if (nsGkAtoms::blockFrame == frameType ||
 #ifdef MOZ_XUL
             nsGkAtoms::XULLabelFrame == frameType ||
 #endif
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/536692-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body onload="document.removeChild(document.documentElement);">
+<table style="position: fixed;"><tr style="position: absolute;"></tr></table>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -312,16 +312,17 @@ load 515811-1.html
 load 517968.html
 load 519031.xhtml
 load 520340.html
 load 533379-1.html
 load 533379-2.html
 load 534082-1.html
 load 534366-1.html
 load 534366-2.html
+load 536692-1.xhtml
 load 541277-1.html
 load 541277-2.html
 load 541714-1.html
 load 541714-2.html
 load 542136-1.html
 load 545571-1.html
 load 547338.xul
 load 547843-1.xhtml
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -513,32 +513,35 @@ nsHTMLReflowState::InitFrameType()
 
   // Section 9.7 of the CSS2 spec indicates that absolute position
   // takes precedence over float which takes precedence over display.
   // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
   // Make sure the frame was actually moved out of the flow, and don't
 
   // just assume what the style says, because we might not have had a
   // useful float/absolute containing block
-  nsIFrame* frameToTest =
-    frame->GetType() == nsGkAtoms::tableFrame ? frame->GetParent() : frame;
+
+  DISPLAY_INIT_TYPE(frame, this);
 
-  DISPLAY_INIT_TYPE(frameToTest, this);
+  if (frame->GetType() == nsGkAtoms::tableFrame) {
+    mFrameType = NS_CSS_FRAME_TYPE_BLOCK;
+    return;
+  }
 
-  NS_ASSERTION(frameToTest->GetStyleDisplay()->IsAbsolutelyPositioned() ==
+  NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositioned() ==
                  disp->IsAbsolutelyPositioned(),
                "Unexpected position style");
-  NS_ASSERTION(frameToTest->GetStyleDisplay()->IsFloating() ==
+  NS_ASSERTION(frame->GetStyleDisplay()->IsFloating() ==
                  disp->IsFloating(), "Unexpected float style");
-  if (frameToTest->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+  if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
     if (disp->IsAbsolutelyPositioned()) {
       frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
       //XXXfr hack for making frames behave properly when in overflow container lists
       //      see bug 154892; need to revisit later
-      if (frameToTest->GetPrevInFlow())
+      if (frame->GetPrevInFlow())
         frameType = NS_CSS_FRAME_TYPE_BLOCK;
     }
     else if (disp->IsFloating()) {
       frameType = NS_CSS_FRAME_TYPE_FLOATING;
     } else {
       NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP,
                    "unknown out of flow frame type");
       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
@@ -1127,25 +1130,25 @@ void
 nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext* aPresContext,
                                            const nsHTMLReflowState* cbrs,
                                            nscoord containingBlockWidth,
                                            nscoord containingBlockHeight)
 {
   NS_PRECONDITION(containingBlockHeight != NS_AUTOHEIGHT,
                   "containing block height must be constrained");
 
-  nsIFrame* outOfFlow = 
-    frame->GetType() == nsGkAtoms::tableFrame ? frame->GetParent() : frame;
-  NS_ASSERTION(outOfFlow->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
+  NS_ASSERTION(frame->GetType() != nsGkAtoms::tableFrame,
+               "InitAbsoluteConstraints should not be called on table frames");
+  NS_ASSERTION(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                "Why are we here?");
 
   // Get the placeholder frame
   nsIFrame*     placeholderFrame;
 
-  placeholderFrame = aPresContext->PresShell()->GetPlaceholderFrameFor(outOfFlow);
+  placeholderFrame = aPresContext->PresShell()->GetPlaceholderFrameFor(frame);
   NS_ASSERTION(nsnull != placeholderFrame, "no placeholder frame");
 
   // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
   // 'auto', then compute the hypothetical box of where the element would
   // have been if it had been in the flow
   nsHypotheticalBox hypotheticalBox;
   if (((eStyleUnit_Auto == mStylePosition->mOffset.GetLeftUnit()) &&
        (eStyleUnit_Auto == mStylePosition->mOffset.GetRightUnit())) ||
--- a/layout/reftests/abs-pos/reftest.list
+++ b/layout/reftests/abs-pos/reftest.list
@@ -1,3 +1,5 @@
 == font-size-wrap.html font-size-wrap-ref.html
 == abs-pos-auto-margin-1.html abs-pos-auto-margin-1-ref.html
 == auto-offset-inline-block-1.html auto-offset-inline-block-1-ref.html
+== table-1.html table-1-ref.html
+== table-2.html table-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/table-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0">
+    <table style="position: relative; top: 100px; left: 50px; border: 1px solid red; width: 90px; height: 100px; border-spacing: 0">
+      <tr>
+        <td style="padding: 0">
+        </td>
+      </tr>
+    </table>
+    <div style="position: absolute; top: 110px; left: 70px; border: 1px solid green; width: 50px; height: 60px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/table-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0">
+    <table style="position: relative; top: 100px; left: 50px; border: 1px solid red; width: 90px; height: 100px; border-spacing: 0">
+      <tr>
+        <td style="padding: 0">
+          <div style="position: absolute; top: 10px; left: 20px; border: 1px solid green; width: 50px; height: 60px;"></div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/table-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0">
+    <table style="position: relative; top: 100px; left: 50px; border: 1px solid red; width: 90px; height: 100px; border-spacing: 0">
+      <caption>foo</caption>
+      <tr>
+        <td style="padding: 0">
+        </td>
+      </tr>
+    </table>
+    <div style="position: absolute; top: 110px; left: 70px; border: 1px solid green; width: 50px; height: 60px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/abs-pos/table-2.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <body style="margin: 0">
+    <table style="position: relative; top: 100px; left: 50px; border: 1px solid red; width: 90px; height: 100px; border-spacing: 0">
+      <caption>foo</caption>
+      <tr>
+        <td style="padding: 0">
+          <div style="position: absolute; top: 10px; left: 20px; border: 1px solid green; width: 50px; height: 60px;"></div>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1432,17 +1432,17 @@ random-if(d2d) == 523468-1.html 523468-1
 == 526463-1.html 526463-1-ref.html
 == 527464-1.html 527464-ref.html
 == 528038-1a.html 528038-1-ref.html
 == 528038-1b.html 528038-1-ref.html
 == 528038-1c.html 528038-1-ref.html
 == 528038-1d.html 528038-1-ref.html
 == 528038-1e.html 528038-1-ref.html
 == 528038-1f.html 528038-1-ref.html
-asserts(5) == 528038-2.html 528038-2-ref.html # bug 512749
+== 528038-2.html 528038-2-ref.html
 == 528096-1.html 528096-1-ref.html
 == 530686-1.html 530686-1-ref.html
 == 531098-1.html 531098-1-ref.html
 == 531371-1.html 531371-1-ref.html
 == 534526-1a.html 534526-1-ref.html
 == 534526-1b.html 534526-1-ref.html
 == 534804-1.html 534804-1-ref.html
 == 534808-1.html 534808-1-ref.html
--- a/layout/reftests/first-line/reftest.list
+++ b/layout/reftests/first-line/reftest.list
@@ -11,17 +11,17 @@ fails == out-of-flow-1d.html out-of-flow
 == parent-style-1.html parent-style-1-ref.html
 == parent-style-2.html parent-style-2-ref.html
 == parent-style-3.html parent-style-3-ref.html
 
 # stress-tests
 load stress-1.html # assertion test
 == stress-2.html stress-2-ref.html # assertion + rendering test
 load stress-3.html # assertion test
-asserts(2) load stress-4.html # assertion/crash test. existing assertions are bug 512749.
+load stress-4.html # assertion/crash test.
 load stress-5.html # assertion/crash test
 load stress-6.html # assertion/crash test
 load stress-7.html # assertion/crash test
 == stress-8.html stress-8-ref.html # assertion/crash test
 == stress-9.html stress-9-ref.html # assertion/crash test
 load stress-10.html # crash test
 == stress-11.xhtml stress-11-ref.xhtml
 
new file mode 100644
--- /dev/null
+++ b/layout/tables/crashtests/512749-1.html
@@ -0,0 +1,1 @@
+<html style="position:fixed"><table style="position:absolute"></table></html>
\ No newline at end of file
--- a/layout/tables/crashtests/crashtests.list
+++ b/layout/tables/crashtests/crashtests.list
@@ -75,17 +75,17 @@ load 391898-1.html
 load 391901-1.html
 load 392132-1.xhtml
 load 397448-1.html
 load 398157-1.xhtml
 load 399209-1.xhtml
 load 403249-1.html
 load 403579-1.html
 load 404301-1.xhtml
-asserts(1-2) load 408753-1.xhtml # Bug 512749
+load 408753-1.xhtml
 load 410426-1.html
 load 411582.xhtml
 load 413091.xhtml
 load 413180-1.html
 load 416845-1.xhtml
 load 416845-2.xhtml
 load 416845-3.html   
 asserts(12) load 420654-1.xhtml # Bug 575011
@@ -93,16 +93,17 @@ load 423514-1.xhtml
 load 430374.html
 load 444431-1.html
 load 448988-1.xhtml
 load 450311-1.html
 load 456041.html
 load 457115.html
 load 467141-1.html
 load 488388-1.html
+load 512749-1.html
 load 513732-1.html
 asserts(0-1) load 533380-1.xhtml # Bug 614457
 load 534716-1.html
 load 573354-1.xhtml
 load 576890-1.html
 load 576890-2.html
 load 576890-3.html
 asserts(0-3) load 595758-1.xhtml # Bug 453871
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -51,17 +51,17 @@
 #endif
 #include "nsIServiceManager.h"
 #include "nsIDOMNode.h"
 #include "nsDisplayList.h"
 #include "nsLayoutUtils.h"
 
 /* ----------- nsTableCaptionFrame ---------- */
 
-#define NS_TABLE_FRAME_CAPTION_LIST_INDEX 0
+#define NS_TABLE_FRAME_CAPTION_LIST_INDEX 1
 #define NO_SIDE 100
 
 // caption frame
 nsTableCaptionFrame::nsTableCaptionFrame(nsStyleContext* aContext):
   nsBlockFrame(aContext)
 {
   // shrink wrap 
   SetFlags(NS_BLOCK_FLOAT_MGR);
@@ -203,16 +203,17 @@ nsTableOuterFrame::CreateAccessible()
 nsTableOuterFrame::IsContainingBlock() const
 {
   return PR_FALSE;
 }
 
 void
 nsTableOuterFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
+  DestroyAbsoluteFrames(aDestructRoot);
   mCaptionFrames.DestroyFramesFrom(aDestructRoot);
   nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 nsFrameList
 nsTableOuterFrame::GetChildList(ChildListID aListID) const
 {
   if (aListID == kCaptionList) {
@@ -931,17 +932,16 @@ nsTableOuterFrame::UpdateReflowMetrics(P
   SetDesiredSize(aCaptionSide, aInnerMargin, aCaptionMargin,
                  aMet.width, aMet.height);
 
   aMet.SetOverflowAreasToDesiredBounds();
   ConsiderChildOverflow(aMet.mOverflowAreas, InnerTableFrame());
   if (mCaptionFrames.NotEmpty()) {
     ConsiderChildOverflow(aMet.mOverflowAreas, mCaptionFrames.FirstChild());
   }
-  FinishAndStoreOverflow(&aMet);
 }
 
 NS_METHOD nsTableOuterFrame::Reflow(nsPresContext*           aPresContext,
                                     nsHTMLReflowMetrics&     aDesiredSize,
                                     const nsHTMLReflowState& aOuterRS,
                                     nsReflowStatus&          aStatus)
 {
   DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame");
@@ -1124,17 +1124,18 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPr
                                 origInnerVisualOverflow, innerFirstReflow);
   if (mCaptionFrames.NotEmpty()) {
     nsTableFrame::InvalidateFrame(mCaptionFrames.FirstChild(), origCaptionRect,
                                   origCaptionVisualOverflow,
                                   captionFirstReflow);
   }
 
   UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin);
-  
+  FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRS, aStatus);
+
   // Return our desired rect
 
   NS_FRAME_SET_TRUNCATION(aStatus, aOuterRS, aDesiredSize);
   return rv;
 }
 
 nsIAtom*
 nsTableOuterFrame::GetType() const