Bug 1409114 - Part 10: Make sure we build display items for table parts where only the normal position is visible, since we may need to create background items for ancestors at that position. r=dbaron
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 20 May 2019 23:16:39 +0000
changeset 474636 1ca7d32474c635ae947a747fdc3eae8e22e3050b
parent 474635 1c9357112b30b32385452b1f8794980fd72fc4b4
child 474637 2543d1e28c3065ec2b0db16c59a69259d49e1d37
push id36042
push userdvarga@mozilla.com
push dateTue, 21 May 2019 04:19:40 +0000
treeherdermozilla-central@ca560ff55451 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1409114
milestone69.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 1409114 - Part 10: Make sure we build display items for table parts where only the normal position is visible, since we may need to create background items for ancestors at that position. r=dbaron Differential Revision: https://phabricator.services.mozilla.com/D29447
layout/generic/nsFrame.cpp
layout/reftests/position-relative/1409114-1-ref.html
layout/reftests/position-relative/1409114-1.html
layout/reftests/position-relative/1409114-2.html
layout/reftests/position-relative/1409114-3.html
layout/reftests/position-relative/reftest.list
layout/tables/nsTableFrame.h
layout/tables/nsTableRowGroupFrame.cpp
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3618,16 +3618,41 @@ static bool DescendIntoChild(nsDisplayLi
   if (aDirty.Intersects(overflow)) {
     return true;
   }
 
   if (aChild->ForceDescendIntoIfVisible() && aVisible.Intersects(overflow)) {
     return true;
   }
 
+  if (aChild->IsFrameOfType(nsIFrame::eTablePart)) {
+    // Relative positioning and transforms can cause table parts to move, but we
+    // will still paint the backgrounds for their ancestor parts under them at
+    // their 'normal' position. That means that we must consider the overflow
+    // rects at both positions.
+
+    // We convert the overflow rect into the nsTableFrame's coordinate
+    // space, applying the normal position offset at each step. Then we
+    // compare that against the builder's cached dirty rect in table
+    // coordinate space.
+    const nsIFrame* f = aChild;
+    nsRect normalPositionOverflowRelativeToTable = overflow;
+
+    while (f->IsFrameOfType(nsIFrame::eTablePart)) {
+      normalPositionOverflowRelativeToTable += f->GetNormalPosition();
+      f = f->GetParent();
+    }
+
+    nsDisplayTableBackgroundSet* tableBGs = aBuilder->GetTableBackgroundSet();
+    if (tableBGs &&
+        tableBGs->GetDirtyRect().Intersects(normalPositionOverflowRelativeToTable)) {
+      return true;
+    }
+  }
+
   return false;
 }
 
 void nsIFrame::BuildDisplayListForSimpleChild(nsDisplayListBuilder* aBuilder,
                                               nsIFrame* aChild,
                                               const nsDisplayListSet& aLists) {
   // This is the shortcut for frames been handled along the common
   // path, the most common one of THE COMMON CASE mentioned later.
new file mode 100644
--- /dev/null
+++ b/layout/reftests/position-relative/1409114-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table>
+  <col style="background:green">
+  <tr>
+    <td style="width:20px; height:20px"></td>
+  </tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/position-relative/1409114-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table>
+  <col style="background:green">
+  <tr>
+    <td style="position:relative; left:-100px; width:20px; height:20px"></td>
+  </tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/position-relative/1409114-2.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body style="overflow:hidden">
+<table style="position:relative; top:-50px">
+  <col style="background:green; width: 40px;">
+  <tr style="position:relative; left:-100px; height: 40px">
+    <td rowspan=2></td>
+  </tr>
+  <tr style="height: 40px"></tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/position-relative/1409114-3.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<body style="overflow:hidden">
+<table style="position:relative; top:-50px">
+  <tbody style="background:green">
+    <tr style="position:relative; left:-100px; height: 40px">
+      <td rowspan=2 style="width: 40px;"></td>
+    </tr>
+    <tr style="height: 40px"></tr>
+  </tbody>
+</table>
+</body>
+</html>
--- a/layout/reftests/position-relative/reftest.list
+++ b/layout/reftests/position-relative/reftest.list
@@ -2,8 +2,11 @@
 == table-collapse-2.html table-collapse-2-ref.html
 == table-collapse-3.html table-collapse-3-ref.html
 == table-collapse-4.html table-collapse-4-ref.html
 == table-separate-1.html table-separate-1-ref.html
 == table-separate-2.html table-separate-2-ref.html
 == table-separate-3.html table-separate-3-ref.html
 == table-separate-4.html table-separate-4-ref.html
 == 1115999-1.html 1115999-1-ref.html
+== 1409114-1.html 1409114-1-ref.html
+!= 1409114-2.html about:blank
+!= 1409114-3.html about:blank
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -77,16 +77,17 @@ class nsDisplayTableBackgroundSet {
   nsDisplayList* ColBackgrounds() { return &mColBackgrounds; }
 
   nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable)
       : mBuilder(aBuilder) {
     mPrevTableBackgroundSet = mBuilder->SetTableBackgroundSet(this);
     mozilla::DebugOnly<const nsIFrame*> reference =
         mBuilder->FindReferenceFrameFor(aTable, &mToReferenceFrame);
     MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(reference, aTable));
+    mDirtyRect = mBuilder->GetDirtyRect();
   }
 
   ~nsDisplayTableBackgroundSet() {
     mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result =
         mBuilder->SetTableBackgroundSet(mPrevTableBackgroundSet);
     MOZ_ASSERT(result == this);
   }
 
@@ -100,30 +101,33 @@ class nsDisplayTableBackgroundSet {
   }
 
   void AddColumn(nsTableColFrame* aFrame) { mColumns.AppendElement(aFrame); }
 
   nsTableColFrame* GetColForIndex(int32_t aIndex) { return mColumns[aIndex]; }
 
   const nsPoint& TableToReferenceFrame() { return mToReferenceFrame; }
 
+  const nsRect& GetDirtyRect() { return mDirtyRect; }
+
  private:
   // This class is only used on stack, so we don't have to worry about leaking
   // it.  Don't let us be heap-allocated!
   void* operator new(size_t sz) CPP_THROW_NEW;
 
  protected:
   nsDisplayListBuilder* mBuilder;
   nsDisplayTableBackgroundSet* mPrevTableBackgroundSet;
 
   nsDisplayList mColGroupBackgrounds;
   nsDisplayList mColBackgrounds;
 
   nsTArray<nsTableColFrame*> mColumns;
   nsPoint mToReferenceFrame;
+  nsRect mDirtyRect;
 };
 
 /* ========================================================================== */
 
 enum nsTableColType {
   eColContent = 0,            // there is real col content associated
   eColAnonymousCol = 1,       // the result of a span on a col
   eColAnonymousColGroup = 2,  // the result of a span on a col group
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -237,17 +237,17 @@ static void DisplayRows(nsDisplayListBui
 }
 
 void nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                             const nsDisplayListSet& aLists) {
   DisplayOutsetBoxShadow(aBuilder, aLists.BorderBackground());
 
   for (nsTableRowFrame* row = GetFirstRow(); row; row = row->GetNextRow()) {
     if (!aBuilder->GetDirtyRect().Intersects(
-            nsRect(row->GetNormalPosition(), row->GetSize()))) {
+            row->GetVisualOverflowRect() + row->GetNormalPosition())) {
       continue;
     }
     row->PaintCellBackgroundsForFrame(this, aBuilder, aLists,
                                       row->GetNormalPosition());
   }
 
   DisplayInsetBoxShadow(aBuilder, aLists.BorderBackground());