mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-26 12:41:59 +03:00
LibWeb: Implement Document::remove_replaced_animations()
This commit is contained in:
parent
fe848487db
commit
10fddb99fc
Notes:
sideshowbarker
2024-07-17 04:10:16 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/10fddb99fc Pull-request: https://github.com/SerenityOS/serenity/pull/23300
@ -345,6 +345,20 @@ bool Animation::is_replaceable() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void Animation::set_replace_state(Bindings::AnimationReplaceState value)
|
||||
{
|
||||
m_replace_state = value;
|
||||
|
||||
if (value == Bindings::AnimationReplaceState::Removed) {
|
||||
// Remove the associated effect from its target, if applicable
|
||||
if (m_effect && m_effect->target())
|
||||
m_effect->target()->disassociate_with_effect(*m_effect);
|
||||
|
||||
// Remove this animation from its timeline
|
||||
m_timeline->disassociate_with_animation(*this);
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animation-play
|
||||
WebIDL::ExceptionOr<void> Animation::play()
|
||||
{
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
|
||||
bool is_replaceable() const;
|
||||
Bindings::AnimationReplaceState replace_state() const { return m_replace_state; }
|
||||
void set_replace_state(Bindings::AnimationReplaceState value);
|
||||
|
||||
// https://www.w3.org/TR/web-animations-1/#dom-animation-pending
|
||||
bool pending() const { return m_pending_play_task == TaskState::Scheduled || m_pending_pause_task == TaskState::Scheduled; }
|
||||
|
@ -142,6 +142,7 @@ public:
|
||||
Optional<double> transformed_progress() const;
|
||||
|
||||
virtual DOM::Element* target() const { return {}; }
|
||||
virtual bool is_keyframe_effect() const { return false; }
|
||||
|
||||
protected:
|
||||
AnimationEffect(JS::Realm&);
|
||||
|
@ -96,6 +96,8 @@ public:
|
||||
KeyFrameSet const* key_frame_set() { return m_key_frame_set; }
|
||||
void set_key_frame_set(RefPtr<KeyFrameSet const> key_frame_set) { m_key_frame_set = key_frame_set; }
|
||||
|
||||
virtual bool is_keyframe_effect() const override { return true; }
|
||||
|
||||
private:
|
||||
KeyframeEffect(JS::Realm&);
|
||||
virtual ~KeyframeEffect() override;
|
||||
|
@ -3820,7 +3820,92 @@ void Document::update_animations_and_send_events(Optional<double> const& timesta
|
||||
// https://www.w3.org/TR/web-animations-1/#remove-replaced-animations
|
||||
void Document::remove_replaced_animations()
|
||||
{
|
||||
// FIXME: Implement this
|
||||
// When asked to remove replaced animations for a Document, doc, then for every animation, animation, that:
|
||||
// - has an associated animation effect whose effect target is a descendant of doc, and
|
||||
// - is replaceable, and
|
||||
// - has a replace state of active, and
|
||||
// - for which there exists for each target property of every animation effect associated with animation, an
|
||||
// animation effect associated with a replaceable animation with a higher composite order than animation that
|
||||
// includes the same target property
|
||||
|
||||
Vector<JS::NonnullGCPtr<Animations::Animation>> replaceable_animations;
|
||||
for (auto const& timeline : m_associated_animation_timelines) {
|
||||
for (auto const& animation : timeline->associated_animations()) {
|
||||
if (!animation->effect() || !animation->effect()->target() || &animation->effect()->target()->document() != this)
|
||||
continue;
|
||||
|
||||
if (!animation->is_replaceable())
|
||||
continue;
|
||||
|
||||
if (animation->replace_state() != Bindings::AnimationReplaceState::Active)
|
||||
continue;
|
||||
|
||||
// Composite order is only defined for KeyframeEffects
|
||||
if (!animation->effect()->is_keyframe_effect())
|
||||
continue;
|
||||
|
||||
replaceable_animations.append(animation);
|
||||
}
|
||||
}
|
||||
|
||||
quick_sort(replaceable_animations, [](JS::NonnullGCPtr<Animations::Animation>& a, JS::NonnullGCPtr<Animations::Animation>& b) {
|
||||
VERIFY(a->effect()->is_keyframe_effect());
|
||||
VERIFY(b->effect()->is_keyframe_effect());
|
||||
auto& a_effect = *static_cast<Animations::KeyframeEffect*>(a->effect().ptr());
|
||||
auto& b_effect = *static_cast<Animations::KeyframeEffect*>(b->effect().ptr());
|
||||
return Animations::KeyframeEffect::composite_order(a_effect, b_effect) < 0;
|
||||
});
|
||||
|
||||
// Lower value = higher priority
|
||||
HashMap<CSS::PropertyID, size_t> highest_property_composite_orders;
|
||||
for (int i = replaceable_animations.size() - 1; i >= 0; i--) {
|
||||
auto animation = replaceable_animations[i];
|
||||
bool has_any_highest_priority_property = false;
|
||||
|
||||
for (auto const& property : animation->effect()->target_properties()) {
|
||||
if (!highest_property_composite_orders.contains(property)) {
|
||||
has_any_highest_priority_property = true;
|
||||
highest_property_composite_orders.set(property, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_any_highest_priority_property) {
|
||||
// perform the following steps:
|
||||
|
||||
// - Set animation’s replace state to removed.
|
||||
animation->set_replace_state(Bindings::AnimationReplaceState::Removed);
|
||||
|
||||
// - Create an AnimationPlaybackEvent, removeEvent.
|
||||
// - Set removeEvent’s type attribute to remove.
|
||||
// - Set removeEvent’s currentTime attribute to the current time of animation.
|
||||
// - Set removeEvent’s timelineTime attribute to the current time of the timeline with which animation is
|
||||
// associated.
|
||||
Animations::AnimationPlaybackEventInit init;
|
||||
init.current_time = animation->current_time();
|
||||
init.timeline_time = animation->timeline()->current_time();
|
||||
auto remove_event = Animations::AnimationPlaybackEvent::create(realm(), HTML::EventNames::remove, init);
|
||||
|
||||
// - If animation has a document for timing, then append removeEvent to its document for timing's pending
|
||||
// animation event queue along with its target, animation. For the scheduled event time, use the result of
|
||||
// applying the procedure to convert timeline time to origin-relative time to the current time of the
|
||||
// timeline with which animation is associated.
|
||||
if (auto document = animation->document_for_timing()) {
|
||||
PendingAnimationEvent pending_animation_event {
|
||||
remove_event,
|
||||
animation,
|
||||
animation->timeline()->convert_a_timeline_time_to_an_origin_relative_time(init.timeline_time),
|
||||
};
|
||||
document->append_pending_animation_event(pending_animation_event);
|
||||
}
|
||||
// Otherwise, queue a task to dispatch removeEvent at animation. The task source for this task is the DOM
|
||||
// manipulation task source.
|
||||
else {
|
||||
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, realm().global_object(), [animation, remove_event]() {
|
||||
animation->dispatch_event(remove_event);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/dom.html#dom-document-nameditem-filter
|
||||
|
@ -81,6 +81,7 @@ namespace Web::HTML::EventNames {
|
||||
__ENUMERATE_HTML_EVENT(ratechange) \
|
||||
__ENUMERATE_HTML_EVENT(readystatechange) \
|
||||
__ENUMERATE_HTML_EVENT(rejectionhandled) \
|
||||
__ENUMERATE_HTML_EVENT(remove) \
|
||||
__ENUMERATE_HTML_EVENT(removetrack) \
|
||||
__ENUMERATE_HTML_EVENT(reset) \
|
||||
__ENUMERATE_HTML_EVENT(resize) \
|
||||
|
Loading…
Reference in New Issue
Block a user