Bug 1174575 - Part 6: Implement KeyframeEffectReadOnly Constructor for CSSPseudoElement. r=birtles
authorBoris Chiou <boris.chiou@gmail.com>
Tue, 09 Feb 2016 05:05:00 +0100
changeset 321864 70be723fde4a63c1aa4f12eef7cdde821c6cd446
parent 321863 989f065259c4318ab6684d876204a4db67e58a46
child 321865 b973ffb1e6421cf7a4f5c2d5a5ea1ae1a1bd6c1f
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1174575
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1174575 - Part 6: Implement KeyframeEffectReadOnly Constructor for CSSPseudoElement. r=birtles Let KeyframeEffectReadOnly::Constructor support both Element and CSSPseudoElement as the target.
dom/animation/CSSPseudoElement.h
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffect.h
--- a/dom/animation/CSSPseudoElement.h
+++ b/dom/animation/CSSPseudoElement.h
@@ -35,16 +35,17 @@ public:
   ParentObject GetParentObject() const
   {
     return mParentElement->GetParentObject();
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
+  nsCSSPseudoElements::Type GetType() const { return mPseudoType; }
   void GetType(nsString& aRetVal) const
   {
     MOZ_ASSERT(nsCSSPseudoElements::GetPseudoAtom(mPseudoType),
                "All pseudo-types allowed by this class should have a"
                " corresponding atom");
     nsCSSPseudoElements::GetPseudoAtom(mPseudoType)->ToString(aRetVal);
   }
   already_AddRefed<Element> ParentElement() const
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1142,32 +1142,36 @@ ApplyDistributeSpacing(nsTArray<OffsetIn
  * Splits out each property's keyframe animation segment information
  * from the OffsetIndexedKeyframe objects into an array of KeyframeValueEntry.
  *
  * The easing string value in OffsetIndexedKeyframe objects is parsed
  * into a ComputedTimingFunction value in the corresponding KeyframeValueEntry
  * objects.
  *
  * @param aTarget The target of the animation.
+ * @param aPseudoType The pseudo type of the target if it is a pseudo element.
  * @param aKeyframes The keyframes to read.
  * @param aResult The array to append the resulting KeyframeValueEntry
  *   objects to.
  */
 static void
 GenerateValueEntries(Element* aTarget,
+                     nsCSSPseudoElements::Type aPseudoType,
                      nsTArray<OffsetIndexedKeyframe>& aKeyframes,
                      nsTArray<KeyframeValueEntry>& aResult,
                      ErrorResult& aRv)
 {
   nsCSSPropertySet properties;              // All properties encountered.
   nsCSSPropertySet propertiesWithFromValue; // Those with a defined 0% value.
   nsCSSPropertySet propertiesWithToValue;   // Those with a defined 100% value.
 
   for (OffsetIndexedKeyframe& keyframe : aKeyframes) {
     float offset = float(keyframe.mKeyframeDict.mOffset.Value());
+    // ParseEasing uses element's owner doc, so if it is a pseudo element,
+    // we use its parent element's owner doc.
     Maybe<ComputedTimingFunction> easing =
       AnimationUtils::ParseEasing(aTarget, keyframe.mKeyframeDict.mEasing);
     // We ignore keyframe.mKeyframeDict.mComposite since we don't support
     // composite modes on keyframes yet.
 
     // keyframe.mPropertyValuePairs is currently sorted by CSS property IDL
     // name, since that was the order we read the properties from the JS
     // object.  Re-sort the list so that longhand properties appear before
@@ -1192,24 +1196,23 @@ GenerateValueEntries(Element* aTarget,
     nsCSSPropertySet propertiesOnThisKeyframe;
     for (const PropertyValuesPair& pair : keyframe.mPropertyValuePairs) {
       MOZ_ASSERT(pair.mValues.Length() == 1,
                  "ConvertKeyframeSequence should have parsed single "
                  "DOMString values from the property-values pairs");
       // Parse the property's string value and produce a KeyframeValueEntry (or
       // more than one, for shorthands) for it.
       nsTArray<PropertyStyleAnimationValuePair> values;
-      if (StyleAnimationValue::ComputeValues(
-            pair.mProperty,
-            nsCSSProps::eEnabledForAllContent,
-            aTarget,
-            nsCSSPseudoElements::ePseudo_NotPseudoElement,
-            pair.mValues[0],
-            /* aUseSVGMode */ false,
-            values)) {
+      if (StyleAnimationValue::ComputeValues(pair.mProperty,
+                                             nsCSSProps::eEnabledForAllContent,
+                                             aTarget,
+                                             aPseudoType,
+                                             pair.mValues[0],
+                                             /* aUseSVGMode */ false,
+                                             values)) {
         for (auto& value : values) {
           // If we already got a value for this property on the keyframe,
           // skip this one.
           if (propertiesOnThisKeyframe.HasProperty(value.mProperty)) {
             continue;
           }
 
           KeyframeValueEntry* entry = aResult.AppendElement();
@@ -1350,16 +1353,17 @@ BuildSegmentsFromValueEntries(nsTArray<K
  *   object to iterate over as a sequence.
  * @param aResult The array into which the resulting AnimationProperty
  *   objects will be appended.
  */
 static void
 BuildAnimationPropertyListFromKeyframeSequence(
     JSContext* aCx,
     Element* aTarget,
+    nsCSSPseudoElements::Type aPseudoType,
     JS::ForOfIterator& aIterator,
     nsTArray<AnimationProperty>& aResult,
     ErrorResult& aRv)
 {
   // Convert the object in aIterator to sequence<Keyframe>, producing
   // an array of OffsetIndexedKeyframe objects.
   AutoTArray<OffsetIndexedKeyframe,4> keyframes;
   if (!ConvertKeyframeSequence(aCx, aIterator, keyframes)) {
@@ -1383,17 +1387,17 @@ BuildAnimationPropertyListFromKeyframeSe
   // Fill in 0%/100% values if the first/element keyframes don't have
   // a specified offset, and evenly space those that have a missing
   // offset.  (We don't support paced spacing yet.)
   ApplyDistributeSpacing(keyframes);
 
   // Convert the OffsetIndexedKeyframes into a list of KeyframeValueEntry
   // objects.
   nsTArray<KeyframeValueEntry> entries;
-  GenerateValueEntries(aTarget, keyframes, entries, aRv);
+  GenerateValueEntries(aTarget, aPseudoType, keyframes, entries, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   // Finally, build an array of AnimationProperty objects in aResult
   // corresponding to the entries.
   BuildSegmentsFromValueEntries(entries, aResult);
 }
@@ -1407,31 +1411,34 @@ BuildAnimationPropertyListFromKeyframeSe
  * @param aValue The JS object.
  * @param aResult The array into which the resulting AnimationProperty
  *   objects will be appended.
  */
 static void
 BuildAnimationPropertyListFromPropertyIndexedKeyframes(
     JSContext* aCx,
     Element* aTarget,
+    nsCSSPseudoElements::Type aPseudoType,
     JS::Handle<JS::Value> aValue,
     InfallibleTArray<AnimationProperty>& aResult,
     ErrorResult& aRv)
 {
   MOZ_ASSERT(aValue.isObject());
 
   // Convert the object to a PropertyIndexedKeyframes dictionary to
   // get its explicit dictionary members.
   binding_detail::FastPropertyIndexedKeyframes keyframes;
   if (!keyframes.Init(aCx, aValue, "PropertyIndexedKeyframes argument",
                       false)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
+  // ParseEasing uses element's owner doc, so if it is a pseudo element,
+  // we use its parent element's owner doc.
   Maybe<ComputedTimingFunction> easing =
     AnimationUtils::ParseEasing(aTarget, keyframes.mEasing);
 
   // We ignore easing.mComposite since we don't support composite modes on
   // keyframes yet.
 
   // Get all the property--value-list pairs off the object.
   JS::Rooted<JSObject*> object(aCx, &aValue.toObject());
@@ -1474,24 +1481,23 @@ BuildAnimationPropertyListFromPropertyIn
     //   0.25 -> 0.50 : green -> yellow
     //   0.50 -> 1.00 : yellow -> blue
     //
     // With future spec clarifications we might decide to preserve the invalid
     // value on the segment and make the animation code deal with the invalid
     // value instead.
     nsTArray<PropertyStyleAnimationValuePair> fromValues;
     float fromKey = 0.0f;
-    if (!StyleAnimationValue::ComputeValues(
-          pair.mProperty,
-          nsCSSProps::eEnabledForAllContent,
-          aTarget,
-          nsCSSPseudoElements::ePseudo_NotPseudoElement,
-          pair.mValues[0],
-          /* aUseSVGMode */ false,
-          fromValues)) {
+    if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+                                            nsCSSProps::eEnabledForAllContent,
+                                            aTarget,
+                                            aPseudoType,
+                                            pair.mValues[0],
+                                            /* aUseSVGMode */ false,
+                                            fromValues)) {
       // We need to throw for an invalid first value, since that would imply an
       // additive animation, which we don't support yet.
       aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
       return;
     }
 
     if (fromValues.IsEmpty()) {
       // All longhand components of a shorthand pair.mProperty must be disabled.
@@ -1528,24 +1534,23 @@ BuildAnimationPropertyListFromPropertyIn
         properties.AddProperty(p);
       }
     }
 
     double portion = 1.0 / (count - 1);
     for (size_t i = 0; i < count - 1; ++i) {
       nsTArray<PropertyStyleAnimationValuePair> toValues;
       float toKey = (i + 1) * portion;
-      if (!StyleAnimationValue::ComputeValues(
-            pair.mProperty,
-            nsCSSProps::eEnabledForAllContent,
-            aTarget,
-            nsCSSPseudoElements::ePseudo_NotPseudoElement,
-            pair.mValues[i + 1],
-            /* aUseSVGMode */ false,
-            toValues)) {
+      if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+                                              nsCSSProps::eEnabledForAllContent,
+                                              aTarget,
+                                              aPseudoType,
+                                              pair.mValues[i + 1],
+                                              /* aUseSVGMode */ false,
+                                              toValues)) {
         if (i + 1 == count - 1) {
           // We need to throw for an invalid last value, since that would
           // imply an additive animation, which we don't support yet.
           aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
           return;
         }
         // Otherwise, skip the segment.
         continue;
@@ -1581,16 +1586,17 @@ BuildAnimationPropertyListFromPropertyIn
  *   that is the keyframe list specification.
  * @param aResult The array into which the resulting AnimationProperty
  *   objects will be appended.
  */
 /* static */ void
 KeyframeEffectReadOnly::BuildAnimationPropertyList(
     JSContext* aCx,
     Element* aTarget,
+    nsCSSPseudoElements::Type aPseudoType,
     JS::Handle<JSObject*> aFrames,
     InfallibleTArray<AnimationProperty>& aResult,
     ErrorResult& aRv)
 {
   MOZ_ASSERT(aResult.IsEmpty());
 
   // A frame list specification in the IDL is:
   //
@@ -1614,58 +1620,71 @@ KeyframeEffectReadOnly::BuildAnimationPr
   JS::Rooted<JS::Value> objectValue(aCx, JS::ObjectValue(*aFrames));
   JS::ForOfIterator iter(aCx);
   if (!iter.init(objectValue, JS::ForOfIterator::AllowNonIterable)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   if (iter.valueIsIterable()) {
-    BuildAnimationPropertyListFromKeyframeSequence(aCx, aTarget, iter,
-                                                   aResult, aRv);
+    BuildAnimationPropertyListFromKeyframeSequence(aCx, aTarget, aPseudoType,
+                                                   iter, aResult, aRv);
   } else {
     BuildAnimationPropertyListFromPropertyIndexedKeyframes(aCx, aTarget,
+                                                           aPseudoType,
                                                            objectValue, aResult,
                                                            aRv);
   }
 }
 
 /* static */ already_AddRefed<KeyframeEffectReadOnly>
 KeyframeEffectReadOnly::Constructor(
     const GlobalObject& aGlobal,
     const Nullable<ElementOrCSSPseudoElement>& aTarget,
     JS::Handle<JSObject*> aFrames,
     const TimingParams& aTiming,
     ErrorResult& aRv)
 {
-  if (aTarget.IsNull() || aTarget.Value().IsCSSPseudoElement()) {
-    // We don't support null or CSSPseudoElement targets yet.
+  if (aTarget.IsNull()) {
+    // We don't support null targets yet.
     aRv.Throw(NS_ERROR_DOM_ANIM_NO_TARGET_ERR);
     return nullptr;
   }
 
-  Element& targetElement = aTarget.Value().GetAsElement();
-  if (!targetElement.GetCurrentDoc()) {
+  const ElementOrCSSPseudoElement& target = aTarget.Value();
+  MOZ_ASSERT(target.IsElement() || target.IsCSSPseudoElement(),
+             "Uninitialized target");
+
+  RefPtr<Element> targetElement;
+  nsCSSPseudoElements::Type pseudoType =
+    nsCSSPseudoElements::ePseudo_NotPseudoElement;
+  if (target.IsElement()) {
+    targetElement = &target.GetAsElement();
+  } else {
+    targetElement = target.GetAsCSSPseudoElement().ParentElement();
+    pseudoType = target.GetAsCSSPseudoElement().GetType();
+  }
+
+  if (!targetElement->GetCurrentDoc()) {
     // Bug 1245748: We don't support targets that are not in a document yet.
     aRv.Throw(NS_ERROR_DOM_ANIM_TARGET_NOT_IN_DOC_ERR);
     return nullptr;
   }
 
   InfallibleTArray<AnimationProperty> animationProperties;
-  BuildAnimationPropertyList(aGlobal.Context(), &targetElement, aFrames,
-                             animationProperties, aRv);
+  BuildAnimationPropertyList(aGlobal.Context(), targetElement, pseudoType,
+                             aFrames, animationProperties, aRv);
 
   if (aRv.Failed()) {
     return nullptr;
   }
 
   RefPtr<KeyframeEffectReadOnly> effect =
-    new KeyframeEffectReadOnly(targetElement.OwnerDoc(), &targetElement,
-                               nsCSSPseudoElements::ePseudo_NotPseudoElement,
-                               aTiming);
+    new KeyframeEffectReadOnly(targetElement->OwnerDoc(), targetElement,
+                               pseudoType, aTiming);
   effect->mProperties = Move(animationProperties);
   return effect.forget();
 }
 
 void
 KeyframeEffectReadOnly::GetTarget(
     Nullable<OwningElementOrCSSPseudoElement>& aRv) const
 {
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -340,16 +340,17 @@ protected:
   // As a result, we need to make sure this gets called whenever anything
   // changes with regards to this effects's timing including changes to the
   // owning Animation's timing.
   void UpdateTargetRegistration();
 
   static void BuildAnimationPropertyList(
     JSContext* aCx,
     Element* aTarget,
+    nsCSSPseudoElements::Type aPseudoType,
     JS::Handle<JSObject*> aFrames,
     InfallibleTArray<AnimationProperty>& aResult,
     ErrorResult& aRv);
 
   nsCOMPtr<Element> mTarget;
   RefPtr<Animation> mAnimation;
 
   OwningNonNull<AnimationEffectTimingReadOnly> mTiming;