Bug 1334036 - Part 8: Add AddLayerChangesForAnimation in ServoRestyleManager.
Some changes to animations don't affect the computed style and yet still
require the layer to be updated. Therefore, we also need to call
AddLayerChangesForAnimation in ServoRestyleManager. In this patch, we
factor out this function from GeckoRestyleManager, so we can reuse it.
MozReview-Commit-ID: LL7D1oGS65l
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -14,17 +14,16 @@
#include "mozilla/EffectSet.h"
#include "mozilla/EventStates.h"
#include "mozilla/ViewportFrame.h"
#include "mozilla/css/StyleRule.h" // For nsCSSSelector
#include "nsLayoutUtils.h"
#include "AnimationCommon.h" // For GetLayerAnimationInfo
#include "FrameLayerBuilder.h"
#include "GeckoProfiler.h"
-#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
#include "nsAutoPtr.h"
#include "nsStyleChangeList.h"
#include "nsRuleProcessorData.h"
#include "nsStyleSet.h"
#include "nsStyleUtil.h"
#include "nsCSSFrameConstructor.h"
#include "nsSVGEffects.h"
#include "nsCSSPseudoElements.h"
@@ -45,17 +44,16 @@
#include "nsContentUtils.h"
#include "nsIFrameInlines.h"
#include "ActiveLayerTracker.h"
#include "nsDisplayList.h"
#include "RestyleTrackerInlines.h"
#include "nsSMILAnimationController.h"
#include "nsCSSRuleProcessor.h"
#include "ChildIterator.h"
-#include "Layers.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
#endif
namespace mozilla {
using namespace layers;
@@ -1222,64 +1220,16 @@ ElementRestyler::ElementRestyler(nsPresC
#endif
{
MOZ_ASSERT(!(mHintsHandledByAncestors & nsChangeHint_ReconstructFrame),
"why restyle descendants if we are reconstructing the frame for "
"an ancestor?");
}
void
-ElementRestyler::AddLayerChangesForAnimation()
-{
- uint64_t frameGeneration =
- GeckoRestyleManager::GetAnimationGenerationForFrame(mFrame);
-
- nsChangeHint hint = nsChangeHint(0);
- for (const LayerAnimationInfo::Record& layerInfo :
- LayerAnimationInfo::sRecords) {
- Layer* layer =
- FrameLayerBuilder::GetDedicatedLayer(mFrame, layerInfo.mLayerType);
- if (layer && frameGeneration != layer->GetAnimationGeneration()) {
- // If we have a transform layer but don't have any transform style, we
- // probably just removed the transform but haven't destroyed the layer
- // yet. In this case we will add the appropriate change hint
- // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
- // so we can skip adding any change hint here. (If we *were* to add
- // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
- // complain that we're updating a transform layer without a transform).
- if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
- !mFrame->StyleDisplay()->HasTransformStyle()) {
- continue;
- }
- hint |= layerInfo.mChangeHint;
- }
-
- // We consider it's the first paint for the frame if we have an animation
- // for the property but have no layer.
- // Note that in case of animations which has properties preventing running
- // on the compositor, e.g., width or height, corresponding layer is not
- // created at all, but even in such cases, we normally set valid change
- // hint for such animations in each tick, i.e. restyles in each tick. As
- // a result, we usually do restyles for such animations in every tick on
- // the main-thread. The only animations which will be affected by this
- // explicit change hint are animations that have opacity/transform but did
- // not have those properies just before. e.g, setting transform by
- // setKeyframes or changing target element from other target which prevents
- // running on the compositor, etc.
- if (!layer &&
- nsLayoutUtils::HasEffectiveAnimation(mFrame, layerInfo.mProperty)) {
- hint |= layerInfo.mChangeHint;
- }
- }
- if (hint) {
- mChangeList->AppendChange(mFrame, mContent, hint);
- }
-}
-
-void
ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
nsStyleContext* aNewContext,
nsChangeHint aChangeToAssume,
uint32_t* aEqualStructs,
uint32_t* aSamePointerStructs)
{
static_assert(nsStyleStructID_Length <= 32,
"aEqualStructs is not big enough");
@@ -1874,25 +1824,25 @@ ElementRestyler::Restyle(nsRestyleHint a
f = GeckoRestyleManager::GetNextContinuationWithSameStyle(
f, oldContext, &haveMoreContinuations);
}
// Some changes to animations don't affect the computed style and yet still
// require the layer to be updated. For example, pausing an animation via
// the Web Animations API won't affect an element's style but still
- // requires us to pull the animation off the layer.
+ // requires to update the animation on the layer.
//
// Although we only expect this code path to be called when computed style
// is not changing, we can sometimes reach this at the end of a transition
// when the animated style is being removed. Since
// AddLayerChangesForAnimation checks if mFrame has a transform style or not,
// we need to call it *after* calling RestyleSelf to ensure the animated
// transform has been removed first.
- AddLayerChangesForAnimation();
+ RestyleManager::AddLayerChangesForAnimation(mFrame, mContent, *mChangeList);
if (haveMoreContinuations && hintToRestore) {
// If we have more continuations with different style (e.g., because
// we're inside a ::first-letter or ::first-line), put the restyle
// hint back.
mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
hintToRestore, nsChangeHint(0));
}
--- a/layout/base/GeckoRestyleManager.h
+++ b/layout/base/GeckoRestyleManager.h
@@ -579,18 +579,16 @@ private:
* This is used to check whether it is appropriate to call
* ReparentStyleContext.
*/
bool CanReparentStyleContext(nsRestyleHint aRestyleHint);
/**
* Helpers for Restyle().
*/
- void AddLayerChangesForAnimation();
-
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
nsStyleContext* aOldContext,
nsTArray<nsStyleContext*>& aContextsToMove);
bool MoveStyleContextsForChildren(nsStyleContext* aOldContext);
/**
* Helpers for RestyleSelf().
*/
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1,20 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/RestyleManager.h"
#include "mozilla/RestyleManagerInlines.h"
+
+#include "Layers.h"
+#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
#include "mozilla/StyleSetHandleInlines.h"
#include "nsIFrame.h"
#include "nsIPresShellInlines.h"
+
namespace mozilla {
RestyleManager::RestyleManager(StyleBackendType aType,
nsPresContext* aPresContext)
: mPresContext(aPresContext)
, mRestyleGeneration(1)
, mHoverGeneration(0)
, mType(aType)
@@ -1766,16 +1770,72 @@ RestyleManager::IncrementAnimationGenera
// ProcessPendingRestyles so we should ignore any subsequent (redundant)
// calls that occur while we are still processing restyles.
if ((IsGecko() && !AsGecko()->IsProcessingRestyles()) ||
(IsServo() && !mInStyleRefresh)) {
++mAnimationGeneration;
}
}
+/* static */ void
+RestyleManager::AddLayerChangesForAnimation(nsIFrame* aFrame,
+ nsIContent* aContent,
+ nsStyleChangeList&
+ aChangeListToProcess)
+{
+ if (!aFrame || !aContent) {
+ return;
+ }
+
+ uint64_t frameGeneration =
+ RestyleManager::GetAnimationGenerationForFrame(aFrame);
+
+ nsChangeHint hint = nsChangeHint(0);
+ for (const LayerAnimationInfo::Record& layerInfo :
+ LayerAnimationInfo::sRecords) {
+ layers::Layer* layer =
+ FrameLayerBuilder::GetDedicatedLayer(aFrame, layerInfo.mLayerType);
+ if (layer && frameGeneration != layer->GetAnimationGeneration()) {
+ // If we have a transform layer but don't have any transform style, we
+ // probably just removed the transform but haven't destroyed the layer
+ // yet. In this case we will add the appropriate change hint
+ // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
+ // so we can skip adding any change hint here. (If we *were* to add
+ // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
+ // complain that we're updating a transform layer without a transform).
+ if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
+ !aFrame->StyleDisplay()->HasTransformStyle()) {
+ continue;
+ }
+ hint |= layerInfo.mChangeHint;
+ }
+
+ // We consider it's the first paint for the frame if we have an animation
+ // for the property but have no layer.
+ // Note that in case of animations which has properties preventing running
+ // on the compositor, e.g., width or height, corresponding layer is not
+ // created at all, but even in such cases, we normally set valid change
+ // hint for such animations in each tick, i.e. restyles in each tick. As
+ // a result, we usually do restyles for such animations in every tick on
+ // the main-thread. The only animations which will be affected by this
+ // explicit change hint are animations that have opacity/transform but did
+ // not have those properies just before. e.g, setting transform by
+ // setKeyframes or changing target element from other target which prevents
+ // running on the compositor, etc.
+ if (!layer &&
+ nsLayoutUtils::HasEffectiveAnimation(aFrame, layerInfo.mProperty)) {
+ hint |= layerInfo.mChangeHint;
+ }
+ }
+
+ if (hint) {
+ aChangeListToProcess.AppendChange(aFrame, aContent, hint);
+ }
+}
+
RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
RestyleManager* aRestyleManager)
: mRestyleManager(aRestyleManager)
, mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
{
MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
"shouldn't construct recursively");
mRestyleManager->mAnimationsWithDestroyedFrame = this;
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -189,16 +189,21 @@ public:
// Update the animation generation count to mark that animation state
// has changed.
//
// This is normally performed automatically by ProcessPendingRestyles
// but it is also called when we have out-of-band changes to animations
// such as changes made through the Web Animations API.
void IncrementAnimationGeneration();
+ static void AddLayerChangesForAnimation(nsIFrame* aFrame,
+ nsIContent* aContent,
+ nsStyleChangeList&
+ aChangeListToProcess);
+
protected:
RestyleManager(StyleBackendType aType, nsPresContext* aPresContext);
virtual ~RestyleManager()
{
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
"leaving dangling pointers from AnimationsWithDestroyedFrame");
}
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -310,16 +310,27 @@ ServoRestyleManager::ProcessPostTraversa
if (MOZ_UNLIKELY(displayContentsNode)) {
MOZ_ASSERT(!styleFrame);
displayContentsNode->mStyle = newContext;
}
if (styleFrame) {
styleFrame->UpdateStyleOfOwnedAnonBoxes(*aStyleSet, aChangeList, changeHint);
}
+
+ // Some changes to animations don't affect the computed style and yet still
+ // require the layer to be updated. For example, pausing an animation via
+ // the Web Animations API won't affect an element's style but still
+ // requires to update the animation on the layer.
+ //
+ // We can sometimes reach this when the animated style is being removed.
+ // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
+ // style or not, we need to call it *after* setting |newContext| to
+ // |styleFrame| to ensure the animated transform has been removed first.
+ AddLayerChangesForAnimation(styleFrame, aElement, aChangeList);
}
const bool descendantsNeedFrames =
aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
const bool traverseElementChildren =
aElement->HasDirtyDescendantsForServo() || descendantsNeedFrames;
const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
if (traverseElementChildren || traverseTextChildren) {