Bug 1365472 - Snapshot elements when their class name is animated; r?heycam draft
authorBrian Birtles <birtles@gmail.com>
Thu, 22 Jun 2017 15:06:37 +0900
changeset 598762 49c141ae11c2c5474af22859b7dcb18678b76b81
parent 598761 b1b2b9c8cdad417cff730e5384ae68eed8a94cca
child 634578 720eb7f923bfc579ba0069433f9dc156e3edeaf5
push id65318
push userbbirtles@mozilla.com
push dateThu, 22 Jun 2017 07:20:54 +0000
reviewersheycam
bugs1365472
milestone56.0a1
Bug 1365472 - Snapshot elements when their class name is animated; r?heycam This patch causes us to trigger a snapshot whenever the class attribute of an element is updated via SMIL animation so that when it comes time to restyle, we have the old value of the attribute to compare against the current value. MozReview-Commit-ID: IVYkhl2D6vz
dom/svg/nsSVGElement.cpp
layout/base/ServoRestyleManager.cpp
layout/base/ServoRestyleManager.h
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -123,24 +123,34 @@ nsSVGElement::GetStyle(nsIDOMCSSStyleDec
 }
 
 //----------------------------------------------------------------------
 // nsSVGElement methods
 
 void
 nsSVGElement::DidAnimateClass()
 {
+  // For Servo, snapshot the element before we change it.
+  nsIPresShell* shell = OwnerDoc()->GetShell();
+  if (shell) {
+    nsPresContext* presContext = shell->GetPresContext();
+    if (presContext && presContext->RestyleManager()->IsServo()) {
+      presContext->RestyleManager()
+                  ->AsServo()
+                  ->ClassAttributeWillBeChangedBySMIL(this);
+    }
+  }
+
   nsAutoString src;
   mClassAttribute.GetAnimValue(src, this);
   if (!mClassAnimAttr) {
     mClassAnimAttr = new nsAttrValue();
   }
   mClassAnimAttr->ParseAtomArray(src);
 
-  nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     shell->RestyleForAnimation(this, eRestyle_Self);
   }
 }
 
 nsresult
 nsSVGElement::Init()
 {
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -831,16 +831,30 @@ AttributeInfluencesOtherPseudoClassState
 }
 
 void
 ServoRestyleManager::AttributeWillChange(Element* aElement,
                                          int32_t aNameSpaceID,
                                          nsIAtom* aAttribute, int32_t aModType,
                                          const nsAttrValue* aNewValue)
 {
+  SnapshotForAttributeChange(aElement, aNameSpaceID, aAttribute);
+}
+
+void
+ServoRestyleManager::ClassAttributeWillBeChangedBySMIL(Element* aElement)
+{
+  SnapshotForAttributeChange(aElement, kNameSpaceID_None, nsGkAtoms::_class);
+}
+
+void
+ServoRestyleManager::SnapshotForAttributeChange(Element* aElement,
+                                                int32_t aNameSpaceID,
+                                                nsIAtom* aAttribute)
+{
   MOZ_ASSERT(!mInStyleRefresh);
 
   if (!aElement->HasServoData()) {
     return;
   }
 
   bool influencesOtherPseudoClassState =
     AttributeInfluencesOtherPseudoClassState(aElement, aAttribute);
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -64,16 +64,17 @@ public:
   void RestyleForAppend(nsIContent* aContainer,
                         nsIContent* aFirstNewContent);
   void ContentStateChanged(nsIContent* aContent, EventStates aStateMask);
   void AttributeWillChange(dom::Element* aElement,
                            int32_t aNameSpaceID,
                            nsIAtom* aAttribute,
                            int32_t aModType,
                            const nsAttrValue* aNewValue);
+  void ClassAttributeWillBeChangedBySMIL(dom::Element* aElement);
 
   void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
                         nsIAtom* aAttribute, int32_t aModType,
                         const nsAttrValue* aOldValue);
 
   nsresult ReparentStyleContext(nsIFrame* aFrame);
 
   /**
@@ -142,16 +143,19 @@ private:
                "ServoRestyleManager should only be used with a Servo-flavored "
                "style backend");
     return PresContext()->StyleSet()->AsServo();
   }
 
   const SnapshotTable& Snapshots() const { return mSnapshots; }
   void ClearSnapshots();
   ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
+  void SnapshotForAttributeChange(mozilla::dom::Element* aElement,
+                                  int32_t aNameSpaceID,
+                                  nsIAtom* aAttribute);
 
   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.
   struct ReentrantChange {
     nsCOMPtr<nsIContent> mContent;