Bug 841192. Part 8: On encountering out-of-flow frames during display list construction, save their clip rect as well as their dirty rect for later use when we traverse the placeholder. r=mattwoodrow
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 04 Mar 2013 22:56:02 +1300
changeset 138750 b16876942c8df78107b10f0288f88f27198cbdc8
parent 138749 a9214f38c73e930990123678bf1f4bfc26ac7cf5
child 138751 30928f33d63f060dc0f5fbf4d6773bf29d0f948a
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs841192
milestone23.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 841192. Part 8: On encountering out-of-flow frames during display list construction, save their clip rect as well as their dirty rect for later use when we traverse the placeholder. r=mattwoodrow
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/generic/nsFrame.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -582,27 +582,26 @@ void nsDisplayListBuilder::MarkOutOfFlow
   }
 
   if (mHasDisplayPort && IsFixedFrame(aFrame)) {
     dirty = overflowRect;
   }
 
   if (!dirty.IntersectRect(dirty, overflowRect))
     return;
-
-  aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
-                           new nsRect(dirty));
+  aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(),
+    new OutOfFlowDisplayData(mClipState.GetClipForContainingBlockDescendants(), dirty));
 
   MarkFrameForDisplay(aFrame, aDirtyFrame);
 }
 
 static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
   nsPresContext* presContext = aFrame->PresContext();
   presContext->PropertyTable()->
-    Delete(aFrame, nsDisplayListBuilder::OutOfFlowDirtyRectProperty());
+    Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
 
   for (nsIFrame* f = aFrame; f;
        f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
     if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
       return;
     f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
   }
 }
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -107,16 +107,17 @@ class ImageContainer;
  * coordinate system for all display list items. Some of the parameters are
  * available from the prescontext/presshell, but we copy them into the builder
  * for faster/more convenient access.
  */
 class nsDisplayListBuilder {
 public:
   typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
   typedef mozilla::FrameLayerBuilder FrameLayerBuilder;
+  typedef mozilla::DisplayListClipState DisplayListClipState;
   typedef nsIWidget::ThemeGeometry ThemeGeometry;
 
   /**
    * @param aReferenceFrame the frame at the root of the subtree; its origin
    * is the origin of the reference coordinate system for this display list
    * @param aIsForEvents true if we're creating this list in order to
    * determine which frame is under the mouse position
    * @param aBuildCaret whether or not we should include the caret in any
@@ -556,17 +557,31 @@ public:
     nsDisplayListBuilder* mBuilder;
     bool                  mOldValue;
   };
 
   // Helpers for tables
   nsDisplayTableItem* GetCurrentTableItem() { return mCurrentTableItem; }
   void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
 
-  NS_DECLARE_FRAME_PROPERTY(OutOfFlowDirtyRectProperty, nsIFrame::DestroyRect)
+  struct OutOfFlowDisplayData {
+    OutOfFlowDisplayData(const DisplayItemClip* aContainingBlockClip,
+                         const nsRect &aDirtyRect)
+      : mContainingBlockClip(aContainingBlockClip)
+      , mDirtyRect(aDirtyRect)
+    {}
+    const DisplayItemClip* mContainingBlockClip;
+    nsRect mDirtyRect;
+  };
+  static void DestroyOutOfFlowDisplayData(void* aPropertyValue)
+  {
+    delete static_cast<OutOfFlowDisplayData*>(aPropertyValue);
+  }
+
+  NS_DECLARE_FRAME_PROPERTY(OutOfFlowDisplayDataProperty, DestroyOutOfFlowDisplayData)
   NS_DECLARE_FRAME_PROPERTY(Preserve3DDirtyRectProperty, nsIFrame::DestroyRect)
 
   nsPresContext* CurrentPresContext() {
     return CurrentPresShellState()->mPresShell->GetPresContext();
   }
 
   /**
    * Accumulates the bounds of box frames that have moz-appearance
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2094,16 +2094,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
     // pseudo-stacking-context.
     pseudoStackingContext = true;
   }
 
   // dirty rect in child-relative coordinates
   nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
 
   nsIAtom* childType = child->GetType();
+  nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
   if (childType == nsGkAtoms::placeholderFrame) {
     nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
     child = placeholder->GetOutOfFlowFrame();
     NS_ASSERTION(child, "No out of flow frame?");
     // If 'child' is a pushed float then it's owned by a block that's not an
     // ancestor of the placeholder, and it will be painted by that block and
     // should not be painted through the placeholder.
     if (!child || nsLayoutUtils::IsPopup(child) ||
@@ -2111,20 +2112,20 @@ nsIFrame::BuildDisplayListForChild(nsDis
       return;
     // Make sure that any attempt to use childType below is disappointed. We
     // could call GetType again but since we don't currently need it, let's
     // avoid the virtual call.
     childType = nullptr;
     // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
     if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
       return;
-    nsRect* savedDirty = static_cast<nsRect*>
-      (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDirtyRectProperty()));
-    if (savedDirty) {
-      dirty = *savedDirty;
+    savedOutOfFlowData = static_cast<OutOfFlowDisplayData*>
+      (child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()));
+    if (savedOutOfFlowData) {
+      dirty = savedOutOfFlowData->mDirtyRect;
     } else {
       // The out-of-flow frame did not intersect the dirty area. We may still
       // need to traverse into it, since it may contain placeholders we need
       // to enter to reach other out-of-flow frames that are visible.
       dirty.SetEmpty();
     }
     pseudoStackingContext = true;
   }
@@ -2203,23 +2204,29 @@ nsIFrame::BuildDisplayListForChild(nsDis
   // active, that's pointless and the extra layer(s) created may be wasteful.
   bool buildFixedPositionItem = disp->mPosition == NS_STYLE_POSITION_FIXED &&
     !child->GetParent()->GetParent() && !aBuilder->IsInFixedPosition() &&
     IsRootScrollFrameActive(PresContext()->PresShell()) && !isSVG;
 
   nsDisplayListBuilder::AutoBuildingDisplayList
     buildingForChild(aBuilder, child, pseudoStackingContext, buildFixedPositionItem);
 
+  if (savedOutOfFlowData) {
+    aBuilder->ClipState().SetClipForContainingBlockDescendants(
+      savedOutOfFlowData->mContainingBlockClip);
+  }
+
   nsRect overflowClip;
   nscoord overflowClipRadii[8];
   bool applyOverflowClip =
     ApplyOverflowClipping(aBuilder, child, disp, &overflowClip);
   if (applyOverflowClip) {
     child->GetPaddingBoxBorderRadii(overflowClipRadii);
   }
+
   // Don't use overflowClip to restrict the dirty rect, since some of the
   // descendants may not be clipped by it. Even if we end up with unnecessary
   // display items, they'll be pruned during ComputeVisibility. Note that
   // this overflow-clipping here only applies to overflow:-moz-hidden-unscrollable;
   // overflow:hidden etc creates an nsHTML/XULScrollFrame which does its own
   // clipping.
 
   child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);