Bug 1351535 - Part 5: Add EffectCompositor method to pre-traverse within a specific subtree. r=hiro
It's not great that we traverse up the tree looking for the subtree root for
each animating element that is in mElementsToRestyle. An alternative could
be to traverse the entire subtree and build a hash set of the elements
within it, so that each test in the mElementsToRestyle loop can be done
quickly. I suspect that most of the time looking up the tree for
each animation will be quicker, but it does have worse worst case behavior.
MozReview-Commit-ID: FWoQ7fD9YZC
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -958,30 +958,56 @@ EffectCompositor::SetPerformanceWarning(
for (KeyframeEffectReadOnly* effect : *effects) {
effect->SetPerformanceWarning(aProperty, aWarning);
}
}
bool
EffectCompositor::PreTraverse()
{
+ return PreTraverseInSubtree(nullptr);
+}
+
+static bool
+IsFlattenedTreeDescendantOf(nsINode* aPossibleDescendant,
+ nsINode* aPossibleAncestor)
+{
+ do {
+ if (aPossibleDescendant == aPossibleAncestor) {
+ return true;
+ }
+ aPossibleDescendant = aPossibleDescendant->GetFlattenedTreeParentNode();
+ } while (aPossibleDescendant);
+
+ return false;
+}
+
+bool
+EffectCompositor::PreTraverseInSubtree(Element* aRoot)
+{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
bool foundElementsNeedingRestyle = false;
for (auto& elementsToRestyle : mElementsToRestyle) {
for (auto iter = elementsToRestyle.Iter(); !iter.Done(); iter.Next()) {
bool postedRestyle = iter.Data();
// Ignore throttled restyle.
if (!postedRestyle) {
continue;
}
NonOwningAnimationTarget target = iter.Key();
+ // Ignore restyles that aren't in the flattened tree subtree rooted at
+ // aRoot.
+ if (aRoot && !IsFlattenedTreeDescendantOf(target.mElement, aRoot)) {
+ continue;
+ }
+
// We need to post restyle hints even if the target is not in EffectSet to
// ensure the final restyling for removed animations.
// We can't call PostRestyleEvent directly here since we are still in the
// middle of the servo traversal.
mPresContext->RestyleManager()->AsServo()->
PostRestyleEventForAnimations(target.mElement, eRestyle_CSSAnimations);
foundElementsNeedingRestyle = true;
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -244,16 +244,20 @@ public:
// 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();
// Similar to the above but only for the (pseudo-)element.
bool PreTraverse(dom::Element* aElement, nsIAtom* aPseudoTagOrNull);
+ // Similar to the above but for all elements in the subtree rooted
+ // at aElement.
+ bool PreTraverseInSubtree(dom::Element* aElement);
+
private:
~EffectCompositor() = default;
// Rebuilds the animation rule corresponding to |aCascadeLevel| on the
// EffectSet associated with the specified (pseudo-)element.
static void ComposeAnimationRule(dom::Element* aElement,
CSSPseudoElementType aPseudoType,
CascadeLevel aCascadeLevel);