Commit 10686d89 authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Implement KeyframeEffectReadOnly::getKeyframes()

This CL implements most of the getKeyframes() algorithm from the
web-animations spec[0]. There are a few deviations from the spec:

  * We always include the 'composite' property. This is because we
    don't yet track the general composite operation for the KeyframeEffect,
    so cannot tell when a Keyframe has the same operation.
  * Shorthand CSS properties in the input keyframe argument will have been
    expanded to longhand properties in getKeyframes(). This is because we
    improperly expand shorthand properties when creating a StringKeyframe.

Despite the deviations this implementation allows us to pass >40 additional
WPT tests. It also makes the failure reasons for many more tests explicit,
as they no longer just fail on "getKeyframes doesn't exist".

[0]: http://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-getkeyframes

Bug: 777971
Change-Id: I80cf62bc0121b946b1bf896890e96afd27437057
Reviewed-on: https://chromium-review.googlesource.com/758921Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarXida Chen <xidachen@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517701}
parent 20a2f79a
<!DOCTYPE html>
<meta charset=utf-8>
<title>KeyframeEffectReadOnly::getKeyframes should use correct context</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../external/wpt/web-animations/testcommon.js"></script>
<div id="elem"></div>
<iframe id="iframe"></iframe>
<script>
"use strict";
// This test checks a particularly nasty corner-case of getKeyframes(). Because
// getKeyframes() manually constructs a JavaScript object to pass back, care
// must be taken to ensure that the resultant object is in the same context as
// the KeyframeEffectReadOnly object it is being applied to.
test(function(t) {
const effect = new KeyframeEffectReadOnly(elem, [
{ left: "0px" },
{ left: "20px" }
], 1000);
const iframe = document.getElementById("iframe");
const keyframes = iframe.contentWindow.KeyframeEffectReadOnly.prototype
.getKeyframes.apply(effect);
assert_equals(Object.getPrototypeOf(keyframes[0]), Object.prototype);
}, "Applying getKeyframes to a KeyframeEffectReadOnly object from another "
+ " frame should produce keyframes in the same frame as the object.");
</script>
This is a testharness.js-based test. This is a testharness.js-based test.
FAIL Default value assert_equals: The default value should be replace expected (string) "replace" but got (undefined) undefined FAIL Default value assert_equals: The default value should be replace expected (string) "replace" but got (undefined) undefined
PASS Change composite value PASS Change composite value
FAIL Unspecified keyframe composite value when setting effect composite anim.effect.getKeyframes is not a function FAIL Unspecified keyframe composite value when setting effect composite assert_equals: unspecified keyframe composite value should be absent even if effect composite is set expected (undefined) undefined but got (string) "replace"
FAIL Specified keyframe composite value when setting effect composite anim.effect.getKeyframes is not a function PASS Specified keyframe composite value when setting effect composite
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -14,13 +14,13 @@ PASS KeyframeEffectReadOnly interface: existence and properties of interface pro ...@@ -14,13 +14,13 @@ PASS KeyframeEffectReadOnly interface: existence and properties of interface pro
FAIL KeyframeEffectReadOnly interface: attribute target assert_true: The prototype object must have a property "target" expected true got false FAIL KeyframeEffectReadOnly interface: attribute target assert_true: The prototype object must have a property "target" expected true got false
FAIL KeyframeEffectReadOnly interface: attribute iterationComposite assert_true: The prototype object must have a property "iterationComposite" expected true got false FAIL KeyframeEffectReadOnly interface: attribute iterationComposite assert_true: The prototype object must have a property "iterationComposite" expected true got false
FAIL KeyframeEffectReadOnly interface: attribute composite assert_true: The prototype object must have a property "composite" expected true got false FAIL KeyframeEffectReadOnly interface: attribute composite assert_true: The prototype object must have a property "composite" expected true got false
FAIL KeyframeEffectReadOnly interface: operation getKeyframes() assert_own_property: interface prototype object missing non-static operation expected property "getKeyframes" missing PASS KeyframeEffectReadOnly interface: operation getKeyframes()
PASS KeyframeEffectReadOnly must be primary interface of new KeyframeEffectReadOnly(null, null) PASS KeyframeEffectReadOnly must be primary interface of new KeyframeEffectReadOnly(null, null)
PASS Stringification of new KeyframeEffectReadOnly(null, null) PASS Stringification of new KeyframeEffectReadOnly(null, null)
FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "target" with the proper type assert_inherits: property "target" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "target" with the proper type assert_inherits: property "target" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "iterationComposite" with the proper type assert_inherits: property "iterationComposite" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "iterationComposite" with the proper type assert_inherits: property "iterationComposite" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "composite" with the proper type assert_inherits: property "composite" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "composite" with the proper type assert_inherits: property "composite" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "getKeyframes()" with the proper type assert_inherits: property "getKeyframes" not found in prototype chain PASS KeyframeEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "getKeyframes()" with the proper type
PASS AnimationEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "timing" with the proper type PASS AnimationEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "timing" with the proper type
PASS AnimationEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "getComputedTiming()" with the proper type PASS AnimationEffectReadOnly interface: new KeyframeEffectReadOnly(null, null) must inherit property "getComputedTiming()" with the proper type
PASS KeyframeEffect interface: existence and properties of interface object PASS KeyframeEffect interface: existence and properties of interface object
...@@ -42,7 +42,7 @@ FAIL KeyframeEffect interface: calling setKeyframes(object) on new KeyframeEffec ...@@ -42,7 +42,7 @@ FAIL KeyframeEffect interface: calling setKeyframes(object) on new KeyframeEffec
FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "target" with the proper type assert_inherits: property "target" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "target" with the proper type assert_inherits: property "target" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "iterationComposite" with the proper type assert_inherits: property "iterationComposite" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "iterationComposite" with the proper type assert_inherits: property "iterationComposite" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "composite" with the proper type assert_inherits: property "composite" not found in prototype chain FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "composite" with the proper type assert_inherits: property "composite" not found in prototype chain
FAIL KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "getKeyframes()" with the proper type assert_inherits: property "getKeyframes" not found in prototype chain PASS KeyframeEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "getKeyframes()" with the proper type
PASS AnimationEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "timing" with the proper type PASS AnimationEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "timing" with the proper type
PASS AnimationEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "getComputedTiming()" with the proper type PASS AnimationEffectReadOnly interface: new KeyframeEffect(null, null) must inherit property "getComputedTiming()" with the proper type
Harness: the test ran to completion. Harness: the test ran to completion.
......
This is a testharness.js-based test. This is a testharness.js-based test.
Found 50 tests; 35 PASS, 15 FAIL, 0 TIMEOUT, 0 NOTRUN. Found 50 tests; 40 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS non-animatable property 'animation' is not accessed when using a property-indexed keyframe object PASS non-animatable property 'animation' is not accessed when using a property-indexed keyframe object
PASS non-animatable property 'animationDelay' is not accessed when using a property-indexed keyframe object PASS non-animatable property 'animationDelay' is not accessed when using a property-indexed keyframe object
PASS non-animatable property 'animationDirection' is not accessed when using a property-indexed keyframe object PASS non-animatable property 'animationDirection' is not accessed when using a property-indexed keyframe object
...@@ -34,21 +34,21 @@ PASS non-animatable property 'transitionTimingFunction' is not accessed when usi ...@@ -34,21 +34,21 @@ PASS non-animatable property 'transitionTimingFunction' is not accessed when usi
PASS non-animatable property 'display' is not accessed when using a keyframe sequence PASS non-animatable property 'display' is not accessed when using a keyframe sequence
PASS non-animatable property 'unsupportedProperty' is not accessed when using a keyframe sequence PASS non-animatable property 'unsupportedProperty' is not accessed when using a keyframe sequence
PASS non-animatable property 'font-size' is not accessed when using a keyframe sequence PASS non-animatable property 'font-size' is not accessed when using a keyframe sequence
FAIL Equivalent property-indexed and sequenced keyframes: two properties with one value (intermediate value).getKeyframes is not a function PASS Equivalent property-indexed and sequenced keyframes: two properties with one value
FAIL Equivalent property-indexed and sequenced keyframes: two properties with three values (intermediate value).getKeyframes is not a function PASS Equivalent property-indexed and sequenced keyframes: two properties with three values
FAIL Equivalent property-indexed and sequenced keyframes: two properties with different numbers of values (intermediate value).getKeyframes is not a function PASS Equivalent property-indexed and sequenced keyframes: two properties with different numbers of values
FAIL Equivalent property-indexed and sequenced keyframes: same easing applied to all keyframes (intermediate value).getKeyframes is not a function PASS Equivalent property-indexed and sequenced keyframes: same easing applied to all keyframes
FAIL Equivalent property-indexed and sequenced keyframes: same composite applied to all keyframes (intermediate value).getKeyframes is not a function PASS Equivalent property-indexed and sequenced keyframes: same composite applied to all keyframes
FAIL Keyframes are read from a custom iterator effect.getKeyframes is not a function FAIL Keyframes are read from a custom iterator assert_equals: number of frames expected 3 but got 0
FAIL 'easing' and 'offset' are ignored on iterable objects effect.getKeyframes is not a function FAIL 'easing' and 'offset' are ignored on iterable objects assert_equals: number of frames expected 3 but got 0
FAIL Keyframes are read from a custom iterator with multiple properties specified effect.getKeyframes is not a function FAIL Keyframes are read from a custom iterator with multiple properties specified assert_equals: number of frames expected 3 but got 0
FAIL Keyframes are read from a custom iterator with where an offset is specified effect.getKeyframes is not a function FAIL Keyframes are read from a custom iterator with where an offset is specified assert_equals: number of frames expected 3 but got 0
PASS Reading from a custom iterator that returns a non-object keyframe should throw PASS Reading from a custom iterator that returns a non-object keyframe should throw
FAIL A list of values returned from a custom iterator should be ignored effect.getKeyframes is not a function FAIL A list of values returned from a custom iterator should be ignored assert_equals: number of frames expected 1 but got 0
FAIL Only enumerable properties on keyframes are read effect.getKeyframes is not a function FAIL Only enumerable properties on keyframes are read assert_equals: number of frames expected 2 but got 0
FAIL Only properties defined directly on keyframes are read effect.getKeyframes is not a function FAIL Only properties defined directly on keyframes are read assert_equals: number of frames expected 2 but got 0
FAIL Only enumerable properties on property-indexed keyframes are read effect.getKeyframes is not a function FAIL Only enumerable properties on property-indexed keyframes are read assert_equals: number of frames expected 2 but got 0
FAIL Only properties defined directly on property-indexed keyframes are read effect.getKeyframes is not a function FAIL Only properties defined directly on property-indexed keyframes are read assert_equals: number of frames expected 2 but got 0
FAIL Properties are read in ascending order by Unicode codepoint assert_array_equals: property access order lengths differ, expected 5 got 8 FAIL Properties are read in ascending order by Unicode codepoint assert_array_equals: property access order lengths differ, expected 5 got 8
Harness: the test ran to completion. Harness: the test ran to completion.
This is a testharness.js-based test. This is a testharness.js-based test.
FAIL easing values are parsed correctly when set on a property-indexed keyframe effect.getKeyframes is not a function PASS easing values are parsed correctly when set on a property-indexed keyframe
FAIL easing values are parsed correctly when using a keyframe sequence effect.getKeyframes is not a function PASS easing values are parsed correctly when using a keyframe sequence
PASS Invalid easing values are correctly rejected when set on a property-indexed keyframe PASS Invalid easing values are correctly rejected when set on a property-indexed keyframe
PASS Invalid easing values are correctly rejected when using a keyframe sequence PASS Invalid easing values are correctly rejected when using a keyframe sequence
FAIL Errors from invalid easings on a property-indexed keyframe are thrown after reading all properties assert_equals: All properties were read before throwing the easing error expected 2 but got 0 FAIL Errors from invalid easings on a property-indexed keyframe are thrown after reading all properties assert_equals: All properties were read before throwing the easing error expected 2 but got 0
......
...@@ -3944,6 +3944,7 @@ interface KeyframeEffect : KeyframeEffectReadOnly ...@@ -3944,6 +3944,7 @@ interface KeyframeEffect : KeyframeEffectReadOnly
interface KeyframeEffectReadOnly : AnimationEffectReadOnly interface KeyframeEffectReadOnly : AnimationEffectReadOnly
attribute @@toStringTag attribute @@toStringTag
method constructor method constructor
method getKeyframes
interface LinearAccelerationSensor : Accelerometer interface LinearAccelerationSensor : Accelerometer
attribute @@toStringTag attribute @@toStringTag
method constructor method constructor
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "core/animation/AnimationInputHelpers.h" #include "core/animation/AnimationInputHelpers.h"
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "core/animation/PropertyHandle.h"
#include "core/css/CSSValueList.h" #include "core/css/CSSValueList.h"
#include "core/css/parser/CSSParser.h" #include "core/css/parser/CSSParser.h"
#include "core/css/parser/CSSVariableParser.h" #include "core/css/parser/CSSVariableParser.h"
...@@ -29,6 +30,28 @@ static String RemoveSVGPrefix(const String& property) { ...@@ -29,6 +30,28 @@ static String RemoveSVGPrefix(const String& property) {
return property.Substring(kSVGPrefixLength); return property.Substring(kSVGPrefixLength);
} }
static String CSSPropertyToKeyframeAttribute(CSSPropertyID property) {
DCHECK_NE(property, CSSPropertyInvalid);
DCHECK_NE(property, CSSPropertyVariable);
switch (property) {
case CSSPropertyFloat:
return "cssFloat";
case CSSPropertyOffset:
return "cssOffset";
default:
return getJSPropertyName(property);
}
}
static String PresentationAttributeToKeyframeAttribute(
CSSPropertyID presentation_attribute) {
StringBuilder builder;
builder.Append(kSVGPrefix, kSVGPrefixLength);
builder.Append(getPropertyName(presentation_attribute));
return builder.ToString();
}
CSSPropertyID AnimationInputHelpers::KeyframeAttributeToCSSProperty( CSSPropertyID AnimationInputHelpers::KeyframeAttributeToCSSProperty(
const String& property, const String& property,
const Document& document) { const Document& document) {
...@@ -237,4 +260,21 @@ scoped_refptr<TimingFunction> AnimationInputHelpers::ParseTimingFunction( ...@@ -237,4 +260,21 @@ scoped_refptr<TimingFunction> AnimationInputHelpers::ParseTimingFunction(
document); document);
} }
String AnimationInputHelpers::PropertyHandleToKeyframeAttribute(
PropertyHandle property) {
if (property.IsCSSProperty()) {
return property.IsCSSCustomProperty()
? property.CustomPropertyName()
: CSSPropertyToKeyframeAttribute(property.CssProperty());
}
if (property.IsPresentationAttribute()) {
return PresentationAttributeToKeyframeAttribute(
property.PresentationAttribute());
}
DCHECK(property.IsSVGAttribute());
return property.SvgAttribute().LocalName();
}
} // namespace blink } // namespace blink
...@@ -15,6 +15,7 @@ namespace blink { ...@@ -15,6 +15,7 @@ namespace blink {
class Document; class Document;
class Element; class Element;
class ExceptionState; class ExceptionState;
class PropertyHandle;
class TimingFunction; class TimingFunction;
class QualifiedName; class QualifiedName;
...@@ -31,6 +32,8 @@ class CORE_EXPORT AnimationInputHelpers { ...@@ -31,6 +32,8 @@ class CORE_EXPORT AnimationInputHelpers {
static scoped_refptr<TimingFunction> ParseTimingFunction(const String&, static scoped_refptr<TimingFunction> ParseTimingFunction(const String&,
Document*, Document*,
ExceptionState&); ExceptionState&);
static String PropertyHandleToKeyframeAttribute(PropertyHandle);
}; };
} // namespace blink } // namespace blink
......
...@@ -4,12 +4,13 @@ ...@@ -4,12 +4,13 @@
#include "core/animation/AnimationInputHelpers.h" #include "core/animation/AnimationInputHelpers.h"
#include <memory>
#include "core/animation/PropertyHandle.h"
#include "core/dom/Element.h" #include "core/dom/Element.h"
#include "core/dom/ExceptionCode.h" #include "core/dom/ExceptionCode.h"
#include "core/testing/DummyPageHolder.h" #include "core/testing/DummyPageHolder.h"
#include "platform/animation/TimingFunction.h" #include "platform/animation/TimingFunction.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include <memory>
namespace blink { namespace blink {
...@@ -20,6 +21,23 @@ class AnimationAnimationInputHelpersTest : public ::testing::Test { ...@@ -20,6 +21,23 @@ class AnimationAnimationInputHelpersTest : public ::testing::Test {
*document); *document);
} }
String PropertyHandleToKeyframeAttribute(
CSSPropertyID property,
bool is_presentation_attribute = false) {
PropertyHandle handle(property, is_presentation_attribute);
return AnimationInputHelpers::PropertyHandleToKeyframeAttribute(handle);
}
String PropertyHandleToKeyframeAttribute(AtomicString property) {
PropertyHandle handle(property);
return AnimationInputHelpers::PropertyHandleToKeyframeAttribute(handle);
}
String PropertyHandleToKeyframeAttribute(QualifiedName property) {
PropertyHandle handle(property);
return AnimationInputHelpers::PropertyHandleToKeyframeAttribute(handle);
}
scoped_refptr<TimingFunction> ParseTimingFunction( scoped_refptr<TimingFunction> ParseTimingFunction(
const String& string, const String& string,
ExceptionState& exception_state) { ExceptionState& exception_state) {
...@@ -140,4 +158,33 @@ TEST_F(AnimationAnimationInputHelpersTest, ParseAnimationTimingFunction) { ...@@ -140,4 +158,33 @@ TEST_F(AnimationAnimationInputHelpersTest, ParseAnimationTimingFunction) {
TimingFunctionThrows("cubic-bezier(0.1, 0, 4, 0.4)", exception_state); TimingFunctionThrows("cubic-bezier(0.1, 0, 4, 0.4)", exception_state);
} }
TEST_F(AnimationAnimationInputHelpersTest, PropertyHandleToKeyframeAttribute) {
// CSS properties.
EXPECT_EQ("top", PropertyHandleToKeyframeAttribute(CSSPropertyTop));
EXPECT_EQ("lineHeight",
PropertyHandleToKeyframeAttribute(CSSPropertyLineHeight));
EXPECT_EQ("cssFloat", PropertyHandleToKeyframeAttribute(CSSPropertyFloat));
EXPECT_EQ("cssOffset", PropertyHandleToKeyframeAttribute(CSSPropertyOffset));
// CSS custom properties.
EXPECT_EQ("--x", PropertyHandleToKeyframeAttribute("--x"));
EXPECT_EQ("--test-prop", PropertyHandleToKeyframeAttribute("--test-prop"));
// Presentation attributes.
EXPECT_EQ("svg-top", PropertyHandleToKeyframeAttribute(CSSPropertyTop, true));
EXPECT_EQ("svg-line-height",
PropertyHandleToKeyframeAttribute(CSSPropertyLineHeight, true));
EXPECT_EQ("svg-float",
PropertyHandleToKeyframeAttribute(CSSPropertyFloat, true));
EXPECT_EQ("svg-offset",
PropertyHandleToKeyframeAttribute(CSSPropertyOffset, true));
// SVG attributes.
EXPECT_EQ("calcMode", PropertyHandleToKeyframeAttribute(QualifiedName(
g_null_atom, "calcMode", g_null_atom)));
EXPECT_EQ("overline-position",
PropertyHandleToKeyframeAttribute(
QualifiedName(g_null_atom, "overline-position", g_null_atom)));
}
} // namespace blink } // namespace blink
...@@ -175,6 +175,7 @@ EffectModel* EffectInput::Convert( ...@@ -175,6 +175,7 @@ EffectModel* EffectInput::Convert(
const DictionarySequenceOrDictionary& effect_input, const DictionarySequenceOrDictionary& effect_input,
ExecutionContext* execution_context, ExecutionContext* execution_context,
ExceptionState& exception_state) { ExceptionState& exception_state) {
// TODO(crbug.com/772014): The element is allowed to be null; remove check.
if (effect_input.IsNull() || !element) if (effect_input.IsNull() || !element)
return nullptr; return nullptr;
......
...@@ -4,10 +4,26 @@ ...@@ -4,10 +4,26 @@
#include "core/animation/Keyframe.h" #include "core/animation/Keyframe.h"
#include "bindings/core/v8/V8ObjectBuilder.h"
#include "core/animation/EffectModel.h"
#include "core/animation/InvalidatableInterpolation.h" #include "core/animation/InvalidatableInterpolation.h"
namespace blink { namespace blink {
namespace {
StringView CompositeOperationToString(EffectModel::CompositeOperation op) {
switch (op) {
case EffectModel::kCompositeAdd:
return "add";
case EffectModel::kCompositeReplace:
return "replace";
default:
NOTREACHED();
return "";
}
}
} // namespace
scoped_refptr<Interpolation> scoped_refptr<Interpolation>
Keyframe::PropertySpecificKeyframe::CreateInterpolation( Keyframe::PropertySpecificKeyframe::CreateInterpolation(
const PropertyHandle& property_handle, const PropertyHandle& property_handle,
...@@ -18,6 +34,15 @@ Keyframe::PropertySpecificKeyframe::CreateInterpolation( ...@@ -18,6 +34,15 @@ Keyframe::PropertySpecificKeyframe::CreateInterpolation(
const_cast<PropertySpecificKeyframe*>(&end)); const_cast<PropertySpecificKeyframe*>(&end));
} }
void Keyframe::AddKeyframePropertiesToV8Object(
V8ObjectBuilder& object_builder) const {
object_builder.Add("offset", offset_);
object_builder.Add("easing", easing_->ToString());
// TODO(crbug.com/785526): This should be absent if it matches the composite
// operation of the keyframe effect (which is not yet implemented).
object_builder.AddString("composite", CompositeOperationToString(composite_));
}
bool Keyframe::CompareOffsets(const scoped_refptr<Keyframe>& a, bool Keyframe::CompareOffsets(const scoped_refptr<Keyframe>& a,
const scoped_refptr<Keyframe>& b) { const scoped_refptr<Keyframe>& b) {
return a->Offset() < b->Offset(); return a->Offset() < b->Offset();
......
...@@ -21,6 +21,7 @@ using PropertyHandleSet = HashSet<PropertyHandle>; ...@@ -21,6 +21,7 @@ using PropertyHandleSet = HashSet<PropertyHandle>;
class Element; class Element;
class ComputedStyle; class ComputedStyle;
class V8ObjectBuilder;
// A base class representing an animation keyframe. // A base class representing an animation keyframe.
// //
...@@ -101,6 +102,12 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> { ...@@ -101,6 +102,12 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> {
return the_clone; return the_clone;
} }
// Add the properties represented by this keyframe to the given V8 object.
//
// Subclasses should override this to add the (property, value) pairs they
// store, and call into the base version to add the basic Keyframe properties.
virtual void AddKeyframePropertiesToV8Object(V8ObjectBuilder&) const;
virtual bool IsStringKeyframe() const { return false; } virtual bool IsStringKeyframe() const { return false; }
virtual bool IsTransitionKeyframe() const { return false; } virtual bool IsTransitionKeyframe() const { return false; }
......
...@@ -123,10 +123,7 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel { ...@@ -123,10 +123,7 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel {
const ComputedStyle& base_style, const ComputedStyle& base_style,
const ComputedStyle* parent_style) const; const ComputedStyle* parent_style) const;
static Vector<double> GetComputedOffsetsForInspector( static Vector<double> GetComputedOffsets(const KeyframeVector& keyframes);
const KeyframeVector& keyframes) {
return GetComputedOffsets(keyframes);
}
bool Affects(const PropertyHandle& property) const override { bool Affects(const PropertyHandle& property) const override {
EnsureKeyframeGroups(); EnsureKeyframeGroups();
...@@ -144,8 +141,6 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel { ...@@ -144,8 +141,6 @@ class CORE_EXPORT KeyframeEffectModelBase : public EffectModel {
has_synthetic_keyframes_(false), has_synthetic_keyframes_(false),
needs_compositor_keyframes_snapshot_(true) {} needs_compositor_keyframes_snapshot_(true) {}
static Vector<double> GetComputedOffsets(const KeyframeVector& keyframes);
// Lazily computes the groups of property-specific keyframes. // Lazily computes the groups of property-specific keyframes.
void EnsureKeyframeGroups() const; void EnsureKeyframeGroups() const;
void EnsureInterpolationEffectPopulated() const; void EnsureInterpolationEffectPopulated() const;
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "bindings/core/v8/Dictionary.h" #include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/V8ObjectBuilder.h"
#include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h" #include "bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h"
#include "core/animation/Animation.h" #include "core/animation/Animation.h"
#include "core/animation/EffectInput.h" #include "core/animation/EffectInput.h"
...@@ -21,6 +23,7 @@ ...@@ -21,6 +23,7 @@
#include "core/frame/UseCounter.h" #include "core/frame/UseCounter.h"
#include "core/paint/PaintLayer.h" #include "core/paint/PaintLayer.h"
#include "core/svg/SVGElement.h" #include "core/svg/SVGElement.h"
#include "platform/bindings/ScriptState.h"
namespace blink { namespace blink {
...@@ -82,7 +85,9 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(Element* target, ...@@ -82,7 +85,9 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(Element* target,
target_(target), target_(target),
model_(model), model_(model),
sampled_effect_(nullptr), sampled_effect_(nullptr),
priority_(priority) {} priority_(priority) {
DCHECK(!model_ || model_->IsKeyframeEffectModel());
}
void KeyframeEffectReadOnly::Attach(Animation* animation) { void KeyframeEffectReadOnly::Attach(Animation* animation) {
if (target_) { if (target_) {
...@@ -311,6 +316,33 @@ void KeyframeEffectReadOnly::StartAnimationOnCompositor( ...@@ -311,6 +316,33 @@ void KeyframeEffectReadOnly::StartAnimationOnCompositor(
DCHECK(!compositor_animation_ids_.IsEmpty()); DCHECK(!compositor_animation_ids_.IsEmpty());
} }
Vector<ScriptValue> KeyframeEffectReadOnly::getKeyframes(
ScriptState* script_state) {
Vector<ScriptValue> computed_keyframes;
if (!model_)
return computed_keyframes;
// getKeyframes() returns a list of 'ComputedKeyframes'. A ComputedKeyframe
// consists of the normal keyframe data combined with the computed offset for
// the given keyframe.
//
// https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-getkeyframes
const KeyframeVector& keyframes =
ToKeyframeEffectModelBase(model_)->GetFrames();
Vector<double> computed_offsets =
KeyframeEffectModelBase::GetComputedOffsets(keyframes);
computed_keyframes.ReserveInitialCapacity(keyframes.size());
ScriptState::Scope scope(script_state);
for (size_t i = 0; i < keyframes.size(); i++) {
V8ObjectBuilder object_builder(script_state);
keyframes[i]->AddKeyframePropertiesToV8Object(object_builder);
object_builder.Add("computedOffset", computed_offsets[i]);
computed_keyframes.push_back(object_builder.GetScriptValue());
}
return computed_keyframes;
}
bool KeyframeEffectReadOnly::HasActiveAnimationsOnCompositor() const { bool KeyframeEffectReadOnly::HasActiveAnimationsOnCompositor() const {
return !compositor_animation_ids_.IsEmpty(); return !compositor_animation_ids_.IsEmpty();
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef KeyframeEffectReadOnly_h #ifndef KeyframeEffectReadOnly_h
#define KeyframeEffectReadOnly_h #define KeyframeEffectReadOnly_h
#include "bindings/core/v8/ScriptValue.h"
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "core/animation/AnimationEffectReadOnly.h" #include "core/animation/AnimationEffectReadOnly.h"
#include "core/animation/CompositorAnimations.h" #include "core/animation/CompositorAnimations.h"
...@@ -18,6 +19,7 @@ class ExceptionState; ...@@ -18,6 +19,7 @@ class ExceptionState;
class ExecutionContext; class ExecutionContext;
class PropertyHandle; class PropertyHandle;
class SampledEffect; class SampledEffect;
class ScriptState;
class UnrestrictedDoubleOrKeyframeEffectOptions; class UnrestrictedDoubleOrKeyframeEffectOptions;
// Represents the effect of an Animation on an Element's properties. // Represents the effect of an Animation on an Element's properties.
...@@ -50,6 +52,9 @@ class CORE_EXPORT KeyframeEffectReadOnly : public AnimationEffectReadOnly { ...@@ -50,6 +52,9 @@ class CORE_EXPORT KeyframeEffectReadOnly : public AnimationEffectReadOnly {
bool IsKeyframeEffectReadOnly() const override { return true; } bool IsKeyframeEffectReadOnly() const override { return true; }
// IDL implementation.
Vector<ScriptValue> getKeyframes(ScriptState*);
bool Affects(const PropertyHandle&) const; bool Affects(const PropertyHandle&) const;
const EffectModel* Model() const { return model_.Get(); } const EffectModel* Model() const { return model_.Get(); }
EffectModel* Model() { return model_.Get(); } EffectModel* Model() { return model_.Get(); }
......
...@@ -10,4 +10,5 @@ ...@@ -10,4 +10,5 @@
RaisesException=Constructor, RaisesException=Constructor,
RuntimeEnabled=WebAnimationsAPI RuntimeEnabled=WebAnimationsAPI
] interface KeyframeEffectReadOnly : AnimationEffectReadOnly { ] interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
[CallWith=ScriptState] sequence<object> getKeyframes();
}; };
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#include "core/animation/StringKeyframe.h" #include "core/animation/StringKeyframe.h"
#include "bindings/core/v8/V8ObjectBuilder.h"
#include "core/StylePropertyShorthand.h" #include "core/StylePropertyShorthand.h"
#include "core/animation/AnimationInputHelpers.h"
#include "core/animation/css/CSSAnimations.h" #include "core/animation/css/CSSAnimations.h"
#include "core/css/CSSCustomPropertyDeclaration.h" #include "core/css/CSSCustomPropertyDeclaration.h"
#include "core/css/resolver/StyleResolver.h" #include "core/css/resolver/StyleResolver.h"
...@@ -94,6 +96,27 @@ PropertyHandleSet StringKeyframe::Properties() const { ...@@ -94,6 +96,27 @@ PropertyHandleSet StringKeyframe::Properties() const {
return properties; return properties;
} }
void StringKeyframe::AddKeyframePropertiesToV8Object(
V8ObjectBuilder& object_builder) const {
Keyframe::AddKeyframePropertiesToV8Object(object_builder);
for (const PropertyHandle& property : Properties()) {
String property_name =
AnimationInputHelpers::PropertyHandleToKeyframeAttribute(property);
String value;
if (property.IsCSSProperty()) {
value = CssPropertyValue(property).CssText();
} else if (property.IsPresentationAttribute()) {
const auto& attribute = property.PresentationAttribute();
value = PresentationAttributeValue(attribute).CssText();
} else {
DCHECK(property.IsSVGAttribute());
value = SvgPropertyValue(property.SvgAttribute());
}
object_builder.Add(property_name, value);
}
}
scoped_refptr<Keyframe> StringKeyframe::Clone() const { scoped_refptr<Keyframe> StringKeyframe::Clone() const {
return base::AdoptRef(new StringKeyframe(*this)); return base::AdoptRef(new StringKeyframe(*this));
} }
......
...@@ -68,6 +68,8 @@ class CORE_EXPORT StringKeyframe : public Keyframe { ...@@ -68,6 +68,8 @@ class CORE_EXPORT StringKeyframe : public Keyframe {
PropertyHandleSet Properties() const override; PropertyHandleSet Properties() const override;
void AddKeyframePropertiesToV8Object(V8ObjectBuilder&) const override;
class CSSPropertySpecificKeyframe class CSSPropertySpecificKeyframe
: public Keyframe::PropertySpecificKeyframe { : public Keyframe::PropertySpecificKeyframe {
public: public:
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "core/animation/TransitionKeyframe.h" #include "core/animation/TransitionKeyframe.h"
#include "bindings/core/v8/V8ObjectBuilder.h"
#include "core/animation/CompositorAnimations.h" #include "core/animation/CompositorAnimations.h"
#include "core/animation/InterpolationType.h" #include "core/animation/InterpolationType.h"
#include "core/animation/PairwiseInterpolationValue.h" #include "core/animation/PairwiseInterpolationValue.h"
...@@ -25,6 +26,12 @@ PropertyHandleSet TransitionKeyframe::Properties() const { ...@@ -25,6 +26,12 @@ PropertyHandleSet TransitionKeyframe::Properties() const {
return result; return result;
} }
void TransitionKeyframe::AddKeyframePropertiesToV8Object(
V8ObjectBuilder& object_builder) const {
Keyframe::AddKeyframePropertiesToV8Object(object_builder);
// TODO(crbug.com/777971): Add in the property/value for TransitionKeyframe.
}
scoped_refptr<Keyframe::PropertySpecificKeyframe> scoped_refptr<Keyframe::PropertySpecificKeyframe>
TransitionKeyframe::CreatePropertySpecificKeyframe( TransitionKeyframe::CreatePropertySpecificKeyframe(
const PropertyHandle& property, const PropertyHandle& property,
......
...@@ -31,6 +31,8 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe { ...@@ -31,6 +31,8 @@ class CORE_EXPORT TransitionKeyframe : public Keyframe {
void SetCompositorValue(scoped_refptr<AnimatableValue>); void SetCompositorValue(scoped_refptr<AnimatableValue>);
PropertyHandleSet Properties() const final; PropertyHandleSet Properties() const final;
void AddKeyframePropertiesToV8Object(V8ObjectBuilder&) const override;
class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe { class PropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
public: public:
static scoped_refptr<PropertySpecificKeyframe> Create( static scoped_refptr<PropertySpecificKeyframe> Create(
......
...@@ -152,8 +152,7 @@ BuildObjectForAnimationKeyframes(const KeyframeEffectReadOnly* effect) { ...@@ -152,8 +152,7 @@ BuildObjectForAnimationKeyframes(const KeyframeEffectReadOnly* effect) {
const KeyframeEffectModelBase* model = const KeyframeEffectModelBase* model =
ToKeyframeEffectModelBase(effect->Model()); ToKeyframeEffectModelBase(effect->Model());
Vector<double> computed_offsets = Vector<double> computed_offsets =
KeyframeEffectModelBase::GetComputedOffsetsForInspector( KeyframeEffectModelBase::GetComputedOffsets(model->GetFrames());
model->GetFrames());
std::unique_ptr<protocol::Array<protocol::Animation::KeyframeStyle>> std::unique_ptr<protocol::Array<protocol::Animation::KeyframeStyle>>
keyframes = protocol::Array<protocol::Animation::KeyframeStyle>::create(); keyframes = protocol::Array<protocol::Animation::KeyframeStyle>::create();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment