diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp index 0ded127403..68d11b81d1 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -630,7 +630,7 @@ WebIDL::ExceptionOr> KeyframeEffect::construct_ // When assigning this property, the error-handling defined for the pseudoElement setter on the interface is // applied. If the setter requires an exception to be thrown, this procedure must throw the same exception and // abort all further steps. - effect->set_pseudo_element(options.get().pseudo_element); + TRY(effect->set_pseudo_element(options.get().pseudo_element)); } // Otherwise, else { @@ -730,16 +730,14 @@ void KeyframeEffect::set_target(DOM::Element* target) m_target_element->associate_with_effect(*this); } -void KeyframeEffect::set_pseudo_element(Optional pseudo_element) +WebIDL::ExceptionOr KeyframeEffect::set_pseudo_element(Optional pseudo_element) { + auto& realm = this->realm(); + // On setting, sets the target pseudo-selector of the animation effect to the provided value after applying the // following exceptions: // FIXME: - // - If the provided value is not null and is an invalid , the user agent must throw a - // DOMException with error name SyntaxError and leave the target pseudo-selector of this animation effect - // unchanged. - // - If one of the legacy Selectors Level 2 single-colon selectors (':before', ':after', ':first-letter', or // ':first-line') is specified, the target pseudo-selector must be set to the equivalent two-colon selector // (e.g. '::before'). @@ -747,12 +745,33 @@ void KeyframeEffect::set_pseudo_element(Optional pseudo_element) auto value = pseudo_element.value(); if (value == ":before" || value == ":after" || value == ":first-letter" || value == ":first-line") { - m_target_pseudo_selector = MUST(String::formatted(":{}", value)); - return; + m_target_pseudo_selector = CSS::Selector::PseudoElement::from_string(MUST(value.substring_from_byte_offset(1))); + return {}; } } - m_target_pseudo_selector = pseudo_element; + // - If the provided value is not null and is an invalid , the user agent must throw a + // DOMException with error name SyntaxError and leave the target pseudo-selector of this animation effect + // unchanged. + if (pseudo_element.has_value()) { + auto pseudo_element_without_colons = MUST(pseudo_element->replace("::"sv, ""sv, ReplaceMode::FirstOnly)); + if (auto value = CSS::Selector::PseudoElement::from_string(pseudo_element_without_colons); value.has_value()) { + m_target_pseudo_selector = value; + } else { + return WebIDL::SyntaxError::create(realm, MUST(String::formatted("Invalid pseudo-element selector: \"{}\"", pseudo_element.value()))); + } + } else { + m_target_pseudo_selector = {}; + } + + return {}; +} + +Optional KeyframeEffect::pseudo_element_type() const +{ + if (!m_target_pseudo_selector.has_value()) + return {}; + return m_target_pseudo_selector->type(); } // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-getkeyframes diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h index 968b50be37..fd2dfd689d 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.h @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace Web::Animations { @@ -84,8 +85,12 @@ public: DOM::Element* target() const override { return m_target_element; } void set_target(DOM::Element* target); - Optional pseudo_element() const { return m_target_pseudo_selector; } - void set_pseudo_element(Optional); + // JS bindings + Optional pseudo_element() const { return m_target_pseudo_selector->name(); } + WebIDL::ExceptionOr set_pseudo_element(Optional); + + Optional pseudo_element_type() const; + void set_pseudo_element(Optional pseudo_element) { m_target_pseudo_selector = pseudo_element; } Bindings::CompositeOperation composite() const { return m_composite; } void set_composite(Bindings::CompositeOperation value) { m_composite = value; } @@ -109,7 +114,7 @@ private: JS::GCPtr m_target_element {}; // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-pseudoelement - Optional m_target_pseudo_selector {}; + Optional m_target_pseudo_selector {}; // https://www.w3.org/TR/web-animations-1/#dom-keyframeeffect-composite Bindings::CompositeOperation m_composite { Bindings::CompositeOperation::Replace }; diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index 5298a1d3b6..c38de3fa2d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -1074,6 +1074,8 @@ ErrorOr StyleComputer::compute_cascaded_values(StyleProperties& style, DOM effect->set_timing_function(move(timing_function)); effect->set_fill_mode(Animations::css_fill_mode_to_bindings_fill_mode(fill_mode)); effect->set_playback_direction(Animations::css_animation_direction_to_bindings_playback_direction(direction)); + if (pseudo_element.has_value()) + effect->set_pseudo_element(Selector::PseudoElement { pseudo_element.value() }); auto animation = CSSAnimation::create(realm); animation->set_id(animation_name.release_value()); @@ -1099,7 +1101,8 @@ ErrorOr StyleComputer::compute_cascaded_values(StyleProperties& style, DOM if (auto effect = animation->effect(); effect && effect->is_keyframe_effect()) { auto& keyframe_effect = *static_cast(effect.ptr()); - TRY(collect_animation_into(keyframe_effect, style)); + if (keyframe_effect.pseudo_element_type() == pseudo_element) + TRY(collect_animation_into(keyframe_effect, style)); } }