mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Bug 1334036 - Part 11: Trigger animation-only restyle when we handle an event with coordinates. r=birtles,heycam
We need to request an animation-only restyle to force flush all throttled animations on main thread when we handle an event with coordinates (e.g. mouse event). MozReview-Commit-ID: KkjeQVsLgTl --HG-- extra : rebase_source : 314408062e719e9f52df9a6726e2f3dad817bbef
This commit is contained in:
parent
731ab38439
commit
38215cedea
@ -957,13 +957,14 @@ EffectCompositor::SetPerformanceWarning(
|
||||
}
|
||||
|
||||
bool
|
||||
EffectCompositor::PreTraverse()
|
||||
EffectCompositor::PreTraverse(AnimationRestyleType aRestyleType)
|
||||
{
|
||||
return PreTraverseInSubtree(nullptr);
|
||||
return PreTraverseInSubtree(nullptr, aRestyleType);
|
||||
}
|
||||
|
||||
bool
|
||||
EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
||||
EffectCompositor::PreTraverseInSubtree(Element* aRoot,
|
||||
AnimationRestyleType aRestyleType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
|
||||
@ -971,9 +972,13 @@ EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
||||
AutoRestore<bool> guard(mIsInPreTraverse);
|
||||
mIsInPreTraverse = true;
|
||||
|
||||
// We need to force flush all throttled animations if there are any
|
||||
// non-animation restyles.
|
||||
bool flushThrottledRestyles = aRoot && aRoot->HasDirtyDescendantsForServo();
|
||||
// We need to force flush all throttled animations if we also have
|
||||
// non-animation restyles (since we'll want the up-to-date animation style
|
||||
// when we go to process them so we can trigger transitions correctly), and
|
||||
// if we are currently flushing all throttled animation restyles.
|
||||
bool flushThrottledRestyles =
|
||||
(aRoot && aRoot->HasDirtyDescendantsForServo()) ||
|
||||
aRestyleType == AnimationRestyleType::Full;
|
||||
|
||||
using ElementsToRestyleIterType =
|
||||
nsDataHashtable<PseudoElementHashEntry, bool>::Iterator;
|
||||
@ -1092,8 +1097,9 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
|
||||
|
||||
PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
|
||||
|
||||
// We need to flush all throttled animation restyles too if there are
|
||||
// any non-animation restyles.
|
||||
// We need to flush all throttled animation restyles too if we also have
|
||||
// non-animation restyles (since we'll want the up-to-date animation style
|
||||
// when we go to process them so we can trigger transitions correctly).
|
||||
Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
|
||||
bool flushThrottledRestyles = elementToRestyle &&
|
||||
elementToRestyle->HasDirtyDescendantsForServo();
|
||||
|
@ -227,18 +227,27 @@ public:
|
||||
nsCSSPropertyID aProperty,
|
||||
const AnimationPerformanceWarning& aWarning);
|
||||
|
||||
// The type which represents what kind of animation restyle we want.
|
||||
enum class AnimationRestyleType {
|
||||
Throttled, // Restyle elements that have posted animation restyles.
|
||||
Full // Restyle all elements with animations (i.e. even if the
|
||||
// animations are throttled).
|
||||
};
|
||||
|
||||
// Do a bunch of stuff that we should avoid doing during the parallel
|
||||
// traversal (e.g. changing member variables) for all elements that we expect
|
||||
// to restyle on the next traversal.
|
||||
//
|
||||
// Returns true if there are elements needing a restyle for animation.
|
||||
bool PreTraverse();
|
||||
bool PreTraverse(AnimationRestyleType aRestyleType);
|
||||
|
||||
// Similar to the above but only for the (pseudo-)element.
|
||||
bool PreTraverse(dom::Element* aElement, CSSPseudoElementType aPseudoType);
|
||||
|
||||
// Similar to the above but for all elements in the subtree rooted
|
||||
// at aElement.
|
||||
bool PreTraverseInSubtree(dom::Element* aElement);
|
||||
bool PreTraverseInSubtree(dom::Element* aElement,
|
||||
AnimationRestyleType aRestyleType);
|
||||
|
||||
private:
|
||||
~EffectCompositor() = default;
|
||||
|
@ -6946,10 +6946,7 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
||||
if (shell && shell->IsVisible()) {
|
||||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (presContext) {
|
||||
if (presContext->RestyleManager()->IsGecko()) {
|
||||
// XXX stylo: ServoRestyleManager doesn't support animations yet.
|
||||
presContext->RestyleManager()->AsGecko()->UpdateOnlyAnimationStyles();
|
||||
}
|
||||
presContext->RestyleManager()->UpdateOnlyAnimationStyles();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,8 @@ public:
|
||||
const nsAttrValue* aOldValue);
|
||||
inline nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
inline void UpdateOnlyAnimationStyles();
|
||||
|
||||
// Get a counter that increments on every style change, that we use to
|
||||
// track whether off-main-thread animations are up-to-date.
|
||||
uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
|
||||
|
@ -79,6 +79,12 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
||||
MOZ_STYLO_FORWARD(ReparentStyleContext, (aFrame));
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::UpdateOnlyAnimationStyles()
|
||||
{
|
||||
MOZ_STYLO_FORWARD(UpdateOnlyAnimationStyles, ());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_RestyleManagerInlines_h
|
||||
|
@ -514,7 +514,8 @@ ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
|
||||
aRestyleBehavior)
|
||||
{
|
||||
MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!");
|
||||
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
|
||||
@ -536,6 +537,8 @@ ServoRestyleManager::ProcessPendingRestyles()
|
||||
|
||||
ServoStyleSet* styleSet = StyleSet();
|
||||
nsIDocument* doc = PresContext()->Document();
|
||||
bool animationOnly = aRestyleBehavior ==
|
||||
TraversalRestyleBehavior::ForAnimationOnly;
|
||||
|
||||
// Ensure the refresh driver is active during traversal to avoid mutating
|
||||
// mActiveTimer and mMostRecentRefresh time.
|
||||
@ -546,12 +549,15 @@ ServoRestyleManager::ProcessPendingRestyles()
|
||||
// in a loop because certain rare paths in the frame constructor (like
|
||||
// uninstalling XBL bindings) can trigger additional style validations.
|
||||
mInStyleRefresh = true;
|
||||
if (mHaveNonAnimationRestyles) {
|
||||
if (mHaveNonAnimationRestyles && !animationOnly) {
|
||||
++mAnimationGeneration;
|
||||
}
|
||||
|
||||
while (styleSet->StyleDocument()) {
|
||||
ClearSnapshots();
|
||||
while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
|
||||
: styleSet->StyleDocument()) {
|
||||
if (!animationOnly) {
|
||||
ClearSnapshots();
|
||||
}
|
||||
|
||||
// Recreate style contexts, and queue up change hints (which also handle
|
||||
// lazy frame construction).
|
||||
@ -582,12 +588,14 @@ ServoRestyleManager::ProcessPendingRestyles()
|
||||
IncrementRestyleGeneration();
|
||||
}
|
||||
|
||||
ClearSnapshots();
|
||||
FlushOverflowChangedTracker();
|
||||
|
||||
mHaveNonAnimationRestyles = false;
|
||||
if (!animationOnly) {
|
||||
ClearSnapshots();
|
||||
styleSet->AssertTreeIsClean();
|
||||
mHaveNonAnimationRestyles = false;
|
||||
}
|
||||
mInStyleRefresh = false;
|
||||
styleSet->AssertTreeIsClean();
|
||||
|
||||
// Note: We are in the scope of |animationsWithDestroyedFrame|, so
|
||||
// |mAnimationsWithDestroyedFrame| is still valid.
|
||||
@ -595,6 +603,24 @@ ServoRestyleManager::ProcessPendingRestyles()
|
||||
mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
{
|
||||
DoProcessPendingRestyles(TraversalRestyleBehavior::Normal);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::UpdateOnlyAnimationStyles()
|
||||
{
|
||||
// Bug 1365855: We also need to implement this for SMIL.
|
||||
bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
|
||||
if (!doCSS) {
|
||||
return;
|
||||
}
|
||||
|
||||
DoProcessPendingRestyles(TraversalRestyleBehavior::ForAnimationOnly);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
|
||||
nsIContent* aChild)
|
||||
|
@ -50,6 +50,8 @@ public:
|
||||
nsRestyleHint aRestyleHint);
|
||||
void ProcessPendingRestyles();
|
||||
|
||||
void UpdateOnlyAnimationStyles();
|
||||
|
||||
void ContentInserted(nsINode* aContainer, nsIContent* aChild);
|
||||
void ContentAppended(nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent);
|
||||
@ -138,6 +140,8 @@ private:
|
||||
void ClearSnapshots();
|
||||
ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
|
||||
|
||||
void DoProcessPendingRestyles(TraversalRestyleBehavior aRestyleBehavior);
|
||||
|
||||
// We use a separate data structure from nsStyleChangeList because we need a
|
||||
// frame to create nsStyleChangeList entries, and the primary frame may not be
|
||||
// attached yet.
|
||||
|
@ -270,7 +270,8 @@ ServoStyleSet::PreTraverseSync()
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::PreTraverse(Element* aRoot)
|
||||
ServoStyleSet::PreTraverse(Element* aRoot,
|
||||
EffectCompositor::AnimationRestyleType aRestyleType)
|
||||
{
|
||||
PreTraverseSync();
|
||||
|
||||
@ -279,12 +280,13 @@ ServoStyleSet::PreTraverse(Element* aRoot)
|
||||
nsSMILAnimationController* smilController =
|
||||
mPresContext->Document()->GetAnimationController();
|
||||
if (aRoot) {
|
||||
mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
|
||||
mPresContext->EffectCompositor()
|
||||
->PreTraverseInSubtree(aRoot, aRestyleType);
|
||||
if (smilController) {
|
||||
smilController->PreTraverseInSubtree(aRoot);
|
||||
}
|
||||
} else {
|
||||
mPresContext->EffectCompositor()->PreTraverse();
|
||||
mPresContext->EffectCompositor()->PreTraverse(aRestyleType);
|
||||
if (smilController) {
|
||||
smilController->PreTraverse();
|
||||
}
|
||||
@ -310,10 +312,18 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
||||
bool isInitial = !aRoot->HasServoData();
|
||||
bool forReconstruct =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
|
||||
bool forAnimationOnly =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForAnimationOnly;
|
||||
bool postTraversalRequired = Servo_TraverseSubtree(
|
||||
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
|
||||
MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
|
||||
|
||||
// Don't need to trigger a second traversal if this restyle only needs
|
||||
// animation-only restyle.
|
||||
if (forAnimationOnly) {
|
||||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
auto root = const_cast<Element*>(aRoot);
|
||||
|
||||
// If there are still animation restyles needed, trigger a second traversal to
|
||||
@ -324,8 +334,10 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
||||
// traversal caused, for example, the font-size to change, the SMIL style
|
||||
// won't be updated until the next tick anyway.
|
||||
EffectCompositor* compositor = mPresContext->EffectCompositor();
|
||||
if (forReconstruct ? compositor->PreTraverseInSubtree(root)
|
||||
: compositor->PreTraverse()) {
|
||||
EffectCompositor::AnimationRestyleType restyleType =
|
||||
EffectCompositor::AnimationRestyleType::Throttled;
|
||||
if (forReconstruct ? compositor->PreTraverseInSubtree(root, restyleType)
|
||||
: compositor->PreTraverse(restyleType)) {
|
||||
if (Servo_TraverseSubtree(
|
||||
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior)) {
|
||||
MOZ_ASSERT(!forReconstruct);
|
||||
@ -851,6 +863,23 @@ ServoStyleSet::StyleDocument()
|
||||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
bool
|
||||
ServoStyleSet::StyleDocumentForAnimationOnly()
|
||||
{
|
||||
PreTraverse(nullptr, EffectCompositor::AnimationRestyleType::Full);
|
||||
|
||||
bool postTraversalRequired = false;
|
||||
DocumentStyleRootIterator iter(mPresContext->Document());
|
||||
while (Element* root = iter.GetNextStyleRoot()) {
|
||||
if (PrepareAndTraverseSubtree(root,
|
||||
TraversalRootBehavior::Normal,
|
||||
TraversalRestyleBehavior::ForAnimationOnly)) {
|
||||
postTraversalRequired = true;
|
||||
}
|
||||
}
|
||||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleNewSubtree(Element* aRoot)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef mozilla_ServoStyleSet_h
|
||||
#define mozilla_ServoStyleSet_h
|
||||
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/PostTraversalTask.h"
|
||||
@ -245,6 +246,15 @@ public:
|
||||
*/
|
||||
bool StyleDocument();
|
||||
|
||||
/**
|
||||
* Performs a Servo animation-only traversal to compute style for all nodes
|
||||
* with the animation-only dirty bit in the document.
|
||||
*
|
||||
* This will traverse all of the document's style roots (that is, its document
|
||||
* element, and the roots of the document-level native anonymous content).
|
||||
*/
|
||||
bool StyleDocumentForAnimationOnly();
|
||||
|
||||
/**
|
||||
* Eagerly styles a subtree of unstyled nodes that was just appended to the
|
||||
* tree. This is used in situations where we need the style immediately and
|
||||
@ -422,7 +432,9 @@ private:
|
||||
* When aRoot is null, the entire document is pre-traversed. Otherwise,
|
||||
* only the subtree rooted at aRoot is pre-traversed.
|
||||
*/
|
||||
void PreTraverse(dom::Element* aRoot = nullptr);
|
||||
void PreTraverse(dom::Element* aRoot = nullptr,
|
||||
EffectCompositor::AnimationRestyleType =
|
||||
EffectCompositor::AnimationRestyleType::Throttled);
|
||||
// Subset of the pre-traverse steps that involve syncing up data
|
||||
void PreTraverseSync();
|
||||
|
||||
|
@ -53,14 +53,16 @@ enum class TraversalRootBehavior {
|
||||
UnstyledChildrenOnly,
|
||||
};
|
||||
|
||||
// Indicates whether the Servo style system should perform normal processing or
|
||||
// whether it should traverse in a mode that doesn't generate any change hints,
|
||||
// which is what's required when handling frame reconstruction. The change
|
||||
// hints in this case are unneeded, since the old frames have already been
|
||||
// destroyed.
|
||||
// Indicates whether the Servo style system should perform normal processing,
|
||||
// animation-only processing (so we can flush any throttled animation styles),
|
||||
// or whether it should traverse in a mode that doesn't generate any change
|
||||
// hints, which is what's required when handling frame reconstruction.
|
||||
// The change hints in this case are unneeded, since the old frames have
|
||||
// already been destroyed.
|
||||
enum class TraversalRestyleBehavior {
|
||||
Normal,
|
||||
ForReconstruct,
|
||||
ForAnimationOnly,
|
||||
};
|
||||
|
||||
// Represents which tasks are performed in a SequentialTask of UpdateAnimations.
|
||||
|
Loading…
Reference in New Issue
Block a user