Commit af8c16d9 authored by George Steel's avatar George Steel Committed by Commit Bot

Implement new pseudoElement interface on KeyframeEffect

Make target() return the originating element if target_ is a
PseudoElement (EventTarget still returns the layout object).

Add pseudoElement() property which returns the target pseudo-selector
if the target is a pseudo-element (null otherwise).
Invalid and unsupported pseudo-elements will still return a selector
and the originating element (from target()) but will not animated
(EventTarget returns null).

Add pseudoElement option to KeyframeEffect constructor.

Change-Id: Id7d16ea6966c533e56d1170462ff60a79b277fd5
Bug: 981894
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1921343
Commit-Queue: George Steel <gtsteel@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Reviewed-by: default avatarKevin Ellis <kevers@chromium.org>
Cr-Commit-Position: refs/heads/master@{#726506}
parent f053c86a
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "third_party/blink/renderer/core/animation/timing_input.h" #include "third_party/blink/renderer/core/animation/timing_input.h"
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h" #include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/pseudo_element.h"
#include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/computed_style.h"
...@@ -49,6 +50,34 @@ ...@@ -49,6 +50,34 @@
namespace blink { namespace blink {
namespace {
// Verifies that a pseudo-element selector lexes and canonicalizes legacy forms
bool ValidateAndCanonicalizePseudo(String& selector) {
if (selector.IsEmpty()) {
if (!selector.IsNull())
selector = String(); // null
return true;
} else if (selector.StartsWith("::")) {
return true;
} else if (selector == ":before") {
selector = "::before";
return true;
} else if (selector == ":after") {
selector = "::after";
return true;
} else if (selector == ":first-letter") {
selector = "::first-letter";
return true;
} else if (selector == ":first-line") {
selector = "::first-line";
return true;
}
return false;
}
} // namespace
KeyframeEffect* KeyframeEffect::Create( KeyframeEffect* KeyframeEffect::Create(
ScriptState* script_state, ScriptState* script_state,
Element* element, Element* element,
...@@ -61,17 +90,40 @@ KeyframeEffect* KeyframeEffect::Create( ...@@ -61,17 +90,40 @@ KeyframeEffect* KeyframeEffect::Create(
return nullptr; return nullptr;
EffectModel::CompositeOperation composite = EffectModel::kCompositeReplace; EffectModel::CompositeOperation composite = EffectModel::kCompositeReplace;
String pseudo = String();
if (options.IsKeyframeEffectOptions()) { if (options.IsKeyframeEffectOptions()) {
composite = EffectModel::StringToCompositeOperation( auto* effect_options = options.GetAsKeyframeEffectOptions();
options.GetAsKeyframeEffectOptions()->composite()) composite =
EffectModel::StringToCompositeOperation(effect_options->composite())
.value(); .value();
if (RuntimeEnabledFeatures::WebAnimationsAPIEnabled() &&
!effect_options->pseudoElement().IsEmpty()) {
pseudo = effect_options->pseudoElement();
if (!ValidateAndCanonicalizePseudo(pseudo)) {
// TODO(gtsteel): update when
// https://github.com/w3c/csswg-drafts/issues/4586 resolves
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"A valid pseudo-selector must start with ::.");
}
}
} }
KeyframeEffectModelBase* model = EffectInput::Convert( KeyframeEffectModelBase* model = EffectInput::Convert(
element, keyframes, composite, script_state, exception_state); element, keyframes, composite, script_state, exception_state);
if (exception_state.HadException()) if (exception_state.HadException())
return nullptr; return nullptr;
return MakeGarbageCollected<KeyframeEffect>(element, model, timing); KeyframeEffect* effect =
MakeGarbageCollected<KeyframeEffect>(element, model, timing);
if (!pseudo.IsEmpty()) {
effect->target_pseudo_ = pseudo;
if (element) {
effect->effect_target_ =
element->GetPseudoElement(CSSSelector::ParsePseudoId(pseudo));
}
}
return effect;
} }
KeyframeEffect* KeyframeEffect::Create(ScriptState* script_state, KeyframeEffect* KeyframeEffect::Create(ScriptState* script_state,
...@@ -103,23 +155,63 @@ KeyframeEffect::KeyframeEffect(Element* target, ...@@ -103,23 +155,63 @@ KeyframeEffect::KeyframeEffect(Element* target,
EventDelegate* event_delegate) EventDelegate* event_delegate)
: AnimationEffect(timing, event_delegate), : AnimationEffect(timing, event_delegate),
effect_target_(target), effect_target_(target),
target_element_(target),
target_pseudo_(),
model_(model), model_(model),
sampled_effect_(nullptr), sampled_effect_(nullptr),
priority_(priority) { priority_(priority) {
DCHECK(model_); DCHECK(model_);
// fix target for css animations and transitions
if (target && target->IsPseudoElement()) {
target_element_ = target->parentElement();
DCHECK(!target_element_->IsPseudoElement());
target_pseudo_ = target->tagName();
}
} }
KeyframeEffect::~KeyframeEffect() = default; KeyframeEffect::~KeyframeEffect() = default;
void KeyframeEffect::setTarget(Element* target) { void KeyframeEffect::setTarget(Element* new_target) {
if (effect_target_ == target) DCHECK(!new_target || !new_target->IsPseudoElement());
return; target_element_ = new_target;
RefreshTarget();
}
const String& KeyframeEffect::pseudoElement() {
return target_pseudo_;
}
void KeyframeEffect::setPseudoElement(String pseudo,
ExceptionState& exception_state) {
if (ValidateAndCanonicalizePseudo(pseudo)) {
target_pseudo_ = pseudo;
} else {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"A valid pseudo-selector must start with ::.");
}
RefreshTarget();
}
void KeyframeEffect::RefreshTarget() {
Element* new_target;
if (!target_element_) {
new_target = nullptr;
} else if (target_pseudo_.IsEmpty()) {
new_target = target_element_;
} else {
PseudoId pseudoId = CSSSelector::ParsePseudoId(target_pseudo_);
new_target = target_element_->GetPseudoElement(pseudoId);
}
if (new_target != effect_target_) {
DetachTarget(GetAnimation()); DetachTarget(GetAnimation());
effect_target_ = target; effect_target_ = new_target;
AttachTarget(GetAnimation()); AttachTarget(GetAnimation());
InvalidateAndNotifyOwner(); InvalidateAndNotifyOwner();
}
} }
String KeyframeEffect::composite() const { String KeyframeEffect::composite() const {
...@@ -320,6 +412,7 @@ bool KeyframeEffect::HasPlayingAnimation() const { ...@@ -320,6 +412,7 @@ bool KeyframeEffect::HasPlayingAnimation() const {
void KeyframeEffect::Trace(blink::Visitor* visitor) { void KeyframeEffect::Trace(blink::Visitor* visitor) {
visitor->Trace(effect_target_); visitor->Trace(effect_target_);
visitor->Trace(target_element_);
visitor->Trace(model_); visitor->Trace(model_);
visitor->Trace(sampled_effect_); visitor->Trace(sampled_effect_);
AnimationEffect::Trace(visitor); AnimationEffect::Trace(visitor);
......
...@@ -77,8 +77,13 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect { ...@@ -77,8 +77,13 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
bool IsKeyframeEffect() const override { return true; } bool IsKeyframeEffect() const override { return true; }
// IDL implementation. // IDL implementation.
Element* target() const { return effect_target_; }
// Returns the target element. If the animation targets a pseudo-element,
// this returns the originating element.
Element* target() const { return target_element_; }
void setTarget(Element*); void setTarget(Element*);
const String& pseudoElement();
void setPseudoElement(String, ExceptionState&);
String composite() const; String composite() const;
void setComposite(String); void setComposite(String);
HeapVector<ScriptValue> getKeyframes(ScriptState*); HeapVector<ScriptValue> getKeyframes(ScriptState*);
...@@ -138,6 +143,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect { ...@@ -138,6 +143,7 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
void Detach() override; void Detach() override;
void AttachTarget(Animation*); void AttachTarget(Animation*);
void DetachTarget(Animation*); void DetachTarget(Animation*);
void RefreshTarget();
AnimationTimeDelta CalculateTimeToEffectChange( AnimationTimeDelta CalculateTimeToEffectChange(
bool forwards, bool forwards,
base::Optional<double> inherited_time, base::Optional<double> inherited_time,
...@@ -148,6 +154,8 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect { ...@@ -148,6 +154,8 @@ class CORE_EXPORT KeyframeEffect final : public AnimationEffect {
bool AnimationsPreserveAxisAlignment(const PropertyHandle&) const; bool AnimationsPreserveAxisAlignment(const PropertyHandle&) const;
Member<Element> effect_target_; Member<Element> effect_target_;
Member<Element> target_element_;
String target_pseudo_;
Member<KeyframeEffectModelBase> model_; Member<KeyframeEffectModelBase> model_;
Member<SampledEffect> sampled_effect_; Member<SampledEffect> sampled_effect_;
......
...@@ -39,6 +39,7 @@ enum CompositeOperation { "replace", "add", "accumulate" }; ...@@ -39,6 +39,7 @@ enum CompositeOperation { "replace", "add", "accumulate" };
[CallWith=ScriptState, RaisesException] constructor(Element? target, object? keyframes, optional (unrestricted double or KeyframeEffectOptions) options); [CallWith=ScriptState, RaisesException] constructor(Element? target, object? keyframes, optional (unrestricted double or KeyframeEffectOptions) options);
[CallWith=ScriptState, RaisesException] constructor(KeyframeEffect source); [CallWith=ScriptState, RaisesException] constructor(KeyframeEffect source);
attribute Element? target; attribute Element? target;
[RuntimeEnabled=WebAnimationsAPI, RaisesException=Setter] attribute CSSOMString? pseudoElement;
[RuntimeEnabled=WebAnimationsAPI] attribute CompositeOperation composite; [RuntimeEnabled=WebAnimationsAPI] attribute CompositeOperation composite;
[CallWith=ScriptState, RuntimeEnabled=WebAnimationsAPI] sequence<object> getKeyframes(); [CallWith=ScriptState, RuntimeEnabled=WebAnimationsAPI] sequence<object> getKeyframes();
[CallWith=ScriptState, RaisesException, RuntimeEnabled=WebAnimationsAPI] void setKeyframes(object? keyframes); [CallWith=ScriptState, RaisesException, RuntimeEnabled=WebAnimationsAPI] void setKeyframes(object? keyframes);
......
...@@ -7,4 +7,5 @@ ...@@ -7,4 +7,5 @@
dictionary KeyframeEffectOptions : EffectTiming { dictionary KeyframeEffectOptions : EffectTiming {
// TODO(alancutter): Implement iterationComposite // TODO(alancutter): Implement iterationComposite
CompositeOperation composite = "replace"; CompositeOperation composite = "replace";
CSSOMString? pseudoElement = null;
}; };
...@@ -12,6 +12,6 @@ PASS Finished but not filling CSS Animations are not returned ...@@ -12,6 +12,6 @@ PASS Finished but not filling CSS Animations are not returned
PASS Yet-to-start CSS Animations are returned PASS Yet-to-start CSS Animations are returned
PASS CSS Animations canceled via the API are not returned PASS CSS Animations canceled via the API are not returned
PASS CSS Animations canceled and restarted via the API are returned PASS CSS Animations canceled and restarted via the API are returned
FAIL CSS Animations targetting (pseudo-)elements should have correct order after sorting assert_equals: Animation #1 has null pseudo type expected (object) null but got (undefined) undefined FAIL CSS Animations targetting (pseudo-)elements should have correct order after sorting assert_equals: Animation #3 has expected target expected Element node <div id="parent" style="animation: animBottom 100s"><div ... but got Element node <div style="animation: animBottom 100s"></div>
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -17,9 +17,9 @@ PASS getAnimations returns objects with the same identity ...@@ -17,9 +17,9 @@ PASS getAnimations returns objects with the same identity
PASS getAnimations for CSS Animations that are canceled PASS getAnimations for CSS Animations that are canceled
FAIL getAnimations for CSS Animations follows animation-name order assert_equals: animation order after prepending to list expected "anim1" but got "anim2" FAIL getAnimations for CSS Animations follows animation-name order assert_equals: animation order after prepending to list expected "anim1" but got "anim2"
PASS { subtree: false } on a leaf element returns the element's animations and ignore pseudo-elements PASS { subtree: false } on a leaf element returns the element's animations and ignore pseudo-elements
FAIL { subtree: true } on a leaf element returns the element's animations and its pseudo-elements' animations assert_equals: The animation targeting the parent element should be returned first expected (object) null but got (undefined) undefined PASS { subtree: true } on a leaf element returns the element's animations and its pseudo-elements' animations
PASS { subtree: false } on an element with a child returns only the element's animations PASS { subtree: false } on an element with a child returns only the element's animations
FAIL { subtree: true } on an element with a child returns animations from the element, its pseudo-elements, its child and its child pseudo-elements assert_equals: The animation targeting the parent element should be returned first expected (object) null but got (undefined) undefined FAIL { subtree: true } on an element with a child returns animations from the element, its pseudo-elements, its child and its child pseudo-elements assert_equals: The animation targeting the ::after pesudo-element should be returned third expected (string) "::after" but got (object) null
PASS { subtree: true } on an element with many descendants returns animations from all the descendants PASS { subtree: true } on an element with many descendants returns animations from all the descendants
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.
PASS getAnimations for non-animated content PASS getAnimations for non-animated content
PASS getAnimations for CSS Transitions PASS getAnimations for CSS Transitions
FAIL CSS Transitions targetting (pseudo-)elements should have correct order after sorting assert_equals: Transition #1 has null pseudo type expected (object) null but got (undefined) undefined FAIL CSS Transitions targetting (pseudo-)elements should have correct order after sorting assert_equals: Transition #3 has expected target expected Element node <div style="display: list-item; left: 100px; transition: ... but got Element node <div style="left: 100px; transition: left 100s ease 0s;">...
PASS Transitions are not returned after they have finished PASS Transitions are not returned after they have finished
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 143 tests; 131 PASS, 12 FAIL, 0 TIMEOUT, 0 NOTRUN. Found 143 tests; 133 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS idl_test setup PASS idl_test setup
PASS idl_test validation PASS idl_test validation
PASS Partial interface Document: original interface defined PASS Partial interface Document: original interface defined
...@@ -107,14 +107,14 @@ PASS KeyframeEffect interface: existence and properties of interface prototype o ...@@ -107,14 +107,14 @@ PASS KeyframeEffect interface: existence and properties of interface prototype o
PASS KeyframeEffect interface: existence and properties of interface prototype object's "constructor" property PASS KeyframeEffect interface: existence and properties of interface prototype object's "constructor" property
PASS KeyframeEffect interface: existence and properties of interface prototype object's @@unscopables property PASS KeyframeEffect interface: existence and properties of interface prototype object's @@unscopables property
PASS KeyframeEffect interface: attribute target PASS KeyframeEffect interface: attribute target
FAIL KeyframeEffect interface: attribute pseudoElement assert_true: The prototype object must have a property "pseudoElement" expected true got false PASS KeyframeEffect interface: attribute pseudoElement
PASS KeyframeEffect interface: attribute composite PASS KeyframeEffect interface: attribute composite
PASS KeyframeEffect interface: operation getKeyframes() PASS KeyframeEffect interface: operation getKeyframes()
PASS KeyframeEffect interface: operation setKeyframes(object) PASS KeyframeEffect interface: operation setKeyframes(object)
PASS KeyframeEffect must be primary interface of new KeyframeEffect(null, null) PASS KeyframeEffect must be primary interface of new KeyframeEffect(null, null)
PASS Stringification of new KeyframeEffect(null, null) PASS Stringification of new KeyframeEffect(null, null)
PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "target" with the proper type PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "target" with the proper type
FAIL KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "pseudoElement" with the proper type assert_inherits: property "pseudoElement" not found in prototype chain PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "pseudoElement" with the proper type
PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "composite" with the proper type PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "composite" with the proper type
PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "getKeyframes()" with the proper type PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "getKeyframes()" with the proper type
PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "setKeyframes(object)" with the proper type PASS KeyframeEffect interface: new KeyframeEffect(null, null) must inherit property "setKeyframes(object)" with the proper type
......
This is a testharness.js-based test. This is a testharness.js-based test.
FAIL All property keys are recognized assert_in_array: Test property 'iterationComposite' should be one of the properties on KeyframeEffect value "iterationComposite" not in array ["getTiming", "getComputedTiming", "updateTiming", "target", "composite", "getKeyframes", "setKeyframes", "KeyframeEffect constructor", "KeyframeEffect copy constructor"] FAIL All property keys are recognized assert_in_array: Test property 'iterationComposite' should be one of the properties on KeyframeEffect value "iterationComposite" not in array ["getTiming", "getComputedTiming", "updateTiming", "target", "composite", "pseudoElement", "getKeyframes", "setKeyframes", "KeyframeEffect constructor", "KeyframeEffect copy constructor"]
PASS KeyframeEffect.getTiming does NOT trigger a style change event PASS KeyframeEffect.getTiming does NOT trigger a style change event
PASS KeyframeEffect.getComputedTiming does NOT trigger a style change event PASS KeyframeEffect.getComputedTiming does NOT trigger a style change event
PASS KeyframeEffect.updateTiming does NOT trigger a style change event PASS KeyframeEffect.updateTiming does NOT trigger a style change event
PASS KeyframeEffect.target does NOT trigger a style change event PASS KeyframeEffect.target does NOT trigger a style change event
PASS KeyframeEffect.composite does NOT trigger a style change event PASS KeyframeEffect.composite does NOT trigger a style change event
PASS KeyframeEffect.pseudoElement does NOT trigger a style change event
PASS KeyframeEffect.getKeyframes does NOT trigger a style change event PASS KeyframeEffect.getKeyframes does NOT trigger a style change event
PASS KeyframeEffect.setKeyframes does NOT trigger a style change event PASS KeyframeEffect.setKeyframes does NOT trigger a style change event
PASS KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event PASS KeyframeEffect.KeyframeEffect constructor does NOT trigger a style change event
......
...@@ -121,6 +121,15 @@ const tests = { ...@@ -121,6 +121,15 @@ const tests = {
}, },
}); });
}, },
pseudoElement: MakeInEffectTest({
setup: elem => elem.animate(
{opacity: [0.5, 1]},
{duration: 100 * MS_PER_SEC, pseudoElement: '::before'}
),
test: effect => {
effect.pseudoElement = null;
},
}),
iterationComposite: UsePropertyTest(effect => { iterationComposite: UsePropertyTest(effect => {
// Get iterationComposite // Get iterationComposite
effect.iterationComposite; effect.iterationComposite;
......
...@@ -4,19 +4,19 @@ PASS Test setting target from null to a valid target ...@@ -4,19 +4,19 @@ PASS Test setting target from null to a valid target
PASS Test setting target from a valid target to null PASS Test setting target from a valid target to null
PASS Test setting target from a valid target to another target PASS Test setting target from a valid target to another target
PASS Target element can be set to a foreign element PASS Target element can be set to a foreign element
FAIL Change target from null to an existing pseudoElement setting target first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px" PASS Change target from null to an existing pseudoElement setting target first.
FAIL Change target from null to an existing pseudoElement setting pseudoElement first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px" PASS Change target from null to an existing pseudoElement setting pseudoElement first.
PASS Change target from an existing pseudo-element to the originating element. PASS Change target from an existing pseudo-element to the originating element.
FAIL Change target from an existing to a different existing pseudo-element by setting target. assert_equals: Animation targets specified pseudo-element (pseudo-selector) expected (string) "::before" but got (undefined) undefined PASS Change target from an existing to a different existing pseudo-element by setting target.
FAIL Change target from an existing to a different existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px" PASS Change target from an existing to a different existing pseudo-element by setting pseudoElement.
FAIL Change target from a non-existing to a different existing pseudo-element by setting target. assert_equals: Animation targets specified pseudo-element (pseudo-selector) expected (string) "::before" but got (undefined) undefined PASS Change target from a non-existing to a different existing pseudo-element by setting target.
FAIL Change target from a non-existing to a different existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px" PASS Change target from a non-existing to a different existing pseudo-element by setting pseudoElement.
FAIL Change target from null to a non-existing pseudoElement setting target first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px" FAIL Change target from null to a non-existing pseudoElement setting target first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px"
FAIL Change target from null to a non-existing pseudoElement setting pseudoElement first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px" FAIL Change target from null to a non-existing pseudoElement setting pseudoElement first. assert_equals: Value at 50% progress after setting new target expected "50px" but got "10px"
PASS Change target from a non-existing pseudo-element to the originating element. PASS Change target from a non-existing pseudo-element to the originating element.
FAIL Change target from an existing to a different non-existing pseudo-element by setting target. assert_equals: Animation targets specified pseudo-element (pseudo-selector) expected (string) "::before" but got (undefined) undefined FAIL Change target from an existing to a different non-existing pseudo-element by setting target. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px"
FAIL Change target from an existing to a different non-existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px" FAIL Change target from an existing to a different non-existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px"
FAIL Change target from a non-existing to a different non-existing pseudo-element by setting target. assert_equals: Animation targets specified pseudo-element (pseudo-selector) expected (string) "::before" but got (undefined) undefined FAIL Change target from a non-existing to a different non-existing pseudo-element by setting target. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px"
FAIL Change target from a non-existing to a different non-existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px" FAIL Change target from a non-existing to a different non-existing pseudo-element by setting pseudoElement. assert_equals: Value of 2nd element (currently targeted) after changing the effect target expected "50px" but got "20px"
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -4613,11 +4613,13 @@ interface KeyboardLayoutMap ...@@ -4613,11 +4613,13 @@ interface KeyboardLayoutMap
interface KeyframeEffect : AnimationEffect interface KeyframeEffect : AnimationEffect
attribute @@toStringTag attribute @@toStringTag
getter composite getter composite
getter pseudoElement
getter target getter target
method constructor method constructor
method getKeyframes method getKeyframes
method setKeyframes method setKeyframes
setter composite setter composite
setter pseudoElement
setter target setter target
interface LargestContentfulPaint : PerformanceEntry interface LargestContentfulPaint : PerformanceEntry
attribute @@toStringTag attribute @@toStringTag
......
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