Bug 539356 - Part 18 - Mark frames with only invalid children as an optimization to use when invalidating further frames. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 29 Aug 2012 17:48:43 +1200
changeset 108555 4372c4914958f5f9effcf48f8cfceccb5fc2f158
parent 108554 25af0febf3296038a360134e4e7995c7a8fcb464
child 108556 b5559af3cf948dfe2acc031c7cda3cd1f0cd7216
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersroc
bugs539356
milestone18.0a1
Bug 539356 - Part 18 - Mark frames with only invalid children as an optimization to use when invalidating further frames. r=roc
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4749,16 +4749,22 @@ nsIFrame::GetTransformMatrix(const nsIFr
      NSAppUnitsToFloatPixels(delta.y, scaleFactor),
      0.0f);
 }
 
 void
 nsIFrame::InvalidateFrameSubtree(uint32_t aFlags)
 {
   InvalidateFrame(aFlags);
+
+  if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
+    return;
+  }
+
+  AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
   
   nsAutoTArray<nsIFrame::ChildList,4> childListArray;
   GetCrossDocChildLists(&childListArray);
 
   nsIFrame::ChildListArrayIterator lists(childListArray);
   for (; !lists.IsDone(); lists.Next()) {
     nsFrameList::Enumerator childFrames(lists.CurrentList());
     for (; !childFrames.AtEnd(); childFrames.Next()) {
@@ -4779,17 +4785,19 @@ nsIFrame::ClearInvalidationStateBits()
     for (; !lists.IsDone(); lists.Next()) {
       nsFrameList::Enumerator childFrames(lists.CurrentList());
       for (; !childFrames.AtEnd(); childFrames.Next()) {
         childFrames.get()->ClearInvalidationStateBits();
       }
     }
   }
 
-  RemoveStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT);
+  RemoveStateBits(NS_FRAME_NEEDS_PAINT | 
+                  NS_FRAME_DESCENDANT_NEEDS_PAINT | 
+                  NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
 }
 
 void
 nsIFrame::InvalidateFrame(uint32_t aFlags)
 {
   AddStateBits(NS_FRAME_NEEDS_PAINT);
   nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(this);
   while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
@@ -7986,16 +7994,23 @@ nsFrame::SetParent(nsIFrame* aParent)
     }
   }
 
   if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
     AddInPopupStateBitToDescendants(this);
   } else {
     RemoveInPopupStateBitFromDescendants(this);
   }
+  
+  // If our new parent only has invalid children, then we just invalidate
+  // ourselves too. This is probably faster than clearing the flag all
+  // the way up the frame tree.
+  if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
+    InvalidateFrame(INVALIDATE_DONT_SCHEDULE_PAINT);
+  }
 }
 
 void
 nsFrame::InitBoxMetrics(bool aClear)
 {
   FrameProperties props = Properties();
   if (aClear) {
     props.Delete(BoxMetricsProperty());
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -308,16 +308,22 @@ typedef uint64_t nsFrameState;
 
 // Frame has a descendant frame that needs painting - This includes
 // cross-doc children.
 #define NS_FRAME_DESCENDANT_NEEDS_PAINT             NS_FRAME_STATE_BIT(49)
 
 // Frame is a descendant of a popup
 #define NS_FRAME_IN_POPUP                           NS_FRAME_STATE_BIT(50)
 
+// Frame has only descendant frames that needs painting - This includes
+// cross-doc children. This guarantees that all descendents have 
+// NS_FRAME_NEEDS_PAINT and NS_FRAME_ALL_DESCENDANTS_NEED_PAINT, or they 
+// have no display items.
+#define NS_FRAME_ALL_DESCENDANTS_NEED_PAINT         NS_FRAME_STATE_BIT(51)
+
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                      NS_FRAME_STATE_BIT(22)
 #define NS_STATE_IS_DIRECTION_NORMAL                NS_FRAME_STATE_BIT(31)
 
 // Helper macros
 #define NS_SUBTREE_DIRTY(_frame)  \
   (((_frame)->GetStateBits() &      \
     (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)