From 5e4e39d84a77b07aac6c9891e6802b20c1e548c7 Mon Sep 17 00:00:00 2001 From: Matthew Olsson Date: Fri, 14 Jun 2024 21:50:25 -0700 Subject: [PATCH] LibWeb: Remove TimingFunction in favor of EasingStyleValue::Function Now that EasingStyleValue is a lot nicer to use, there isn't much reason to keep TimingFunction around. (cherry picked from commit 7950992fc21e2428a7f32954bbe893a2b2d58cf7, manually amended with the output of `git clang-format master`) --- .../Libraries/LibWeb/Animations/BUILD.gn | 2 - .../LibWeb/Animations/AnimationEffect.cpp | 13 +- .../LibWeb/Animations/AnimationEffect.h | 14 +- .../LibWeb/Animations/KeyframeEffect.cpp | 1 - .../LibWeb/Animations/TimingFunction.cpp | 212 ------------------ .../LibWeb/Animations/TimingFunction.h | 59 ----- Userland/Libraries/LibWeb/CMakeLists.txt | 1 - Userland/Libraries/LibWeb/CSS/CSSTransition.h | 1 - .../Libraries/LibWeb/CSS/StyleComputer.cpp | 6 +- .../CSS/StyleValues/EasingStyleValue.cpp | 160 ++++++++++++- .../LibWeb/CSS/StyleValues/EasingStyleValue.h | 20 +- 11 files changed, 187 insertions(+), 302 deletions(-) delete mode 100644 Userland/Libraries/LibWeb/Animations/TimingFunction.cpp delete mode 100644 Userland/Libraries/LibWeb/Animations/TimingFunction.h diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/Animations/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/Animations/BUILD.gn index 2016247801..4a65024255 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/Animations/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/Animations/BUILD.gn @@ -16,7 +16,5 @@ source_set("Animations") { "DocumentTimeline.h", "KeyframeEffect.cpp", "KeyframeEffect.h", - "TimingFunction.cpp", - "TimingFunction.h", ] } diff --git a/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp b/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp index 95caa369b0..83ed5a65fb 100644 --- a/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/AnimationEffect.cpp @@ -76,7 +76,7 @@ EffectTiming AnimationEffect::get_timing() const .iterations = m_iteration_count, .duration = m_iteration_duration, .direction = m_playback_direction, - .easing = m_easing_function, + .easing = m_timing_function.to_string(), }; } @@ -111,7 +111,7 @@ ComputedEffectTiming AnimationEffect::get_computed_timing() const .iterations = m_iteration_count, .duration = duration, .direction = m_playback_direction, - .easing = m_easing_function, + .easing = m_timing_function.to_string(), }, end_time(), @@ -159,6 +159,7 @@ WebIDL::ExceptionOr AnimationEffect::update_timing(OptionalEffectTiming ti easing_value = parse_easing_string(realm(), timing.easing.value()); if (!easing_value) return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid easing function"sv }; + VERIFY(easing_value->is_easing()); } // 5. Assign each member that exists in input to the corresponding timing property of effect as follows: @@ -192,10 +193,8 @@ WebIDL::ExceptionOr AnimationEffect::update_timing(OptionalEffectTiming ti m_playback_direction = timing.direction.value(); // - easing → timing function - if (easing_value) { - m_easing_function = timing.easing.value(); - m_timing_function = TimingFunction::from_easing_style_value(easing_value->as_easing()); - } + if (easing_value) + m_timing_function = easing_value->as_easing().function(); if (auto animation = m_associated_animation) animation->effect_timing_changed({}); @@ -590,7 +589,7 @@ Optional AnimationEffect::transformed_progress() const // 3. Return the result of evaluating the animation effect’s timing function passing directed progress as the input progress value and // before flag as the before flag. - return m_timing_function(directed_progress.value(), before_flag); + return m_timing_function.evaluate_at(directed_progress.value(), before_flag); } RefPtr AnimationEffect::parse_easing_string(JS::Realm& realm, StringView value) diff --git a/Userland/Libraries/LibWeb/Animations/AnimationEffect.h b/Userland/Libraries/LibWeb/Animations/AnimationEffect.h index b070ea3624..ff370a3111 100644 --- a/Userland/Libraries/LibWeb/Animations/AnimationEffect.h +++ b/Userland/Libraries/LibWeb/Animations/AnimationEffect.h @@ -9,10 +9,10 @@ #include #include #include -#include #include #include #include +#include namespace Web::Animations { @@ -92,11 +92,8 @@ public: Bindings::PlaybackDirection playback_direction() const { return m_playback_direction; } void set_playback_direction(Bindings::PlaybackDirection playback_direction) { m_playback_direction = playback_direction; } - String const& easing_function() const { return m_easing_function; } - void set_easing_function(String easing_function) { m_easing_function = move(easing_function); } - - TimingFunction const& timing_function() { return m_timing_function; } - void set_timing_function(TimingFunction value) { m_timing_function = move(value); } + CSS::EasingStyleValue::Function const& timing_function() { return m_timing_function; } + void set_timing_function(CSS::EasingStyleValue::Function value) { m_timing_function = move(value); } JS::GCPtr associated_animation() const { return m_associated_animation; } void set_associated_animation(JS::GCPtr value); @@ -177,14 +174,11 @@ protected: // https://www.w3.org/TR/web-animations-1/#playback-direction Bindings::PlaybackDirection m_playback_direction { Bindings::PlaybackDirection::Normal }; - // https://www.w3.org/TR/css-easing-1/#easing-function - String m_easing_function { "linear"_string }; - // https://www.w3.org/TR/web-animations-1/#animation-associated-effect JS::GCPtr m_associated_animation {}; // https://www.w3.org/TR/web-animations-1/#time-transformations - TimingFunction m_timing_function { LinearTimingFunction {} }; + CSS::EasingStyleValue::Function m_timing_function { CSS::EasingStyleValue::Linear {} }; // Used for calculating transitions in StyleComputer Phase m_previous_phase { Phase::Idle }; diff --git a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp index e94747ed73..644834f310 100644 --- a/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Userland/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -762,7 +762,6 @@ WebIDL::ExceptionOr> KeyframeEffect::construct_ effect->m_playback_direction = source->m_playback_direction; // - timing function. - effect->m_easing_function = source->m_easing_function; effect->m_timing_function = source->m_timing_function; return effect; diff --git a/Userland/Libraries/LibWeb/Animations/TimingFunction.cpp b/Userland/Libraries/LibWeb/Animations/TimingFunction.cpp deleted file mode 100644 index 6ce08b3515..0000000000 --- a/Userland/Libraries/LibWeb/Animations/TimingFunction.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2023, Ali Mohammad Pur - * Copyright (c) 2023, Matthew Olsson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace Web::Animations { - -// https://www.w3.org/TR/css-easing-1/#linear-easing-function -double LinearTimingFunction::operator()(double input_progress, bool) const -{ - return input_progress; -} - -static double cubic_bezier_at(double x1, double x2, double t) -{ - auto a = 1.0 - 3.0 * x2 + 3.0 * x1; - auto b = 3.0 * x2 - 6.0 * x1; - auto c = 3.0 * x1; - - auto t2 = t * t; - auto t3 = t2 * t; - - return (a * t3) + (b * t2) + (c * t); -} - -// https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo -double CubicBezierTimingFunction::operator()(double input_progress, bool) const -{ - // For input progress values outside the range [0, 1], the curve is extended infinitely using tangent of the curve - // at the closest endpoint as follows: - - // - For input progress values less than zero, - if (input_progress < 0.0) { - // 1. If the x value of P1 is greater than zero, use a straight line that passes through P1 and P0 as the - // tangent. - if (x1 > 0.0) - return y1 / x1 * input_progress; - - // 2. Otherwise, if the x value of P2 is greater than zero, use a straight line that passes through P2 and P0 as - // the tangent. - if (x2 > 0.0) - return y2 / x2 * input_progress; - - // 3. Otherwise, let the output progress value be zero for all input progress values in the range [-∞, 0). - return 0.0; - } - - // - For input progress values greater than one, - if (input_progress > 1.0) { - // 1. If the x value of P2 is less than one, use a straight line that passes through P2 and P3 as the tangent. - if (x2 < 1.0) - return (1.0 - y2) / (1.0 - x2) * (input_progress - 1.0) + 1.0; - - // 2. Otherwise, if the x value of P1 is less than one, use a straight line that passes through P1 and P3 as the - // tangent. - if (x1 < 1.0) - return (1.0 - y1) / (1.0 - x1) * (input_progress - 1.0) + 1.0; - - // 3. Otherwise, let the output progress value be one for all input progress values in the range (1, ∞]. - return 1.0; - } - - // Note: The spec does not specify the precise algorithm for calculating values in the range [0, 1]: - // "The evaluation of this curve is covered in many sources such as [FUND-COMP-GRAPHICS]." - - auto x = input_progress; - - auto solve = [&](auto t) { - auto x = cubic_bezier_at(x1, x2, t); - auto y = cubic_bezier_at(y1, y2, t); - return CachedSample { x, y, t }; - }; - - if (m_cached_x_samples.is_empty()) - m_cached_x_samples.append(solve(0.)); - - size_t nearby_index = 0; - if (auto found = binary_search(m_cached_x_samples, x, &nearby_index, [](auto x, auto& sample) { - if (x > sample.x) - return 1; - if (x < sample.x) - return -1; - return 0; - })) - return found->y; - - if (nearby_index == m_cached_x_samples.size() || nearby_index + 1 == m_cached_x_samples.size()) { - // Produce more samples until we have enough. - auto last_t = m_cached_x_samples.last().t; - auto last_x = m_cached_x_samples.last().x; - while (last_x <= x && last_t < 1.0) { - last_t += 1. / 60.; - auto solution = solve(last_t); - m_cached_x_samples.append(solution); - last_x = solution.x; - } - - if (auto found = binary_search(m_cached_x_samples, x, &nearby_index, [](auto x, auto& sample) { - if (x > sample.x) - return 1; - if (x < sample.x) - return -1; - return 0; - })) - return found->y; - } - - // We have two samples on either side of the x value we want, so we can linearly interpolate between them. - auto& sample1 = m_cached_x_samples[nearby_index]; - auto& sample2 = m_cached_x_samples[nearby_index + 1]; - auto factor = (x - sample1.x) / (sample2.x - sample1.x); - return sample1.y + factor * (sample2.y - sample1.y); -} - -// https://www.w3.org/TR/css-easing-1/#step-easing-algo -double StepsTimingFunction::operator()(double input_progress, bool before_flag) const -{ - // 1. Calculate the current step as floor(input progress value × steps). - auto current_step = floor(input_progress * number_of_steps); - - // 2. If the step position property is one of: - // - jump-start, - // - jump-both, - // increment current step by one. - if (jump_at_start) - current_step += 1; - - // 3. If both of the following conditions are true: - // - the before flag is set, and - // - input progress value × steps mod 1 equals zero (that is, if input progress value × steps is integral), then - // decrement current step by one. - auto step_progress = input_progress * number_of_steps; - if (before_flag && trunc(step_progress) == step_progress) - current_step -= 1; - - // 4. If input progress value ≥ 0 and current step < 0, let current step be zero. - if (input_progress >= 0.0 && current_step < 0.0) - current_step = 0.0; - - // 5. Calculate jumps based on the step position as follows: - - // jump-start or jump-end -> steps - // jump-none -> steps - 1 - // jump-both -> steps + 1 - double jumps; - if (jump_at_start ^ jump_at_end) - jumps = number_of_steps; - else if (jump_at_start && jump_at_end) - jumps = number_of_steps + 1; - else - jumps = number_of_steps - 1; - - // 6. If input progress value ≤ 1 and current step > jumps, let current step be jumps. - if (input_progress <= 1.0 && current_step > jumps) - current_step = jumps; - - // 7. The output progress value is current step / jumps. - return current_step / jumps; -} - -TimingFunction TimingFunction::from_easing_style_value(CSS::EasingStyleValue const& easing_value) -{ - return easing_value.function().visit( - [](CSS::EasingStyleValue::Linear const& linear) { - if (!linear.stops.is_empty()) { - dbgln("FIXME: Handle linear easing functions with stops"); - } - return TimingFunction { LinearTimingFunction {} }; - }, - [](CSS::EasingStyleValue::CubicBezier const& bezier) { - return TimingFunction { CubicBezierTimingFunction { bezier.x1, bezier.y1, bezier.x2, bezier.y2 } }; - }, - [](CSS::EasingStyleValue::Steps const& steps) { - auto jump_at_start = false; - auto jump_at_end = false; - - switch (steps.position) { - case CSS::EasingStyleValue::Steps::Position::Start: - case CSS::EasingStyleValue::Steps::Position::JumpStart: - jump_at_start = true; - break; - case CSS::EasingStyleValue::Steps::Position::End: - case CSS::EasingStyleValue::Steps::Position::JumpEnd: - jump_at_end = true; - break; - case CSS::EasingStyleValue::Steps::Position::JumpBoth: - jump_at_start = true; - jump_at_end = true; - break; - case CSS::EasingStyleValue::Steps::Position::JumpNone: - break; - } - - return TimingFunction { StepsTimingFunction { steps.number_of_intervals, jump_at_start, jump_at_end } }; - }); -} - -double TimingFunction::operator()(double input_progress, bool before_flag) const -{ - return function.visit([&](auto const& f) { return f(input_progress, before_flag); }); -} - -} diff --git a/Userland/Libraries/LibWeb/Animations/TimingFunction.h b/Userland/Libraries/LibWeb/Animations/TimingFunction.h deleted file mode 100644 index 69e956f1ef..0000000000 --- a/Userland/Libraries/LibWeb/Animations/TimingFunction.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023, Ali Mohammad Pur - * Copyright (c) 2023, Matthew Olsson - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Web::CSS { -class EasingStyleValue; -} - -namespace Web::Animations { - -// https://www.w3.org/TR/css-easing-1/#the-linear-easing-function -struct LinearTimingFunction { - double operator()(double t, bool) const; -}; - -// https://www.w3.org/TR/css-easing-1/#cubic-bezier-easing-functions -struct CubicBezierTimingFunction { - double x1; - double y1; - double x2; - double y2; - - struct CachedSample { - double x; - double y; - double t; - }; - - mutable Vector m_cached_x_samples = {}; - - double operator()(double input_progress, bool) const; -}; - -// https://www.w3.org/TR/css-easing-1/#step-easing-functions -struct StepsTimingFunction { - size_t number_of_steps; - bool jump_at_start; - bool jump_at_end; - - double operator()(double input_progress, bool before_flag) const; -}; - -struct TimingFunction { - static TimingFunction from_easing_style_value(CSS::EasingStyleValue const&); - - Variant function; - - double operator()(double input_progress, bool before_flag) const; -}; - -} diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 6ce55ad22a..ce5d8b535a 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -9,7 +9,6 @@ set(SOURCES Animations/AnimationTimeline.cpp Animations/DocumentTimeline.cpp Animations/KeyframeEffect.cpp - Animations/TimingFunction.cpp ARIA/AriaData.cpp ARIA/ARIAMixin.cpp ARIA/Roles.cpp diff --git a/Userland/Libraries/LibWeb/CSS/CSSTransition.h b/Userland/Libraries/LibWeb/CSS/CSSTransition.h index 1871b44f62..4e82319cf2 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSTransition.h +++ b/Userland/Libraries/LibWeb/CSS/CSSTransition.h @@ -7,7 +7,6 @@ #pragma once #include -#include #include #include #include diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index de92b0041a..83930427ef 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -1557,10 +1556,9 @@ static void apply_animation_properties(DOM::Document& document, StyleProperties& play_state = *play_state_value; } - static Animations::TimingFunction ease_timing_function = Animations::TimingFunction::from_easing_style_value(*CSS::EasingStyleValue::create(CSS::EasingStyleValue::CubicBezier::ease())); - Animations::TimingFunction timing_function = ease_timing_function; + CSS::EasingStyleValue::Function timing_function { CSS::EasingStyleValue::CubicBezier::ease() }; if (auto timing_property = style.maybe_null_property(PropertyID::AnimationTimingFunction); timing_property && timing_property->is_easing()) - timing_function = Animations::TimingFunction::from_easing_style_value(timing_property->as_easing()); + timing_function = timing_property->as_easing().function(); auto iteration_duration = duration.has_value() ? Variant { duration.release_value().to_milliseconds() } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp index 3ddf1bfe35..5dceeafcfd 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp @@ -9,6 +9,7 @@ */ #include "EasingStyleValue.h" +#include #include namespace Web::CSS { @@ -51,10 +52,165 @@ EasingStyleValue::Steps EasingStyleValue::Steps::step_end() return steps; } -String EasingStyleValue::to_string() const +bool EasingStyleValue::CubicBezier::operator==(Web::CSS::EasingStyleValue::CubicBezier const& other) const +{ + return x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2; +} + +double EasingStyleValue::Function::evaluate_at(double input_progress, bool before_flag) const +{ + constexpr static auto cubic_bezier_at = [](double x1, double x2, double t) { + auto a = 1.0 - 3.0 * x2 + 3.0 * x1; + auto b = 3.0 * x2 - 6.0 * x1; + auto c = 3.0 * x1; + + auto t2 = t * t; + auto t3 = t2 * t; + + return (a * t3) + (b * t2) + (c * t); + }; + + return visit( + [&](Linear const&) { return input_progress; }, + [&](CubicBezier const& bezier) { + auto const& [x1, y1, x2, y2, cached_x_samples] = bezier; + + // https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo + // For input progress values outside the range [0, 1], the curve is extended infinitely using tangent of the curve + // at the closest endpoint as follows: + + // - For input progress values less than zero, + if (input_progress < 0.0) { + // 1. If the x value of P1 is greater than zero, use a straight line that passes through P1 and P0 as the + // tangent. + if (x1 > 0.0) + return y1 / x1 * input_progress; + + // 2. Otherwise, if the x value of P2 is greater than zero, use a straight line that passes through P2 and P0 as + // the tangent. + if (x2 > 0.0) + return y2 / x2 * input_progress; + + // 3. Otherwise, let the output progress value be zero for all input progress values in the range [-∞, 0). + return 0.0; + } + + // - For input progress values greater than one, + if (input_progress > 1.0) { + // 1. If the x value of P2 is less than one, use a straight line that passes through P2 and P3 as the tangent. + if (x2 < 1.0) + return (1.0 - y2) / (1.0 - x2) * (input_progress - 1.0) + 1.0; + + // 2. Otherwise, if the x value of P1 is less than one, use a straight line that passes through P1 and P3 as the + // tangent. + if (x1 < 1.0) + return (1.0 - y1) / (1.0 - x1) * (input_progress - 1.0) + 1.0; + + // 3. Otherwise, let the output progress value be one for all input progress values in the range (1, ∞]. + return 1.0; + } + + // Note: The spec does not specify the precise algorithm for calculating values in the range [0, 1]: + // "The evaluation of this curve is covered in many sources such as [FUND-COMP-GRAPHICS]." + + auto x = input_progress; + + auto solve = [&](auto t) { + auto x = cubic_bezier_at(x1, x2, t); + auto y = cubic_bezier_at(y1, y2, t); + return CubicBezier::CachedSample { x, y, t }; + }; + + if (cached_x_samples.is_empty()) + cached_x_samples.append(solve(0.)); + + size_t nearby_index = 0; + if (auto found = binary_search(cached_x_samples, x, &nearby_index, [](auto x, auto& sample) { + if (x > sample.x) + return 1; + if (x < sample.x) + return -1; + return 0; + })) + return found->y; + + if (nearby_index == cached_x_samples.size() || nearby_index + 1 == cached_x_samples.size()) { + // Produce more samples until we have enough. + auto last_t = cached_x_samples.last().t; + auto last_x = cached_x_samples.last().x; + while (last_x <= x && last_t < 1.0) { + last_t += 1. / 60.; + auto solution = solve(last_t); + cached_x_samples.append(solution); + last_x = solution.x; + } + + if (auto found = binary_search(cached_x_samples, x, &nearby_index, [](auto x, auto& sample) { + if (x > sample.x) + return 1; + if (x < sample.x) + return -1; + return 0; + })) + return found->y; + } + + // We have two samples on either side of the x value we want, so we can linearly interpolate between them. + auto& sample1 = cached_x_samples[nearby_index]; + auto& sample2 = cached_x_samples[nearby_index + 1]; + auto factor = (x - sample1.x) / (sample2.x - sample1.x); + return sample1.y + factor * (sample2.y - sample1.y); + }, + [&](Steps const& steps) { + // https://www.w3.org/TR/css-easing-1/#step-easing-algo + // 1. Calculate the current step as floor(input progress value × steps). + auto [number_of_steps, position] = steps; + auto current_step = floor(input_progress * number_of_steps); + + // 2. If the step position property is one of: + // - jump-start, + // - jump-both, + // increment current step by one. + if (position == Steps::Position::JumpStart || position == Steps::Position::JumpBoth) + current_step += 1; + + // 3. If both of the following conditions are true: + // - the before flag is set, and + // - input progress value × steps mod 1 equals zero (that is, if input progress value × steps is integral), then + // decrement current step by one. + auto step_progress = input_progress * number_of_steps; + if (before_flag && trunc(step_progress) == step_progress) + current_step -= 1; + + // 4. If input progress value ≥ 0 and current step < 0, let current step be zero. + if (input_progress >= 0.0 && current_step < 0.0) + current_step = 0.0; + + // 5. Calculate jumps based on the step position as follows: + + // jump-start or jump-end -> steps + // jump-none -> steps - 1 + // jump-both -> steps + 1 + auto jumps = steps.number_of_intervals; + if (position == Steps::Position::JumpNone) { + jumps--; + } else if (position == Steps::Position::JumpBoth) { + jumps++; + } + + // 6. If input progress value ≤ 1 and current step > jumps, let current step be jumps. + if (input_progress <= 1.0 && current_step > jumps) + current_step = jumps; + + // 7. The output progress value is current step / jumps. + return current_step / jumps; + }); +} + +String EasingStyleValue::Function::to_string() const { StringBuilder builder; - m_function.visit( + visit( [&](Linear const& linear) { builder.append("linear"sv); if (!linear.stops.is_empty()) { diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h index 81ec6442c4..526e7136a7 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h @@ -40,7 +40,15 @@ public: double x2; double y2; - bool operator==(CubicBezier const&) const = default; + struct CachedSample { + double x; + double y; + double t; + }; + + mutable Vector m_cached_x_samples {}; + + bool operator==(CubicBezier const&) const; }; struct Steps { @@ -62,7 +70,13 @@ public: bool operator==(Steps const&) const = default; }; - using Function = Variant; + struct Function : public Variant { + using Variant::Variant; + + double evaluate_at(double input_progress, bool before_flag) const; + + String to_string() const; + }; static ValueComparingNonnullRefPtr create(Function const& function) { @@ -72,7 +86,7 @@ public: Function const& function() const { return m_function; } - virtual String to_string() const override; + virtual String to_string() const override { return m_function.to_string(); } bool properties_equal(EasingStyleValue const& other) const { return m_function == other.m_function; }