mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 13:43:45 +03:00
LibWeb: Generate KeyframeSet in KeyframeEffect::set_keyframes
This is similar to the logic used in StyleComputer (except a bit closer to the spec), and will eventually be shared between the two.
This commit is contained in:
parent
1735f3d9aa
commit
1d98f812af
Notes:
sideshowbarker
2024-07-16 22:54:10 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/1d98f812af Pull-request: https://github.com/SerenityOS/serenity/pull/23218
@ -543,6 +543,45 @@ static WebIDL::ExceptionOr<Vector<BaseKeyframe>> process_a_keyframes_argument(JS
|
||||
return processed_keyframes;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-animations-2/#keyframe-processing
|
||||
void KeyframeEffect::generate_initial_and_final_frames(RefPtr<KeyFrameSet> keyframe_set, HashTable<CSS::PropertyID> const& animated_properties)
|
||||
{
|
||||
// 1. Find or create the initial keyframe, a keyframe with a keyframe offset of 0%, default timing function
|
||||
// as its keyframe timing function, and default composite as its keyframe composite.
|
||||
KeyFrameSet::ResolvedKeyFrame* initial_keyframe;
|
||||
if (auto existing_keyframe = keyframe_set->keyframes_by_key.find(0)) {
|
||||
initial_keyframe = existing_keyframe;
|
||||
} else {
|
||||
keyframe_set->keyframes_by_key.insert(0, {});
|
||||
initial_keyframe = keyframe_set->keyframes_by_key.find(0);
|
||||
}
|
||||
|
||||
// 2. For any property in animated properties that is not otherwise present in a keyframe with an offset of
|
||||
// 0% or one that would be positioned earlier in the used keyframe order, add the computed value of that
|
||||
// property on element to initial keyframe’s keyframe values.
|
||||
for (auto property : animated_properties) {
|
||||
if (!initial_keyframe->resolved_properties.contains(property))
|
||||
initial_keyframe->resolved_properties.set(property, KeyFrameSet::UseInitial {});
|
||||
}
|
||||
|
||||
// 3. If initial keyframe’s keyframe values is not empty, prepend initial keyframe to keyframes.
|
||||
|
||||
// 4. Repeat for final keyframe, using an offset of 100%, considering keyframes positioned later in the used
|
||||
// keyframe order, and appending to keyframes.
|
||||
KeyFrameSet::ResolvedKeyFrame* final_keyframe;
|
||||
if (auto existing_keyframe = keyframe_set->keyframes_by_key.find(100 * AnimationKeyFrameKeyScaleFactor)) {
|
||||
final_keyframe = existing_keyframe;
|
||||
} else {
|
||||
keyframe_set->keyframes_by_key.insert(100 * AnimationKeyFrameKeyScaleFactor, {});
|
||||
final_keyframe = keyframe_set->keyframes_by_key.find(100 * AnimationKeyFrameKeyScaleFactor);
|
||||
}
|
||||
|
||||
for (auto property : animated_properties) {
|
||||
if (!final_keyframe->resolved_properties.contains(property))
|
||||
final_keyframe->resolved_properties.set(property, KeyFrameSet::UseInitial {});
|
||||
}
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<KeyframeEffect> KeyframeEffect::create(JS::Realm& realm)
|
||||
{
|
||||
return realm.heap().allocate<KeyframeEffect>(realm, realm);
|
||||
@ -737,6 +776,25 @@ WebIDL::ExceptionOr<void> KeyframeEffect::set_keyframes(Optional<JS::Handle<JS::
|
||||
// missing keyframe offsets
|
||||
compute_missing_keyframe_offsets(m_keyframes);
|
||||
|
||||
auto keyframe_set = adopt_ref(*new KeyFrameSet);
|
||||
HashTable<CSS::PropertyID> animated_properties;
|
||||
|
||||
for (auto& keyframe : m_keyframes) {
|
||||
Animations::KeyframeEffect::KeyFrameSet::ResolvedKeyFrame resolved_keyframe;
|
||||
|
||||
auto key = static_cast<u64>(keyframe.computed_offset.value() * 100 * AnimationKeyFrameKeyScaleFactor);
|
||||
|
||||
for (auto const& [property_id, property_value] : keyframe.parsed_properties()) {
|
||||
animated_properties.set(property_id);
|
||||
resolved_keyframe.resolved_properties.set(property_id, property_value);
|
||||
}
|
||||
|
||||
keyframe_set->keyframes_by_key.insert(key, resolved_keyframe);
|
||||
}
|
||||
|
||||
generate_initial_and_final_frames(keyframe_set, animated_properties);
|
||||
m_key_frame_set = keyframe_set;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,8 @@ class KeyframeEffect : public AnimationEffect {
|
||||
JS_DECLARE_ALLOCATOR(KeyframeEffect);
|
||||
|
||||
public:
|
||||
constexpr static double AnimationKeyFrameKeyScaleFactor = 1000.0; // 0..100000
|
||||
|
||||
struct KeyFrameSet : public RefCounted<KeyFrameSet> {
|
||||
struct UseInitial { };
|
||||
struct ResolvedKeyFrame {
|
||||
@ -65,6 +67,7 @@ public:
|
||||
};
|
||||
RedBlackTree<u64, ResolvedKeyFrame> keyframes_by_key;
|
||||
};
|
||||
static void generate_initial_and_final_frames(RefPtr<KeyFrameSet>, HashTable<CSS::PropertyID> const& animated_properties);
|
||||
|
||||
static JS::NonnullGCPtr<KeyframeEffect> create(JS::Realm&);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user