Bug 1328787 - Part 13: Call nsAnimationManager.UpdateAnimations(). r?heycam draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Fri, 27 Jan 2017 10:45:40 +0900
changeset 467029 fe41e2923147be18ad591183552c7947763b8e2d
parent 467027 a207162fe9601c5ddb56bd2aa6afd13ac465fdd5
child 543607 434b5102f7a6905802a8b4cb4d53ff6533efea78
push id43090
push userhikezoe@mozilla.com
push dateFri, 27 Jan 2017 01:50:31 +0000
reviewersheycam
bugs1328787
milestone54.0a1
Bug 1328787 - Part 13: Call nsAnimationManager.UpdateAnimations(). r?heycam MozReview-Commit-ID: CcA3dJaxuYY
layout/base/ServoRestyleManager.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -32,16 +32,23 @@ ServoRestyleManager::PostRestyleEvent(El
 {
   MOZ_ASSERT(!(aMinChangeHint & nsChangeHint_NeutralChange),
              "Didn't expect explicit change hints to be neutral!");
   if (MOZ_UNLIKELY(IsDisconnected()) ||
       MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
     return;
   }
 
+  if (mInStyleRefresh && aRestyleHint == eRestyle_CSSAnimations) {
+    // FIXME: This is the initial restyle for CSS animations when the animation
+    // is created. We have to process this restyle if necessary. Currently we
+    // skip it here and will do this restyle in the next tick.
+    return;
+  }
+
   if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) {
     return; // Nothing to do.
   }
 
   // We allow posting change hints during restyling, but not restyle hints
   // themselves, since those would require us to re-traverse the tree.
   MOZ_ASSERT_IF(mInStyleRefresh, aRestyleHint == 0);
 
@@ -164,17 +171,17 @@ ServoRestyleManager::RecreateStyleContex
     // pointer during the replacement. In practice it's not a huge deal (on
     // GetNextContinuationWithSameStyle the pointer is not dereferenced, only
     // compared), but better not playing with dangling pointers if not needed.
     RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
     MOZ_ASSERT(oldStyleContext);
 
     RefPtr<nsStyleContext> newContext =
       aStyleSet->GetContext(computedValues.forget(), aParentContext, nullptr,
-                            CSSPseudoElementType::NotPseudo);
+                            CSSPseudoElementType::NotPseudo, aElement);
 
     // XXX This could not always work as expected: there are kinds of content
     // with the first split and the last sharing style, but others not. We
     // should handle those properly.
     for (nsIFrame* f = primaryFrame; f;
          f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
       f->SetStyleContext(newContext);
     }
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -6,16 +6,17 @@
 
 #include "mozilla/ServoStyleSet.h"
 
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoRestyleManager.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ElementInlines.h"
+#include "nsAnimationManager.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIDocumentInlines.h"
 #include "nsPrintfCString.h"
 #include "nsStyleContext.h"
 #include "nsStyleSet.h"
 
 using namespace mozilla;
@@ -130,33 +131,54 @@ ServoStyleSet::GetContext(nsIContent* aC
   if (aMayCompute == LazyComputeBehavior::Allow) {
     computedValues =
       Servo_ResolveStyleLazily(element, nullptr, mRawSet.get()).Consume();
   } else {
     computedValues = ResolveServoStyle(element);
   }
 
   MOZ_ASSERT(computedValues);
-  return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
+  return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType,
+                    element);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
-                          CSSPseudoElementType aPseudoType)
+                          CSSPseudoElementType aPseudoType,
+                          Element* aElementForAnimation)
 {
   // XXXbholley: nsStyleSet does visited handling here.
 
   // XXXbholley: Figure out the correct thing to pass here. Does this fixup
   // duplicate something that servo already does?
   bool skipFixup = false;
 
-  return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
-                            aPseudoType, Move(aComputedValues), skipFixup);
+  RefPtr<nsStyleContext> result =
+    NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
+                       aPseudoType, Move(aComputedValues), skipFixup);
+
+  // Ignore animations for print or print preview, and for elements
+  // that are not attached to the document tree.
+  if (mPresContext->IsDynamic() &&
+      aElementForAnimation &&
+      aElementForAnimation->IsInComposedDoc()) {
+    // Update/build CSS animations in the case where animation properties are
+    // changed.
+    // FIXME: This isn't right place to update CSS animations. We should do it
+    // , presumably, in cascade_node() in servo side and process the initial
+    // restyle there too.
+    // To do that we need to make updating CSS animations process independent
+    // from nsStyleContext. Also we need to make the process thread safe.
+    mPresContext->AnimationManager()->UpdateAnimations(result,
+                                                       aElementForAnimation);
+  }
+
+  return result.forget();
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleFor(Element* aElement,
                                nsStyleContext* aParentContext,
                                LazyComputeBehavior aMayCompute,
                                TreeMatchContext& aTreeMatchContext)
 {
@@ -179,33 +201,35 @@ ServoStyleSet::ResolveStyleForText(nsICo
   // enough to do on the main thread, which means that the parallel style system
   // can avoid worrying about text nodes.
   const ServoComputedValues* parentComputedValues =
     aParentContext->StyleSource().AsServoComputedValues();
   RefPtr<ServoComputedValues> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(), parentComputedValues).Consume();
 
   return GetContext(computedValues.forget(), aParentContext,
-                    nsCSSAnonBoxes::mozText, CSSPseudoElementType::AnonBox);
+                    nsCSSAnonBoxes::mozText, CSSPseudoElementType::AnonBox,
+                    nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
 {
   // The parent context can be null if the non-element share a style context
   // with the root of an anonymous subtree.
   const ServoComputedValues* parent =
     aParentContext ? aParentContext->StyleSource().AsServoComputedValues() : nullptr;
   RefPtr<ServoComputedValues> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(), parent).Consume();
   MOZ_ASSERT(computedValues);
 
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::mozOtherNonElement,
-                    CSSPseudoElementType::AnonBox);
+                    CSSPseudoElementType::AnonBox,
+                    nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement,
                                          CSSPseudoElementType aType,
                                          nsStyleContext* aParentContext,
                                          Element* aPseudoElement)
 {
@@ -219,31 +243,35 @@ ServoStyleSet::ResolvePseudoElementStyle
   MOZ_ASSERT(aType < CSSPseudoElementType::Count);
   nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
 
   RefPtr<ServoComputedValues> computedValues =
     Servo_ResolvePseudoStyle(aOriginatingElement, pseudoTag,
                              /* is_probe = */ false, mRawSet.get()).Consume();
   MOZ_ASSERT(computedValues);
 
-  return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
+  bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
+                         aType == CSSPseudoElementType::after;
+  return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
+                    isBeforeOrAfter ? aOriginatingElement : nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveTransientStyle(Element* aElement, CSSPseudoElementType aType)
 {
   nsIAtom* pseudoTag = nullptr;
   if (aType != CSSPseudoElementType::NotPseudo) {
     pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
   }
 
   RefPtr<ServoComputedValues> computedValues =
     Servo_ResolveStyleLazily(aElement, pseudoTag, mRawSet.get()).Consume();
 
-  return GetContext(computedValues.forget(), nullptr, pseudoTag, aType);
+  return GetContext(computedValues.forget(), nullptr, pseudoTag, aType,
+                    nullptr);
 }
 
 // aFlags is an nsStyleSet flags bitfield
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
                                         nsStyleContext* aParentContext,
                                         uint32_t aFlags)
 {
@@ -453,29 +481,30 @@ ServoStyleSet::ProbePseudoElementStyle(E
                              /* is_probe = */ true, mRawSet.get()).Consume();
   if (!computedValues) {
     return nullptr;
   }
 
   // For :before and :after pseudo-elements, having display: none or no
   // 'content' property is equivalent to not having the pseudo-element
   // at all.
-  if (computedValues &&
-      (pseudoTag == nsCSSPseudoElements::before ||
-       pseudoTag == nsCSSPseudoElements::after)) {
+  bool isBeforeOrAfter = pseudoTag == nsCSSPseudoElements::before ||
+                         pseudoTag == nsCSSPseudoElements::after;
+  if (isBeforeOrAfter) {
     const nsStyleDisplay *display = Servo_GetStyleDisplay(computedValues);
     const nsStyleContent *content = Servo_GetStyleContent(computedValues);
     // XXXldb What is contentCount for |content: ""|?
     if (display->mDisplay == StyleDisplay::None ||
         content->ContentCount() == 0) {
       return nullptr;
     }
   }
 
-  return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
+  return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
+                    isBeforeOrAfter ? aOriginatingElement : nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
                                        CSSPseudoElementType aType,
                                        nsStyleContext* aParentContext,
                                        TreeMatchContext& aTreeMatchContext,
                                        Element* aPseudoElement)
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -185,17 +185,18 @@ public:
                             const nsTimingFunction& aTimingFunction,
                             const ServoComputedValues* aComputedValues,
                             nsTArray<Keyframe>& aKeyframes);
 
 private:
   already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
                                               nsStyleContext* aParentContext,
                                               nsIAtom* aPseudoTag,
-                                              CSSPseudoElementType aPseudoType);
+                                              CSSPseudoElementType aPseudoType,
+                                              dom::Element* aElementForAnimation);
 
   already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent,
                                               nsStyleContext* aParentContext,
                                               nsIAtom* aPseudoTag,
                                               CSSPseudoElementType aPseudoType,
                                               LazyComputeBehavior aMayCompute);
 
   nsPresContext* mPresContext;