Bug 1355348 - Add SMIL restyles in the stylo pretraverse; r?heycam
MozReview-Commit-ID: mwjkKr6wsr
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -6,16 +6,18 @@
#include "nsSMILAnimationController.h"
#include <algorithm>
#include "mozilla/AutoRestore.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/SVGAnimationElement.h"
+#include "mozilla/RestyleManagerInlines.h"
+#include "nsContentUtils.h"
#include "nsCSSProps.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIPresShellInlines.h"
#include "nsITimer.h"
#include "nsSMILCompositor.h"
#include "nsSMILCSSProperty.h"
#include "nsSMILTimedElement.h"
@@ -718,16 +720,77 @@ nsSMILAnimationController::AddStyleUpdat
aTracker.AddPendingRestyle(key.mElement,
eRestyle_StyleAttribute_Animations,
nsChangeHint(0));
}
mMightHavePendingStyleUpdates = false;
}
+bool
+nsSMILAnimationController::PreTraverse()
+{
+ return PreTraverseInSubtree(nullptr);
+}
+
+bool
+nsSMILAnimationController::PreTraverseInSubtree(Element* aRoot)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mMightHavePendingStyleUpdates) {
+ return false;
+ }
+
+ nsIPresShell* shell = mDocument->GetShell();
+ if (!shell) {
+ return false;
+ }
+
+ nsPresContext* context = shell->GetPresContext();
+ if (!context) {
+ return false;
+ }
+ MOZ_ASSERT(context->RestyleManager()->IsServo(),
+ "PreTraverse should only be called for the servo style system");
+
+ bool foundElementsNeedingRestyle = false;
+ for (auto iter = mAnimationElementTable.Iter(); !iter.Done(); iter.Next()) {
+ SVGAnimationElement* animElement = iter.Get()->GetKey();
+
+ nsSMILTargetIdentifier key;
+ if (!GetTargetIdentifierForAnimation(animElement, key)) {
+ // Something's wrong/missing about animation's target; skip this animation
+ continue;
+ }
+
+ // Ignore restyles that aren't in the flattened tree subtree rooted at
+ // aRoot.
+ if (aRoot &&
+ !nsContentUtils::ContentIsFlattenedTreeDescendantOf(key.mElement,
+ aRoot)) {
+ continue;
+ }
+
+ context->RestyleManager()->AsServo()->
+ PostRestyleEventForAnimations(key.mElement,
+ eRestyle_StyleAttribute_Animations);
+
+ foundElementsNeedingRestyle = true;
+ }
+
+ // Only clear the mMightHavePendingStyleUpdates flag if we definitely posted
+ // all restyles.
+ if (!aRoot) {
+ mMightHavePendingStyleUpdates = false;
+ }
+
+ return foundElementsNeedingRestyle;
+}
+
//----------------------------------------------------------------------
// Add/remove child time containers
nsresult
nsSMILAnimationController::AddChild(nsSMILTimeContainer& aChild)
{
TimeContainerPtrKey* key = mChildContainerTable.PutEntry(&aChild);
NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/smil/nsSMILAnimationController.h
+++ b/dom/smil/nsSMILAnimationController.h
@@ -20,16 +20,17 @@
#include "nsRefreshDriver.h"
struct nsSMILTargetIdentifier;
class nsIDocument;
namespace mozilla {
class RestyleTracker;
namespace dom {
+class Element;
class SVGAnimationElement;
} // namespace dom
} // namespace mozilla
//----------------------------------------------------------------------
// nsSMILAnimationController
//
// The animation controller maintains the animation timer and determines the
@@ -108,16 +109,19 @@ public:
}
void AddStyleUpdatesTo(mozilla::RestyleTracker& aTracker);
bool MightHavePendingStyleUpdates() const
{
return mMightHavePendingStyleUpdates;
}
+ bool PreTraverse();
+ bool PreTraverseInSubtree(mozilla::dom::Element* aRoot);
+
protected:
~nsSMILAnimationController();
// Typedefs
typedef nsPtrHashKey<nsSMILTimeContainer> TimeContainerPtrKey;
typedef nsTHashtable<TimeContainerPtrKey> TimeContainerHashtable;
typedef nsPtrHashKey<mozilla::dom::SVGAnimationElement> AnimationElementPtrKey;
typedef nsTHashtable<AnimationElementPtrKey> AnimationElementHashtable;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -16,16 +16,17 @@
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsCSSAnonBoxes.h"
#include "nsCSSPseudoElements.h"
#include "nsCSSRuleProcessor.h"
#include "nsDeviceContext.h"
#include "nsHTMLStyleSheet.h"
#include "nsIDocumentInlines.h"
#include "nsPrintfCString.h"
+#include "nsSMILAnimationController.h"
#include "nsStyleContext.h"
#include "nsStyleSet.h"
using namespace mozilla;
using namespace mozilla::dom;
ServoStyleSet::ServoStyleSet()
: mPresContext(nullptr)
@@ -258,20 +259,28 @@ ServoStyleSet::PreTraverseSync()
void
ServoStyleSet::PreTraverse(Element* aRoot)
{
PreTraverseSync();
// Process animation stuff that we should avoid doing during the parallel
// traversal.
+ nsSMILAnimationController* smilController =
+ mPresContext->Document()->GetAnimationController();
if (aRoot) {
mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
+ if (smilController) {
+ smilController->PreTraverseInSubtree(aRoot);
+ }
} else {
mPresContext->EffectCompositor()->PreTraverse();
+ if (smilController) {
+ smilController->PreTraverse();
+ }
}
}
bool
ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
TraversalRootBehavior aRootBehavior,
TraversalRestyleBehavior
aRestyleBehavior)
@@ -290,16 +299,21 @@ ServoStyleSet::PrepareAndTraverseSubtree
bool postTraversalRequired =
Servo_TraverseSubtree(aRoot, mRawSet.get(), aRootBehavior, aRestyleBehavior);
MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
auto root = const_cast<Element*>(aRoot);
// If there are still animation restyles needed, trigger a second traversal to
// update CSS animations or transitions' styles.
+ //
+ // We don't need to do this for SMIL since SMIL only updates its animation
+ // values once at the begin of a tick. As a result, even if the previous
+ // 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()) {
if (Servo_TraverseSubtree(aRoot, mRawSet.get(),
aRootBehavior, aRestyleBehavior)) {
MOZ_ASSERT(!forReconstruct);
if (isInitial) {
// We're doing initial styling, and the additional animation