Bug 1251075 - Optimize away nsChangeHint_UpdateContainingBlock in nsStyleContext::CalcStyleDifference when possible. r?bz draft
authorL. David Baron <dbaron@dbaron.org>
Sat, 27 Aug 2016 13:22:54 -0700
changeset 406470 dfbec3a2b446e590cba17dbf863ed913fd4d6352
parent 406469 6209b16f8e205dc7ff004e096d4b9b9556730664
child 406471 d3cc1a1a63f9b90add3d0c2ea1d54d95394df0fe
push id27733
push userdbaron@mozilla.com
push dateSat, 27 Aug 2016 20:23:11 +0000
reviewersbz
bugs1251075
milestone51.0a1
Bug 1251075 - Optimize away nsChangeHint_UpdateContainingBlock in nsStyleContext::CalcStyleDifference when possible. r?bz MozReview-Commit-ID: 4Owobm1vZLn
layout/base/nsChangeHint.h
layout/style/nsStyleContext.cpp
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -126,16 +126,21 @@ enum nsChangeHint {
    */
   nsChangeHint_RecomputePosition = 1 << 16,
 
   /**
    * Behaves like ReconstructFrame, but only if the frame has descendants
    * that are absolutely or fixed position. Use this hint when a style change
    * has changed whether the frame is a container for fixed-pos or abs-pos
    * elements, but reframing is otherwise not needed.
+   *
+   * Note that nsStyleContext::CalcStyleDifference adjusts results
+   * returned by style struct CalcDifference methods to return this hint
+   * only if there was a change to whether the element's overall style
+   * indicates that it establishes a containing block.
    */
   nsChangeHint_UpdateContainingBlock = 1 << 17,
 
   /**
    * This change hint has *no* change handling behavior.  However, it
    * exists to be a non-inherited hint, because when the border-style
    * changes, and it's inherited by a child, that might require a reflow
    * due to the border-width change on the child.
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1259,16 +1259,39 @@ nsStyleContext::CalcStyleDifferenceInter
       }
     }
 
     if (change) {
       hint |= nsChangeHint_RepaintFrame;
     }
   }
 
+  if (hint & nsChangeHint_UpdateContainingBlock) {
+    // If a struct returned nsChangeHint_UpdateContainingBlock, that
+    // means that one property's influence on whether we're a containing
+    // block for abs-pos or fixed-pos elements has changed.  However, we
+    // only need to return the hint if the overall computation of
+    // whether we establish a containing block has changed.
+
+    // Note that it's perhaps good for this test to be last because it
+    // doesn't use Peek* functions to get the structs on the old
+    // context.  But this isn't a big concern because these struct
+    // getters should be called during frame construction anyway.
+    if (StyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
+        aNewContext->StyleDisplay()->
+          IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
+        StyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
+        aNewContext->StyleDisplay()->
+          IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
+      // While some styles that cause the frame to be a containing block
+      // has changed, the overall result hasn't.
+      hint &= ~nsChangeHint_UpdateContainingBlock;
+    }
+  }
+
   MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
              "Added a new hint without bumping AllHints?");
   return hint & ~nsChangeHint_NeutralChange;
 }
 
 nsChangeHint
 nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
                                     nsChangeHint aParentHintsNotHandledForDescendants,