Bug 1379505: Allow calling GetBaseComputedStylesForElement for an unstyled element. r=boris draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 10 Jul 2017 13:33:21 +0200
changeset 607470 e7fb3632804f13bc0e8b531ca137c1954481aada
parent 607469 f936e37dfe095928201bc771648cb0c83ff6351f
child 607471 ca5e7c13d1054d51c8a18b08af587ca102301c48
push id67985
push userbmo:emilio+bugs@crisal.io
push dateWed, 12 Jul 2017 08:36:44 +0000
reviewersboris
bugs1379505
milestone56.0a1
Bug 1379505: Allow calling GetBaseComputedStylesForElement for an unstyled element. r=boris Before this refactoring, getComputedStyle could have side effects, and left the style data in the element, so we could never arrive there without data. There are a few crashtests that caught this, but this was already broken if you called animate() on an element deep in a display: none subtree. MozReview-Commit-ID: 1AvOvhAyOP3
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
dom/animation/test/crashtests/1379606-1.html
dom/animation/test/crashtests/crashtests.list
layout/style/ServoBindingList.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/nsComputedDOMStyle.cpp
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -296,18 +296,17 @@ KeyframeEffectReadOnly::UpdateProperties
 {
   MOZ_ASSERT(aStyleContext);
 
   if (!mDocument->IsStyledByServo()) {
     DoUpdateProperties(Move(aStyleContext));
     return;
   }
 
-  const ServoComputedValues* currentStyle =
-    aStyleContext->ComputedValues();
+  const ServoComputedValues* currentStyle = aStyleContext->ComputedValues();
 
   DoUpdateProperties(currentStyle);
 }
 
 void
 KeyframeEffectReadOnly::UpdateProperties(
   const ServoComputedValues* aComputedValues)
 {
@@ -509,49 +508,53 @@ KeyframeEffectReadOnly::EnsureBaseStyles
 
   nsPresContext* presContext =
     nsContentUtils::GetContextForContent(mTarget->mElement);
   MOZ_ASSERT(presContext,
              "nsPresContext should not be nullptr since this EnsureBaseStyles "
              "supposed to be called right after getting computed values with "
              "a valid nsPresContext");
 
-  RefPtr<ServoComputedValues> baseComputedValues;
+  RefPtr<const ServoComputedValues> baseComputedValues;
   for (const AnimationProperty& property : aProperties) {
     EnsureBaseStyle(property,
                     mTarget->mPseudoType,
                     presContext,
+                    aComputedValues,
                     baseComputedValues);
   }
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyle(
   const AnimationProperty& aProperty,
   CSSPseudoElementType aPseudoType,
   nsPresContext* aPresContext,
-  RefPtr<ServoComputedValues>& aBaseComputedValues)
+  const ServoComputedValues* aComputedStyle,
+  RefPtr<const ServoComputedValues>& aBaseComputedValues)
 {
   bool hasAdditiveValues = false;
 
   for (const AnimationPropertySegment& segment : aProperty.mSegments) {
     if (!segment.HasReplaceableValues()) {
       hasAdditiveValues = true;
       break;
     }
   }
 
   if (!hasAdditiveValues) {
     return;
   }
 
   if (!aBaseComputedValues) {
     aBaseComputedValues =
-      aPresContext->StyleSet()->AsServo()->
-        GetBaseComputedValuesForElement(mTarget->mElement, aPseudoType);
+      aPresContext->StyleSet()->AsServo()->GetBaseComputedValuesForElement(
+          mTarget->mElement,
+          aPseudoType,
+          aComputedStyle);
   }
   RefPtr<RawServoAnimationValue> baseValue =
     Servo_ComputedValues_ExtractAnimationValue(aBaseComputedValues,
                                                aProperty.mProperty).Consume();
   mBaseStyleValuesForServo.Put(aProperty.mProperty, baseValue);
 }
 
 void
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -379,17 +379,18 @@ protected:
   void EnsureBaseStyle(nsCSSPropertyID aProperty,
                        nsStyleContext* aStyleContext,
                        RefPtr<nsStyleContext>& aCachedBaseStyleContext);
   // Stylo version of the above function that also first checks for an additive
   // value in |aProperty|'s list of segments.
   void EnsureBaseStyle(const AnimationProperty& aProperty,
                        CSSPseudoElementType aPseudoType,
                        nsPresContext* aPresContext,
-                       RefPtr<ServoComputedValues>& aBaseComputedValues);
+                       const ServoComputedValues* aComputedValues,
+                       RefPtr<const ServoComputedValues>& aBaseComputedValues);
 
   Maybe<OwningAnimationTarget> mTarget;
 
   KeyframeEffectParams mEffectOptions;
 
   // The specified keyframes.
   nsTArray<Keyframe>          mKeyframes;
 
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1379606-1.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<style>
+div {
+  display: none;
+}
+</style>
+<div>
+<div>
+<div>
+<div>
+<div>
+<div id="target">
+</div>
+</div>
+</div>
+</div>
+</div>
+</div>
+<script>
+  target.animate({ color: "red" })
+</script>
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -23,8 +23,9 @@ pref(dom.animations-api.core.enabled,tru
 pref(dom.animations-api.core.enabled,true) load 1330513-1.html
 pref(dom.animations-api.core.enabled,true) load 1333539-1.html
 pref(dom.animations-api.core.enabled,true) load 1333539-2.html
 pref(dom.animations-api.core.enabled,true) load 1334583-1.html
 pref(dom.animations-api.core.enabled,true) load 1335998-1.html
 pref(dom.animations-api.core.enabled,true) load 1343589-1.html
 pref(dom.animations-api.core.enabled,true) load 1359658-1.html
 pref(dom.animations-api.core.enabled,true) load 1373712-1.html
+pref(dom.animations-api.core.enabled,true) load 1379606-1.html
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -536,16 +536,17 @@ SERVO_BINDING_FUNC(Servo_AssertTreeIsCle
 // and if so, frees them.
 SERVO_BINDING_FUNC(Servo_MaybeGCRuleTree, void, RawServoStyleSetBorrowed set)
 
 // Returns computed values for the given element without any animations rules.
 SERVO_BINDING_FUNC(Servo_StyleSet_GetBaseComputedValuesForElement,
                    ServoComputedValuesStrong,
                    RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowed element,
+                   ServoComputedValuesBorrowed existing_style,
                    const mozilla::ServoElementSnapshotTable* snapshots,
                    mozilla::CSSPseudoElementType pseudo_type)
 
 // For canvas font.
 SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsAString* buffer)
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1069,21 +1069,24 @@ ServoStyleSet::GetAnimationValues(
   Servo_GetAnimationValues(aDeclarations,
                            aElement,
                            aComputedValues,
                            mRawSet.get(),
                            &aAnimationValues);
 }
 
 already_AddRefed<ServoComputedValues>
-ServoStyleSet::GetBaseComputedValuesForElement(Element* aElement,
-                                               CSSPseudoElementType aPseudoType)
+ServoStyleSet::GetBaseComputedValuesForElement(
+  Element* aElement,
+  CSSPseudoElementType aPseudoType,
+  ServoComputedValuesBorrowed aStyle)
 {
   return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
                                                         aElement,
+                                                        aStyle,
                                                         &Snapshots(),
                                                         aPseudoType).Consume();
 }
 
 already_AddRefed<RawServoAnimationValue>
 ServoStyleSet::ComputeAnimationValue(
   Element* aElement,
   RawServoDeclarationBlock* aDeclarations,
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -379,17 +379,18 @@ public:
                      nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues);
 
   bool AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray);
 
   nsCSSCounterStyleRule* CounterStyleRuleForName(nsIAtom* aName);
 
   already_AddRefed<ServoComputedValues>
   GetBaseComputedValuesForElement(dom::Element* aElement,
-                                  CSSPseudoElementType aPseudoType);
+                                  CSSPseudoElementType aPseudoType,
+                                  ServoComputedValuesBorrowed aStyle);
 
   /**
    * Resolve style for a given declaration block with/without the parent style.
    * If the parent style is not specified, the document default computed values
    * is used.
    */
   already_AddRefed<ServoComputedValues>
   ResolveForDeclarations(ServoComputedValuesBorrowedOrNull aParentOrNull,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -637,17 +637,18 @@ nsComputedDOMStyle::DoGetStyleContextNoF
           MOZ_ASSERT(presContext, "Should have a prescontext if we have a frame");
           if (presContext && presContext->StyleSet()->IsGecko()) {
             nsStyleSet* styleSet = presContext->StyleSet()->AsGecko();
             return styleSet->ResolveStyleByRemovingAnimation(
                      aElement, result, eRestyle_AllHintsWithAnimations);
           } else {
             RefPtr<ServoComputedValues> baseComputedValues =
               presContext->StyleSet()->AsServo()->
-                GetBaseComputedValuesForElement(aElement, pseudoType);
+                GetBaseComputedValuesForElement(
+                    aElement, pseudoType, result->ComputedValues());
             return ServoStyleContext::Create(nullptr, presContext, aPseudo,
                                              pseudoType, baseComputedValues.forget());
           }
         }
 
         // this function returns an addrefed style context
         RefPtr<nsStyleContext> ret = result;
         return ret.forget();
@@ -672,17 +673,18 @@ nsComputedDOMStyle::DoGetStyleContextNoF
                                : StyleRuleInclusion::All;
     RefPtr<nsStyleContext> result =
        servoSet->ResolveTransientStyle(aElement, aPseudo, pseudoType, rules);
     if (aAnimationFlag == eWithAnimation) {
       return result.forget();
     }
 
     RefPtr<ServoComputedValues> baseComputedValues =
-      servoSet->GetBaseComputedValuesForElement(aElement, pseudoType);
+      servoSet->GetBaseComputedValuesForElement(
+          aElement, pseudoType, result->ComputedValues());
     return ServoStyleContext::Create(nullptr, presContext, aPseudo,
                                      pseudoType, baseComputedValues.forget());
   }
 
   RefPtr<nsStyleContext> parentContext;
   nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
   // Don't resolve parent context for document fragments.
   if (parent && parent->IsElement()) {