Bug 1467619 - Track and adjust layerization on repaint triggers r?mattwoodrow
To avoid creating a bunch of layers when we don't need to, this
tracks when a frame needs to be repainted, and invalidates the
IsStyleAnimated logic around mRestyleCounts if the frame is also
being invalidated.
MozReview-Commit-ID: 5Q96Cx6f3V0
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1020,16 +1020,18 @@ DoApplyRenderingChangeToTree(nsIFrame* a
needInvalidatingPaint = true;
aFrame->InvalidateFrameSubtree();
if ((aChange & nsChangeHint_UpdateEffects) &&
aFrame->IsFrameOfType(nsIFrame::eSVG) &&
!(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
// Need to update our overflow rects:
nsSVGUtils::ScheduleReflowSVG(aFrame);
}
+
+ ActiveLayerTracker::NotifyNeedsRepaint(aFrame);
}
if (aChange & nsChangeHint_UpdateTextPath) {
if (nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
// Invalidate and reflow the entire SVGTextFrame:
NS_ASSERTION(aFrame->GetContent()->IsSVGElement(nsGkAtoms::textPath),
"expected frame for a <textPath> element");
nsIFrame* text = nsLayoutUtils::GetClosestFrameOfType(
aFrame, LayoutFrameType::SVGText);
--- a/layout/painting/ActiveLayerTracker.cpp
+++ b/layout/painting/ActiveLayerTracker.cpp
@@ -45,16 +45,17 @@ public:
ACTIVITY_TRANSFORM,
ACTIVITY_LEFT,
ACTIVITY_TOP,
ACTIVITY_RIGHT,
ACTIVITY_BOTTOM,
ACTIVITY_BACKGROUND_POSITION,
ACTIVITY_SCALE,
+ ACTIVITY_TRIGGERED_REPAINT,
// keep as last item
ACTIVITY_COUNT
};
explicit LayerActivity(nsIFrame* aFrame)
: mFrame(aFrame)
, mContent(nullptr)
@@ -365,16 +366,29 @@ ActiveLayerTracker::NotifyInlineStyleRul
}
if (gLayerActivityTracker &&
gLayerActivityTracker->mCurrentScrollHandlerFrame.IsAlive()) {
NotifyAnimatedFromScrollHandler(aFrame, aProperty,
gLayerActivityTracker->mCurrentScrollHandlerFrame.GetFrame());
}
}
+/* static */ void
+ActiveLayerTracker::NotifyNeedsRepaint(nsIFrame* aFrame)
+{
+ LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
+ if (IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
+ // This is mirroring NotifyInlineStyleRuleModified's NotifyAnimated logic. Just max out
+ // the restyle count if we're in an animation callback.
+ layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] = 0xFF;
+ } else {
+ IncrementMutationCount(&layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT]);
+ }
+}
+
/* static */ bool
ActiveLayerTracker::IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSPropertyID aProperty)
{
return IsStyleAnimated(nullptr, aFrame, aProperty);
}
/* static */ bool
ActiveLayerTracker::IsBackgroundPositionAnimated(nsDisplayListBuilder* aBuilder,
@@ -421,17 +435,18 @@ ActiveLayerTracker::IsStyleAnimated(nsDi
aProperty == eCSSProperty_opacity &&
(!aBuilder || aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
return true;
}
LayerActivity* layerActivity = GetLayerActivity(aFrame);
if (layerActivity) {
LayerActivity::ActivityIndex activityIndex = LayerActivity::GetActivityIndexForProperty(aProperty);
- if (layerActivity->mRestyleCounts[activityIndex] >= 2) {
+ if (layerActivity->mRestyleCounts[LayerActivity::ACTIVITY_TRIGGERED_REPAINT] < 2 &&
+ layerActivity->mRestyleCounts[activityIndex] >= 2) {
return true;
}
if (CheckScrollInducedActivity(layerActivity, activityIndex, aBuilder)) {
return true;
}
}
if (aProperty == eCSSProperty_transform && aFrame->Combines3DTransformWithAncestors()) {
return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty);
--- a/layout/painting/ActiveLayerTracker.h
+++ b/layout/painting/ActiveLayerTracker.h
@@ -69,16 +69,23 @@ public:
* style will trigger this.
* aNewValue and aDOMCSSDecl are used to determine whether the property's
* value has changed.
*/
static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSPropertyID aProperty,
const nsAString& aNewValue,
nsDOMCSSDeclaration* aDOMCSSDecl);
/**
+ * Notify that a frame needs to be repainted. This is important for layering
+ * decisions where, say, aFrame's transform is updated from JS, but we need
+ * to repaint aFrame anyway, so we get no benefit from giving it its own
+ * layer.
+ */
+ static void NotifyNeedsRepaint(nsIFrame* aFrame);
+ /**
* Return true if aFrame's aProperty style should be considered as being animated
* for pre-rendering.
*/
static bool IsStyleMaybeAnimated(nsIFrame* aFrame, nsCSSPropertyID aProperty);
/**
* Return true if aFrame's aProperty style should be considered as being animated
* for constructing active layers.
*/