Bug 1038781 - Don't reflow/repaint frame when clip changes. r=roc
authorChris Lord <chrislord.net@gmail.com>
Wed, 16 Jul 2014 13:28:50 +0200
changeset 216496 7056b101fbb0a6c318c899e0cacdf78d59a5e8c6
parent 216495 40a5725d7f92a7429978155efded3f57fd33707c
child 216497 3262feb8e982065719d2eb940b5698407b357185
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1038781
milestone33.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 1038781 - Don't reflow/repaint frame when clip changes. r=roc If an element's existing clip changes, just update overflow areas and let DLBI handle invalidation.
layout/base/RestyleManager.cpp
layout/base/nsChangeHint.h
layout/style/nsStyleStruct.cpp
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -78,28 +78,30 @@ static void
 DoApplyRenderingChangeToTree(nsIFrame* aFrame,
                              nsChangeHint aChange);
 
 /**
  * Sync views on aFrame and all of aFrame's descendants (following placeholders),
  * if aChange has nsChangeHint_SyncFrameView.
  * Calls DoApplyRenderingChangeToTree on all aFrame's out-of-flow descendants
  * (following placeholders), if aChange has nsChangeHint_RepaintFrame.
- * aFrame should be some combination of nsChangeHint_SyncFrameView and
- * nsChangeHint_RepaintFrame and nsChangeHint_UpdateOpacityLayer, nothing else.
+ * aFrame should be some combination of nsChangeHint_SyncFrameView,
+ * nsChangeHint_RepaintFrame, nsChangeHint_UpdateOpacityLayer and
+ * nsChangeHint_SchedulePaint, nothing else.
 */
 static void
 SyncViewsAndInvalidateDescendants(nsIFrame* aFrame,
                                   nsChangeHint aChange)
 {
   NS_PRECONDITION(gInApplyRenderingChangeToTree,
                   "should only be called within ApplyRenderingChangeToTree");
   NS_ASSERTION(aChange == (aChange & (nsChangeHint_RepaintFrame |
                                       nsChangeHint_SyncFrameView |
-                                      nsChangeHint_UpdateOpacityLayer)),
+                                      nsChangeHint_UpdateOpacityLayer |
+                                      nsChangeHint_SchedulePaint)),
                "Invalid change flag");
 
   nsView* view = aFrame->GetView();
   if (view) {
     if (aChange & nsChangeHint_SyncFrameView) {
       nsContainerFrame::SyncFrameViewProperties(aFrame->PresContext(),
                                                 aFrame, nullptr, view);
     }
@@ -179,17 +181,18 @@ DoApplyRenderingChangeToTree(nsIFrame* a
     // Invalidate and sync views on all descendant frames, following placeholders.
     // We don't need to update transforms in SyncViewsAndInvalidateDescendants, because
     // there can't be any out-of-flows or popups that need to be transformed;
     // all out-of-flow descendants of the transformed element must also be
     // descendants of the transformed frame.
     SyncViewsAndInvalidateDescendants(aFrame,
       nsChangeHint(aChange & (nsChangeHint_RepaintFrame |
                               nsChangeHint_SyncFrameView |
-                              nsChangeHint_UpdateOpacityLayer)));
+                              nsChangeHint_UpdateOpacityLayer |
+                              nsChangeHint_SchedulePaint)));
     // This must be set to true if the rendering change needs to
     // invalidate content.  If it's false, a composite-only paint
     // (empty transaction) will be scheduled.
     bool needInvalidatingPaint = false;
 
     // if frame has view, will already be invalidated
     if (aChange & nsChangeHint_RepaintFrame) {
       // Note that this whole block will be skipped when painting is suppressed
@@ -256,16 +259,19 @@ DoApplyRenderingChangeToTree(nsIFrame* a
     if (aChange & nsChangeHint_ChildrenOnlyTransform) {
       needInvalidatingPaint = true;
       nsIFrame* childFrame =
         GetFrameForChildrenOnlyTransformHint(aFrame)->GetFirstPrincipalChild();
       for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
         ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
       }
     }
+    if (aChange & nsChangeHint_SchedulePaint) {
+      needInvalidatingPaint = true;
+    }
     aFrame->SchedulePaint(needInvalidatingPaint ?
                           nsIFrame::PAINT_DEFAULT :
                           nsIFrame::PAINT_COMPOSITE_ONLY);
   }
 }
 
 static void
 ApplyRenderingChangeToTree(nsPresContext* aPresContext,
@@ -730,17 +736,17 @@ RestyleManager::ProcessRestyledFrames(ns
       }
       if (hint & nsChangeHint_NeedReflow) {
         StyleChangeReflow(frame, hint);
         didReflowThisFrame = true;
       }
 
       if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
                   nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
-                  nsChangeHint_ChildrenOnlyTransform)) {
+                  nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
         ApplyRenderingChangeToTree(mPresContext, frame, hint);
       }
       if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
         ActiveLayerTracker::NotifyOffsetRestyle(frame);
         // It is possible for this to fall back to a reflow
         if (!RecomputePosition(frame)) {
           didReflowThisFrame = true;
         }
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -122,17 +122,23 @@ enum nsChangeHint {
    * due to the border-width change on the child.
    */
   nsChangeHint_BorderStyleNoneChange = 0x20000,
 
   /**
    * SVG textPath needs to be recomputed because the path has changed.
    * This means that the glyph positions of the text need to be recomputed.
    */
-  nsChangeHint_UpdateTextPath = 0x40000
+  nsChangeHint_UpdateTextPath = 0x40000,
+
+  /**
+   * This will schedule an invalidating paint. This is useful if something
+   * has changed which will be invalidated by DLBI.
+   */
+  nsChangeHint_SchedulePaint = 0x80000
 
   // IMPORTANT NOTE: When adding new hints, consider whether you need to
   // add them to NS_HintsNotHandledForDescendantsIn() below.
 };
 
 // Redefine these operators to return nothing. This will catch any use
 // of these operators on hints. We should not be using these operators
 // on nsChangeHints
@@ -223,17 +229,18 @@ inline nsChangeHint NS_HintsNotHandledFo
 
   return result;
 }
 
 // Redefine the old NS_STYLE_HINT constants in terms of the new hint structure
 #define NS_STYLE_HINT_NONE \
   nsChangeHint(0)
 #define NS_STYLE_HINT_VISUAL \
-  nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView)
+  nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | \
+               nsChangeHint_SchedulePaint)
 #define nsChangeHint_AllReflowHints                     \
   nsChangeHint(nsChangeHint_NeedReflow |                \
                nsChangeHint_ClearAncestorIntrinsics |   \
                nsChangeHint_ClearDescendantIntrinsics | \
                nsChangeHint_NeedDirtyReflow)
 #define NS_STYLE_HINT_REFLOW \
   nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints)
 #define NS_STYLE_HINT_FRAMECHANGE \
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2496,20 +2496,27 @@ nsChangeHint nsStyleDisplay::CalcDiffere
   // necessarily require a repaint, reflow should suffice.
   if (mBreakType != aOther.mBreakType
       || mBreakInside != aOther.mBreakInside
       || mBreakBefore != aOther.mBreakBefore
       || mBreakAfter != aOther.mBreakAfter
       || mAppearance != aOther.mAppearance
       || mOrient != aOther.mOrient
       || mOverflowClipBox != aOther.mOverflowClipBox
-      || mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
+      || mClipFlags != aOther.mClipFlags)
     NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
                                        nsChangeHint_RepaintFrame));
 
+  if (!mClip.IsEqualInterior(aOther.mClip)) {
+    // If the clip has changed, we just need to update overflow areas. DLBI
+    // will handle the invalidation.
+    NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdateOverflow,
+                                       nsChangeHint_SchedulePaint));
+  }
+
   if (mOpacity != aOther.mOpacity) {
     // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
     // repaint the frame because DLBI will not catch the invalidation.  Otherwise,
     // just update the opacity layer.
     if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) ||
         (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) {
       NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
     } else {