mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-08 01:00:05 +00:00
LibWeb/DOM: Fire transition[cancel,start,run,end] events
This commit is contained in:
parent
a2ab3769f4
commit
1c61ccef40
Notes:
github-actions[bot]
2024-12-25 16:15:01 +00:00
Author: https://github.com/LucasChollet
Commit: 1c61ccef40
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3024
6 changed files with 152 additions and 1 deletions
|
@ -111,6 +111,8 @@ public:
|
||||||
|
|
||||||
auto release_saved_cancel_time() { return move(m_saved_cancel_time); }
|
auto release_saved_cancel_time() { return move(m_saved_cancel_time); }
|
||||||
|
|
||||||
|
double associated_effect_end() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Animation(JS::Realm&);
|
Animation(JS::Realm&);
|
||||||
|
|
||||||
|
@ -133,7 +135,6 @@ private:
|
||||||
No,
|
No,
|
||||||
};
|
};
|
||||||
|
|
||||||
double associated_effect_end() const;
|
|
||||||
double effective_playback_rate() const;
|
double effective_playback_rate() const;
|
||||||
|
|
||||||
void apply_any_pending_playback_rate();
|
void apply_any_pending_playback_rate();
|
||||||
|
|
|
@ -118,6 +118,7 @@ public:
|
||||||
bool is_in_the_active_phase() const;
|
bool is_in_the_active_phase() const;
|
||||||
bool is_in_the_idle_phase() const;
|
bool is_in_the_idle_phase() const;
|
||||||
|
|
||||||
|
// Keep this enum up to date with CSSTransition::Phase.
|
||||||
enum class Phase {
|
enum class Phase {
|
||||||
Before,
|
Before,
|
||||||
Active,
|
Active,
|
||||||
|
|
|
@ -39,6 +39,17 @@ public:
|
||||||
double timing_function_output_at_time(double t) const;
|
double timing_function_output_at_time(double t) const;
|
||||||
NonnullRefPtr<CSSStyleValue const> value_at_time(double t) const;
|
NonnullRefPtr<CSSStyleValue const> value_at_time(double t) const;
|
||||||
|
|
||||||
|
// This is designed to be created from AnimationEffect::Phase.
|
||||||
|
enum class Phase : u8 {
|
||||||
|
Before,
|
||||||
|
Active,
|
||||||
|
After,
|
||||||
|
Idle,
|
||||||
|
Pending,
|
||||||
|
};
|
||||||
|
Phase previous_phase() const { return m_previous_phase; }
|
||||||
|
void set_previous_phase(Phase phase) { m_previous_phase = phase; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSSTransition(JS::Realm&, DOM::Element&, PropertyID, size_t transition_generation,
|
CSSTransition(JS::Realm&, DOM::Element&, PropertyID, size_t transition_generation,
|
||||||
double start_time, double end_time, NonnullRefPtr<CSSStyleValue const> start_value, NonnullRefPtr<CSSStyleValue const> end_value,
|
double start_time, double end_time, NonnullRefPtr<CSSStyleValue const> start_value, NonnullRefPtr<CSSStyleValue const> end_value,
|
||||||
|
@ -75,6 +86,8 @@ private:
|
||||||
GC::Ref<Animations::KeyframeEffect> m_keyframe_effect;
|
GC::Ref<Animations::KeyframeEffect> m_keyframe_effect;
|
||||||
|
|
||||||
GC::Ptr<CSS::CSSStyleDeclaration const> m_cached_declaration;
|
GC::Ptr<CSS::CSSStyleDeclaration const> m_cached_declaration;
|
||||||
|
|
||||||
|
Phase m_previous_phase { Phase::Idle };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,12 +32,14 @@
|
||||||
#include <LibWeb/CSS/AnimationEvent.h>
|
#include <LibWeb/CSS/AnimationEvent.h>
|
||||||
#include <LibWeb/CSS/CSSAnimation.h>
|
#include <LibWeb/CSS/CSSAnimation.h>
|
||||||
#include <LibWeb/CSS/CSSImportRule.h>
|
#include <LibWeb/CSS/CSSImportRule.h>
|
||||||
|
#include <LibWeb/CSS/CSSTransition.h>
|
||||||
#include <LibWeb/CSS/FontFaceSet.h>
|
#include <LibWeb/CSS/FontFaceSet.h>
|
||||||
#include <LibWeb/CSS/MediaQueryList.h>
|
#include <LibWeb/CSS/MediaQueryList.h>
|
||||||
#include <LibWeb/CSS/MediaQueryListEvent.h>
|
#include <LibWeb/CSS/MediaQueryListEvent.h>
|
||||||
#include <LibWeb/CSS/StyleComputer.h>
|
#include <LibWeb/CSS/StyleComputer.h>
|
||||||
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
||||||
#include <LibWeb/CSS/SystemColor.h>
|
#include <LibWeb/CSS/SystemColor.h>
|
||||||
|
#include <LibWeb/CSS/TransitionEvent.h>
|
||||||
#include <LibWeb/CSS/VisualViewport.h>
|
#include <LibWeb/CSS/VisualViewport.h>
|
||||||
#include <LibWeb/Cookie/ParsedCookie.h>
|
#include <LibWeb/Cookie/ParsedCookie.h>
|
||||||
#include <LibWeb/DOM/AdoptedStyleSheets.h>
|
#include <LibWeb/DOM/AdoptedStyleSheets.h>
|
||||||
|
@ -2204,9 +2206,139 @@ Element* Document::find_a_potential_indicated_element(FlyString const& fragment)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-transitions-2/#event-dispatch
|
||||||
|
void Document::dispatch_events_for_transition(GC::Ref<CSS::CSSTransition> transition)
|
||||||
|
{
|
||||||
|
auto previous_phase = transition->previous_phase();
|
||||||
|
|
||||||
|
using Phase = CSS::CSSTransition::Phase;
|
||||||
|
// The transition phase of a transition is initially ‘idle’ and is updated on each
|
||||||
|
// animation frame according to the first matching condition from below:
|
||||||
|
auto transition_phase = Phase::Idle;
|
||||||
|
|
||||||
|
if (!transition->effect()) {
|
||||||
|
// If the transition has no associated effect,
|
||||||
|
if (!transition->current_time().has_value()) {
|
||||||
|
// If the transition has an unresolved current time,
|
||||||
|
// The transition phase is ‘idle’.
|
||||||
|
} else if (transition->current_time().value() < 0.0) {
|
||||||
|
// If the transition has a current time < 0,
|
||||||
|
// The transition phase is ‘before’.
|
||||||
|
transition_phase = Phase::Before;
|
||||||
|
} else {
|
||||||
|
// Otherwise,
|
||||||
|
// The transition phase is ‘after’.
|
||||||
|
transition_phase = Phase::After;
|
||||||
|
}
|
||||||
|
} else if (transition->pending() && (previous_phase == Phase::Idle || previous_phase == Phase::Pending)) {
|
||||||
|
// If the transition has a pending play task or a pending pause task
|
||||||
|
// and its phase was previously ‘idle’ or ‘pending’,
|
||||||
|
// The transition phase is ‘pending’.
|
||||||
|
transition_phase = Phase::Pending;
|
||||||
|
} else {
|
||||||
|
// Otherwise,
|
||||||
|
// The transition phase is the phase of its associated effect.
|
||||||
|
transition_phase = Phase(to_underlying(transition->effect()->phase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Interval : u8 {
|
||||||
|
Start,
|
||||||
|
End,
|
||||||
|
ActiveTime,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto dispatch_event = [&](FlyString const& type, Interval interval) {
|
||||||
|
// The target for a transition event is the transition’s owning element. If there is no owning element,
|
||||||
|
// no transition events are dispatched.
|
||||||
|
if (!transition->effect() || !transition->owning_element())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto effect = transition->effect();
|
||||||
|
|
||||||
|
double elapsed_time = [&]() {
|
||||||
|
if (interval == Interval::Start)
|
||||||
|
return max(min(-effect->start_delay(), effect->active_duration()), 0) / 1000;
|
||||||
|
if (interval == Interval::End)
|
||||||
|
return max(min(transition->associated_effect_end() - effect->start_delay(), effect->active_duration()), 0) / 1000;
|
||||||
|
if (interval == Interval::ActiveTime) {
|
||||||
|
// The active time of the animation at the moment it was canceled calculated using a fill mode of both.
|
||||||
|
// FIXME: Compute this properly.
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}();
|
||||||
|
|
||||||
|
append_pending_animation_event({
|
||||||
|
.event = CSS::TransitionEvent::create(
|
||||||
|
transition->owning_element()->realm(),
|
||||||
|
type,
|
||||||
|
CSS::TransitionEventInit {
|
||||||
|
{ .bubbles = true },
|
||||||
|
// FIXME: Correctly set property_name and pseudo_element
|
||||||
|
String {},
|
||||||
|
elapsed_time,
|
||||||
|
String {},
|
||||||
|
}),
|
||||||
|
.animation = transition,
|
||||||
|
.target = *transition->owning_element(),
|
||||||
|
.scheduled_event_time = HighResolutionTime::unsafe_shared_current_time(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (previous_phase == Phase::Idle) {
|
||||||
|
if (transition_phase == Phase::Pending || transition_phase == Phase::Before)
|
||||||
|
dispatch_event(HTML::EventNames::transitionrun, Interval::Start);
|
||||||
|
|
||||||
|
if (transition_phase == Phase::Active) {
|
||||||
|
dispatch_event(HTML::EventNames::transitionrun, Interval::Start);
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::Start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transition_phase == Phase::After) {
|
||||||
|
dispatch_event(HTML::EventNames::transitionrun, Interval::Start);
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::Start);
|
||||||
|
dispatch_event(HTML::EventNames::transitionend, Interval::End);
|
||||||
|
}
|
||||||
|
} else if (previous_phase == Phase::Pending || previous_phase == Phase::Before) {
|
||||||
|
if (transition_phase == Phase::Active)
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::Start);
|
||||||
|
|
||||||
|
if (transition_phase == Phase::After) {
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::Start);
|
||||||
|
dispatch_event(HTML::EventNames::transitionend, Interval::End);
|
||||||
|
}
|
||||||
|
} else if (previous_phase == Phase::Active) {
|
||||||
|
if (transition_phase == Phase::After)
|
||||||
|
dispatch_event(HTML::EventNames::transitionend, Interval::End);
|
||||||
|
|
||||||
|
if (transition_phase == Phase::Before)
|
||||||
|
dispatch_event(HTML::EventNames::transitionend, Interval::Start);
|
||||||
|
} else if (previous_phase == Phase::After) {
|
||||||
|
if (transition_phase == Phase::Active)
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::End);
|
||||||
|
|
||||||
|
if (transition_phase == Phase::Before) {
|
||||||
|
dispatch_event(HTML::EventNames::transitionstart, Interval::End);
|
||||||
|
dispatch_event(HTML::EventNames::transitionend, Interval::Start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transition_phase == Phase::Idle) {
|
||||||
|
if (previous_phase != Phase::Idle && previous_phase != Phase::After)
|
||||||
|
dispatch_event(HTML::EventNames::animationstart, Interval::ActiveTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
transition->set_previous_phase(transition_phase);
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-animations-2/#event-dispatch
|
// https://www.w3.org/TR/css-animations-2/#event-dispatch
|
||||||
void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::Animation> animation)
|
void Document::dispatch_events_for_animation_if_necessary(GC::Ref<Animations::Animation> animation)
|
||||||
{
|
{
|
||||||
|
if (animation->is_css_transition()) {
|
||||||
|
dispatch_events_for_transition(verify_cast<CSS::CSSTransition>(*animation));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Each time a new animation frame is established and the animation does not have a pending play task or pending
|
// Each time a new animation frame is established and the animation does not have a pending play task or pending
|
||||||
// pause task, the events to dispatch are determined by comparing the animation’s phase before and after
|
// pause task, the events to dispatch are determined by comparing the animation’s phase before and after
|
||||||
// establishing the new animation frame as follows:
|
// establishing the new animation frame as follows:
|
||||||
|
|
|
@ -785,6 +785,7 @@ private:
|
||||||
|
|
||||||
Element* find_a_potential_indicated_element(FlyString const& fragment) const;
|
Element* find_a_potential_indicated_element(FlyString const& fragment) const;
|
||||||
|
|
||||||
|
void dispatch_events_for_transition(GC::Ref<CSS::CSSTransition>);
|
||||||
void dispatch_events_for_animation_if_necessary(GC::Ref<Animations::Animation>);
|
void dispatch_events_for_animation_if_necessary(GC::Ref<Animations::Animation>);
|
||||||
|
|
||||||
template<typename GetNotifier, typename... Args>
|
template<typename GetNotifier, typename... Args>
|
||||||
|
|
|
@ -116,6 +116,9 @@ namespace Web::HTML::EventNames {
|
||||||
__ENUMERATE_HTML_EVENT(suspend) \
|
__ENUMERATE_HTML_EVENT(suspend) \
|
||||||
__ENUMERATE_HTML_EVENT(timeupdate) \
|
__ENUMERATE_HTML_EVENT(timeupdate) \
|
||||||
__ENUMERATE_HTML_EVENT(toggle) \
|
__ENUMERATE_HTML_EVENT(toggle) \
|
||||||
|
__ENUMERATE_HTML_EVENT(transitioncancel) \
|
||||||
|
__ENUMERATE_HTML_EVENT(transitionrun) \
|
||||||
|
__ENUMERATE_HTML_EVENT(transitionstart) \
|
||||||
__ENUMERATE_HTML_EVENT(transitionend) \
|
__ENUMERATE_HTML_EVENT(transitionend) \
|
||||||
__ENUMERATE_HTML_EVENT(unhandledrejection) \
|
__ENUMERATE_HTML_EVENT(unhandledrejection) \
|
||||||
__ENUMERATE_HTML_EVENT(unload) \
|
__ENUMERATE_HTML_EVENT(unload) \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue