Bug 1251075 - Optimize away nsChangeHint_UpdateContainingBlock in nsStyleContext::CalcStyleDifference when possible. r?bz
MozReview-Commit-ID: 4Owobm1vZLn
--- 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,