From 119a18fee335866e7268b12a4e3c6e81b6bbdb83 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Tue, 22 Mar 2016 16:36:45 +0900 Subject: [PATCH] Bug 1245748 - Remove no-longer-needed code for directly setting up properties in KeyframeEffect(ReadOnly) constructor; r=heycam MozReview-Commit-ID: 4V3LMByas9Q --HG-- extra : rebase_source : c2c687cd39b8287e7e9cb2a4edd12c86a056a0de --- dom/animation/KeyframeUtils.cpp | 584 +------------------------------- dom/animation/KeyframeUtils.h | 19 -- 2 files changed, 5 insertions(+), 598 deletions(-) diff --git a/dom/animation/KeyframeUtils.cpp b/dom/animation/KeyframeUtils.cpp index 5f342ed4d9dd..6870eb84ad0e 100644 --- a/dom/animation/KeyframeUtils.cpp +++ b/dom/animation/KeyframeUtils.cpp @@ -21,11 +21,6 @@ #include "nsTArray.h" #include // For std::stable_sort -// TODO: Remove once we drop LookupStyleContext -#include "nsComputedDOMStyle.h" -#include "nsIDocument.h" -#include "nsIPresShell.h" - namespace mozilla { // ------------------------------------------------------------------ @@ -231,17 +226,6 @@ struct PropertyValuesPair typedef TPropertyPriorityComparator Comparator; }; -/** - * The result of parsing a JS object as a BaseKeyframe dictionary - * and getting its property-value pairs from its open-ended - * properties. - */ -struct OffsetIndexedKeyframe -{ - dom::binding_detail::FastBaseKeyframe mKeyframeDict; - nsTArray mPropertyValuePairs; -}; - /** * An additional property (for a property-values pair) found on a * BaseKeyframe or BasePropertyIndexedKeyframe object. @@ -267,25 +251,17 @@ struct AdditionalProperty }; }; -/** - * A property and StyleAnimationValue pair. - */ -struct KeyframeValue -{ - nsCSSProperty mProperty; - StyleAnimationValue mValue; -}; - /** * Data for a segment in a keyframe animation of a given property * whose value is a StyleAnimationValue. * - * KeyframeValueEntry is used in BuildAnimationPropertyListFromKeyframeSequence - * to gather data for each individual segment described by an author-supplied - * an IDL sequence value so that they can be parsed into mProperties. + * KeyframeValueEntry is used in GetAnimationPropertiesFromKeyframes + * to gather data for each individual segment. */ -struct KeyframeValueEntry : KeyframeValue +struct KeyframeValueEntry { + nsCSSProperty mProperty; + StyleAnimationValue mValue; float mOffset; Maybe mTimingFunction; @@ -334,26 +310,12 @@ public: // // ------------------------------------------------------------------ -static void -BuildAnimationPropertyListFromKeyframeSequence( - JSContext* aCx, - Element* aTarget, - CSSPseudoElementType aPseudoType, - JS::ForOfIterator& aIterator, - nsTArray& aResult, - ErrorResult& aRv); - static void GetKeyframeListFromKeyframeSequence(JSContext* aCx, JS::ForOfIterator& aIterator, nsTArray& aResult, ErrorResult& aRv); -static bool -ConvertKeyframeSequence(JSContext* aCx, - JS::ForOfIterator& aIterator, - nsTArray& aResult); - static bool ConvertKeyframeSequence(JSContext* aCx, JS::ForOfIterator& aIterator, @@ -380,35 +342,13 @@ static PropertyValuePair MakePropertyValuePair(nsCSSProperty aProperty, const nsAString& aStringValue, nsCSSParser& aParser, nsIDocument* aDocument); -static bool -HasValidOffsets(const nsTArray& aKeyframes); - static bool HasValidOffsets(const nsTArray& aKeyframes); -static void -ApplyDistributeSpacing(nsTArray& aKeyframes); - -static void -GenerateValueEntries(Element* aTarget, - CSSPseudoElementType aPseudoType, - nsTArray& aKeyframes, - nsTArray& aResult, - ErrorResult& aRv); - static void BuildSegmentsFromValueEntries(nsTArray& aEntries, nsTArray& aResult); -static void -BuildAnimationPropertyListFromPropertyIndexedKeyframes( - JSContext* aCx, - Element* aTarget, - CSSPseudoElementType aPseudoType, - JS::Handle aValue, - InfallibleTArray& aResult, - ErrorResult& aRv); - static void GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx, JS::Handle aValue, @@ -420,64 +360,12 @@ RequiresAdditiveAnimation(const nsTArray& aKeyframes, nsIDocument* aDocument); -// TODO: This is only temporary until we remove the call sites for this. -already_AddRefed -LookupStyleContext(dom::Element* aElement, CSSPseudoElementType aPseudoType); - // ------------------------------------------------------------------ // // Public API // // ------------------------------------------------------------------ -/* static */ void -KeyframeUtils::BuildAnimationPropertyList( - JSContext* aCx, - Element* aTarget, - CSSPseudoElementType aPseudoType, - JS::Handle aFrames, - InfallibleTArray& aResult, - ErrorResult& aRv) -{ - MOZ_ASSERT(aResult.IsEmpty()); - - // See the description of frame lists in the spec: - // - // https://w3c.github.io/web-animations/#processing-a-frames-argument - // - // We don't support SharedKeyframeList yet, but we do support the other - // types of arguments. We manually implement the parts of JS-to-IDL union - // conversion algorithm from the Web IDL spec, since we have to represent - // this as an object? so we can look at the open-ended set of properties - // on these objects. - - if (!aFrames) { - // The argument was explicitly null. In this case, the default dictionary - // value for PropertyIndexedKeyframe would result in no keyframes. - return; - } - - // At this point we know we have an object. We try to convert it to a - // sequence first, and if that fails due to not being iterable, - // we try to convert it to PropertyIndexedKeyframe. - JS::Rooted 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, aPseudoType, - iter, aResult, aRv); - } else { - BuildAnimationPropertyListFromPropertyIndexedKeyframes(aCx, aTarget, - aPseudoType, - objectValue, aResult, - aRv); - } -} - /* static */ nsTArray KeyframeUtils::GetKeyframesFromObject(JSContext* aCx, JS::Handle aFrames, @@ -660,65 +548,6 @@ KeyframeUtils::GetAnimationPropertiesFromKeyframes( // // ------------------------------------------------------------------ -/** - * Converts a JS object to an IDL sequence and builds an - * array of AnimationProperty objects for the keyframe animation - * that it specifies. - * - * @param aTarget The target of the animation. - * @param aIterator An already-initialized ForOfIterator for the JS - * 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, - CSSPseudoElementType aPseudoType, - JS::ForOfIterator& aIterator, - nsTArray& aResult, - ErrorResult& aRv) -{ - // Convert the object in aIterator to sequence, producing - // an array of OffsetIndexedKeyframe objects. - AutoTArray keyframes; - if (!ConvertKeyframeSequence(aCx, aIterator, keyframes)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - // If the sequence<> had zero elements, we won't generate any - // keyframes. - if (keyframes.IsEmpty()) { - return; - } - - // Check that the keyframes are loosely sorted and with values all - // between 0% and 100%. - if (!HasValidOffsets(keyframes)) { - aRv.ThrowTypeError(); - return; - } - - // 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 entries; - 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); -} - /** * Converts a JS object to an IDL sequence. * @@ -761,52 +590,6 @@ GetKeyframeListFromKeyframeSequence(JSContext* aCx, } } -/** - * Converts a JS object wrapped by the given JS::ForIfIterator to an - * IDL sequence and stores the resulting OffsetIndexedKeyframe - * objects in aResult. - */ -static bool -ConvertKeyframeSequence(JSContext* aCx, - JS::ForOfIterator& aIterator, - nsTArray& aResult) -{ - JS::Rooted value(aCx); - for (;;) { - bool done; - if (!aIterator.next(&value, &done)) { - return false; - } - if (done) { - break; - } - // Each value found when iterating the object must be an object - // or null/undefined (which gets treated as a default {} dictionary - // value). - if (!value.isObject() && !value.isNullOrUndefined()) { - dom::ThrowErrorMessage(aCx, dom::MSG_NOT_OBJECT, - "Element of sequence argument"); - return false; - } - // Convert the JS value into a BaseKeyframe dictionary value. - OffsetIndexedKeyframe* keyframe = aResult.AppendElement(); - if (!keyframe->mKeyframeDict.Init( - aCx, value, "Element of sequence argument")) { - return false; - } - // Look for additional property-values pairs on the object. - if (value.isObject()) { - JS::Rooted object(aCx, &value.toObject()); - if (!GetPropertyValuesPairs(aCx, object, - ListAllowance::eDisallow, - keyframe->mPropertyValuePairs)) { - return false; - } - } - } - return true; -} - /** * Converts a JS object wrapped by the given JS::ForIfIterator to an * IDL sequence and stores the resulting Keyframe objects in @@ -1058,30 +841,6 @@ MakePropertyValuePair(nsCSSProperty aProperty, const nsAString& aStringValue, return { aProperty, value }; } -/** - * Checks that the given keyframes are loosely ordered (each keyframe's - * offset that is not null is greater than or equal to the previous - * non-null offset) and that all values are within the range [0.0, 1.0]. - * - * @return true if the keyframes' offsets are correctly ordered and - * within range; false otherwise. - */ -static bool -HasValidOffsets(const nsTArray& aKeyframes) -{ - double offset = 0.0; - for (const OffsetIndexedKeyframe& keyframe : aKeyframes) { - if (!keyframe.mKeyframeDict.mOffset.IsNull()) { - double thisOffset = keyframe.mKeyframeDict.mOffset.Value(); - if (thisOffset < offset || thisOffset > 1.0f) { - return false; - } - offset = thisOffset; - } - } - return true; -} - /** * Checks that the given keyframes are loosely ordered (each keyframe's * offset that is not null is greater than or equal to the previous @@ -1106,147 +865,6 @@ HasValidOffsets(const nsTArray& aKeyframes) return true; } -/** - * Fills in any null offsets for the given keyframes by applying the - * "distribute" spacing algorithm. - * - * http://w3c.github.io/web-animations/#distribute-keyframe-spacing-mode - */ -static void -ApplyDistributeSpacing(nsTArray& aKeyframes) -{ - // If the first or last keyframes have an unspecified offset, - // fill them in with 0% and 100%. If there is only a single keyframe, - // then it gets 100%. - if (aKeyframes.LastElement().mKeyframeDict.mOffset.IsNull()) { - aKeyframes.LastElement().mKeyframeDict.mOffset.SetValue(1.0); - } - if (aKeyframes[0].mKeyframeDict.mOffset.IsNull()) { - aKeyframes[0].mKeyframeDict.mOffset.SetValue(0.0); - } - - // Fill in remaining missing offsets. - size_t i = 0; - while (i < aKeyframes.Length() - 1) { - MOZ_ASSERT(!aKeyframes[i].mKeyframeDict.mOffset.IsNull()); - double start = aKeyframes[i].mKeyframeDict.mOffset.Value(); - size_t j = i + 1; - while (aKeyframes[j].mKeyframeDict.mOffset.IsNull()) { - ++j; - } - double end = aKeyframes[j].mKeyframeDict.mOffset.Value(); - size_t n = j - i; - for (size_t k = 1; k < n; ++k) { - double offset = start + double(k) / n * (end - start); - aKeyframes[i + k].mKeyframeDict.mOffset.SetValue(offset); - } - i = j; - } -} - -/** - * 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, - CSSPseudoElementType aPseudoType, - nsTArray& aKeyframes, - nsTArray& aResult, - ErrorResult& aRv) -{ - RefPtr styleContext = - LookupStyleContext(aTarget, aPseudoType); - if (!styleContext) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - 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) { - Maybe easing = - TimingParams::ParseEasing(keyframe.mKeyframeDict.mEasing, - aTarget->OwnerDoc(), aRv); - if (aRv.Failed()) { - return; - } - float offset = float(keyframe.mKeyframeDict.mOffset.Value()); - // 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 - // shorthands, and with shorthands all appearing in increasing order of - // number of components. For two longhand properties, or two shorthands - // with the same number of components, sort by IDL name. - // - // @see PropertyPriorityComparator. - keyframe.mPropertyValuePairs.Sort(PropertyValuesPair::Comparator()); - - 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 values; - if (StyleAnimationValue::ComputeValues(pair.mProperty, - nsCSSProps::eEnabledForAllContent, - aTarget, - styleContext, - 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(); - entry->mOffset = offset; - entry->mProperty = value.mProperty; - entry->mValue = value.mValue; - entry->mTimingFunction = easing; - - if (offset == 0.0) { - propertiesWithFromValue.AddProperty(value.mProperty); - } else if (offset == 1.0) { - propertiesWithToValue.AddProperty(value.mProperty); - } - propertiesOnThisKeyframe.AddProperty(value.mProperty); - properties.AddProperty(value.mProperty); - } - } - } - } - - // We don't support additive segments and so can't support missing properties - // using their underlying value in 0% and 100% keyframes. Throw an exception - // until we do support this. - if (!propertiesWithFromValue.Equals(properties) || - !propertiesWithToValue.Equals(properties)) { - aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR); - return; - } -} - /** * Builds an array of AnimationProperty objects to represent the keyframe * animation segments in aEntries. @@ -1347,183 +965,6 @@ BuildSegmentsFromValueEntries(nsTArray& aEntries, } } -/** - * Converts a JS object to an IDL PropertyIndexedKeyframe and builds an - * array of AnimationProperty objects for the keyframe animation - * that it specifies. - * - * @param aTarget The target of the animation. - * @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, - CSSPseudoElementType aPseudoType, - JS::Handle aValue, - InfallibleTArray& aResult, - ErrorResult& aRv) -{ - MOZ_ASSERT(aValue.isObject()); - - RefPtr styleContext = - LookupStyleContext(aTarget, aPseudoType); - if (!styleContext) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - // Convert the object to a PropertyIndexedKeyframe dictionary to - // get its explicit dictionary members. - dom::binding_detail::FastBasePropertyIndexedKeyframe keyframes; - if (!keyframes.Init(aCx, aValue, "BasePropertyIndexedKeyframe argument", - false)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - Maybe easing = - TimingParams::ParseEasing(keyframes.mEasing, aTarget->OwnerDoc(), aRv); - - // 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 object(aCx, &aValue.toObject()); - nsTArray propertyValuesPairs; - if (!GetPropertyValuesPairs(aCx, object, ListAllowance::eAllow, - propertyValuesPairs)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - // We must keep track of which properties we've already generated - // an AnimationProperty since the author could have specified both a - // shorthand and one of its component longhands on the - // PropertyIndexedKeyframe. - nsCSSPropertySet properties; - - // Create AnimationProperty objects for each PropertyValuesPair, applying - // the "distribute" spacing algorithm to the segments. - for (const PropertyValuesPair& pair : propertyValuesPairs) { - size_t count = pair.mValues.Length(); - if (count == 0) { - // No animation values for this property. - continue; - } - if (count == 1) { - // We don't support additive segments and so can't support an - // animation that goes from the underlying value to this - // specified value. Throw an exception until we do support this. - aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR); - return; - } - - // If we find an invalid value, we don't create a segment for it, but - // we adjust the surrounding segments so that the timing of the segments - // is the same as if we did support it. For example, animating with - // values ["red", "green", "yellow", "invalid", "blue"] will generate - // segments with this timing: - // - // 0.00 -> 0.25 : red -> green - // 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 fromValues; - float fromKey = 0.0f; - if (!StyleAnimationValue::ComputeValues(pair.mProperty, - nsCSSProps::eEnabledForAllContent, - aTarget, - styleContext, - 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. - continue; - } - - // Create AnimationProperty objects for each property that had a - // value computed. When pair.mProperty is a longhand, it is just - // that property. When pair.mProperty is a shorthand, we'll have - // one property per longhand component. - nsTArray animationPropertyIndexes; - animationPropertyIndexes.SetLength(fromValues.Length()); - for (size_t i = 0, n = fromValues.Length(); i < n; ++i) { - nsCSSProperty p = fromValues[i].mProperty; - bool found = false; - if (properties.HasProperty(p)) { - // We have already dealt with this property. Look up and - // overwrite the old AnimationProperty object. - for (size_t j = 0, m = aResult.Length(); j < m; ++j) { - if (aResult[j].mProperty == p) { - aResult[j].mSegments.Clear(); - animationPropertyIndexes[i] = j; - found = true; - break; - } - } - MOZ_ASSERT(found, "properties is inconsistent with aResult"); - } - if (!found) { - // This is the first time we've encountered this property. - animationPropertyIndexes[i] = aResult.Length(); - AnimationProperty* animationProperty = aResult.AppendElement(); - animationProperty->mProperty = p; - properties.AddProperty(p); - } - } - - double portion = 1.0 / (count - 1); - for (size_t i = 0; i < count - 1; ++i) { - nsTArray toValues; - float toKey = (i + 1) * portion; - if (!StyleAnimationValue::ComputeValues(pair.mProperty, - nsCSSProps::eEnabledForAllContent, - aTarget, - styleContext, - 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; - } - MOZ_ASSERT(toValues.Length() == fromValues.Length(), - "should get the same number of properties as the last time " - "we called ComputeValues for pair.mProperty"); - for (size_t j = 0, n = toValues.Length(); j < n; ++j) { - size_t index = animationPropertyIndexes[j]; - AnimationPropertySegment* segment = - aResult[index].mSegments.AppendElement(); - segment->mFromKey = fromKey; - segment->mFromValue = fromValues[j].mValue; - segment->mToKey = toKey; - segment->mToValue = toValues[j].mValue; - segment->mTimingFunction = easing; - } - fromValues = Move(toValues); - fromKey = toKey; - } - } -} - /** * Converts a JS object representing a property-indexed keyframe into * an array of Keyframe objects. @@ -1695,19 +1136,4 @@ RequiresAdditiveAnimation(const nsTArray& aKeyframes, !propertiesWithToValue.Equals(properties); } -already_AddRefed -LookupStyleContext(dom::Element* aElement, CSSPseudoElementType aPseudoType) -{ - nsIDocument* doc = aElement->GetCurrentDoc(); - nsIPresShell* shell = doc->GetShell(); - if (!shell) { - return nullptr; - } - - nsIAtom* pseudo = - aPseudoType < CSSPseudoElementType::Count ? - nsCSSPseudoElements::GetPseudoAtom(aPseudoType) : nullptr; - return nsComputedDOMStyle::GetStyleContextForElement(aElement, pseudo, shell); -} - } // namespace mozilla diff --git a/dom/animation/KeyframeUtils.h b/dom/animation/KeyframeUtils.h index c57f65e40542..d925b0b2eb51 100644 --- a/dom/animation/KeyframeUtils.h +++ b/dom/animation/KeyframeUtils.h @@ -33,25 +33,6 @@ namespace mozilla { class KeyframeUtils { public: - /** - * Converts a JS value to a property-indexed keyframe or a sequence of - * regular keyframes and builds an array of AnimationProperty objects for the - * keyframe animation that it specifies. - * - * @param aTarget The target of the animation, used to resolve style - * for a property's underlying value if needed. - * @param aFrames The JS value, provided as an optional IDL |object?| value, - * that is the keyframe list specification. - * @param aResult The array into which the resulting AnimationProperty - * objects will be appended. - */ - static void - BuildAnimationPropertyList(JSContext* aCx, Element* aTarget, - CSSPseudoElementType aPseudoType, - JS::Handle aFrames, - InfallibleTArray& aResult, - ErrorResult& aRv); - /** * Converts a JS value representing a property-indexed keyframe or a sequence * of keyframes to an array of Keyframe objects.