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 79187 34f184d2a6f8d1932016ac7cfb379b5bc60cb45b
parent 79186 d5ec6fead55bc937414a3f77dcdc97cf5ba7d2b5
child 79188 00f422b2cf36505e1ee8768e09997237be8294c0
push id434
push userclegnitto@mozilla.com
push dateWed, 21 Dec 2011 12:10:54 +0000
treeherdermozilla-beta@bddb6ed8dd47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs10209
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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