diff --git a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp index 01f744502c5..14772fa4406 100644 --- a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp @@ -2621,19 +2621,30 @@ RefPtr Parser::parse_easing_value(TokenStream argument_tokens { comma_separated_arguments[index] }; + return parse_number(argument_tokens); }; - if (bezier.x1 < 0.0 || bezier.x1 > 1.0 || bezier.x2 < 0.0 || bezier.x2 > 1.0) + auto x1 = parse_argument(0); + auto y1 = parse_argument(1); + auto x2 = parse_argument(2); + auto y2 = parse_argument(3); + if (!x1.has_value() || !y1.has_value() || !x2.has_value() || !y2.has_value()) return nullptr; + if (!x1->is_calculated() && (x1->value() < 0.0 || x1->value() > 1.0)) + return nullptr; + if (!x2->is_calculated() && (x2->value() < 0.0 || x2->value() > 1.0)) + return nullptr; + + EasingStyleValue::CubicBezier bezier { + x1.release_value(), + y1.release_value(), + x2.release_value(), + y2.release_value(), + }; transaction.commit(); return EasingStyleValue::create(bezier); diff --git a/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp index 7e5392b3982..cd9f5670d80 100644 --- a/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.cpp @@ -230,6 +230,11 @@ double EasingStyleValue::CubicBezier::evaluate_at(double input_progress, bool) c }; // https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo + auto resolved_x1 = clamp(x1.resolved({}).value_or(0.0), 0.0, 1.0); + auto resolved_y1 = y1.resolved({}).value_or(0.0); + auto resolved_x2 = clamp(x2.resolved({}).value_or(0.0), 0.0, 1.0); + auto resolved_y2 = y2.resolved({}).value_or(0.0); + // 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: @@ -237,13 +242,13 @@ double EasingStyleValue::CubicBezier::evaluate_at(double input_progress, bool) c 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; + if (resolved_x1 > 0.0) + return resolved_y1 / resolved_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; + if (resolved_x2 > 0.0) + return resolved_y2 / resolved_x2 * input_progress; // 3. Otherwise, let the output progress value be zero for all input progress values in the range [-∞, 0). return 0.0; @@ -252,13 +257,13 @@ double EasingStyleValue::CubicBezier::evaluate_at(double input_progress, bool) c // - 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; + if (resolved_x2 < 1.0) + return (1.0 - resolved_y2) / (1.0 - resolved_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; + if (resolved_x1 < 1.0) + return (1.0 - resolved_y1) / (1.0 - resolved_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; @@ -270,8 +275,8 @@ double EasingStyleValue::CubicBezier::evaluate_at(double input_progress, bool) c auto x = input_progress; auto solve = [&](auto t) { - auto x = cubic_bezier_at(x1, x2, t); - auto y = cubic_bezier_at(y1, y2, t); + auto x = cubic_bezier_at(resolved_x1, resolved_x2, t); + auto y = cubic_bezier_at(resolved_y1, resolved_y2, t); return CubicBezier::CachedSample { x, y, t }; }; @@ -317,7 +322,7 @@ double EasingStyleValue::CubicBezier::evaluate_at(double input_progress, bool) c } // https://drafts.csswg.org/css-easing/#bezier-serialization -String EasingStyleValue::CubicBezier::to_string(SerializationMode) const +String EasingStyleValue::CubicBezier::to_string(SerializationMode mode) const { StringBuilder builder; if (*this == CubicBezier::ease()) { @@ -329,7 +334,18 @@ String EasingStyleValue::CubicBezier::to_string(SerializationMode) const } else if (*this == CubicBezier::ease_in_out()) { builder.append("ease-in-out"sv); } else { - builder.appendff("cubic-bezier({}, {}, {}, {})", x1, y1, x2, y2); + auto x1_value = x1; + auto y1_value = y1; + auto x2_value = x2; + auto y2_value = y2; + if (mode == SerializationMode::ResolvedValue) { + x1_value = clamp(x1_value.resolved({}).value_or(0.0), 0.0, 1.0); + x2_value = clamp(x2_value.resolved({}).value_or(0.0), 0.0, 1.0); + y1_value = y1_value.resolved({}).value_or(0.0); + y2_value = y2_value.resolved({}).value_or(0.0); + } + builder.appendff("cubic-bezier({}, {}, {}, {})", + x1_value.to_string(), y1_value.to_string(), x2_value.to_string(), y2_value.to_string()); } return MUST(builder.to_string()); } diff --git a/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h index bfe360d3384..67c575cc16c 100644 --- a/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/EasingStyleValue.h @@ -47,10 +47,10 @@ public: static CubicBezier ease_out(); static CubicBezier ease_in_out(); - double x1; - double y1; - double x2; - double y2; + NumberOrCalculated x1 { 0 }; + NumberOrCalculated y1 { 0 }; + NumberOrCalculated x2 { 0 }; + NumberOrCalculated y2 { 0 }; struct CachedSample { double x; @@ -79,7 +79,7 @@ public: static Steps step_start(); static Steps step_end(); - IntegerOrCalculated number_of_intervals { 0 }; + IntegerOrCalculated number_of_intervals { 1 }; Position position { Position::End }; bool operator==(Steps const&) const = default; diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-computed.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-computed.txt index 8078d8b2590..fd9086070e5 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-computed.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-computed.txt @@ -2,8 +2,8 @@ Harness status: OK Found 21 tests -18 Pass -3 Fail +19 Pass +2 Fail Pass Property animation-timing-function value 'linear' Pass Property animation-timing-function value 'ease' Pass Property animation-timing-function value 'ease-in' @@ -12,7 +12,7 @@ Pass Property animation-timing-function value 'ease-in-out' Pass Property animation-timing-function value 'cubic-bezier(0.1, 0.2, 0.8, 0.9)' Pass Property animation-timing-function value 'cubic-bezier(0, -2, 1, 3)' Pass Property animation-timing-function value 'cubic-bezier(0, 0.7, 1, 1.3)' -Fail Property animation-timing-function value 'cubic-bezier(calc(-2), calc(0.7 / 2), calc(1.5), calc(0))' +Pass Property animation-timing-function value 'cubic-bezier(calc(-2), calc(0.7 / 2), calc(1.5), calc(0))' Pass Property animation-timing-function value 'steps(4, start)' Pass Property animation-timing-function value 'steps(2, end)' Pass Property animation-timing-function value 'steps( 2, end )' diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-valid.txt index e5a2fdef199..abd1dded796 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-easing/timing-functions-syntax-valid.txt @@ -2,8 +2,8 @@ Harness status: OK Found 22 tests -19 Pass -3 Fail +20 Pass +2 Fail Pass e.style['animation-timing-function'] = "linear" should set the property value Pass e.style['animation-timing-function'] = "ease" should set the property value Pass e.style['animation-timing-function'] = "ease-in" should set the property value @@ -12,7 +12,7 @@ Pass e.style['animation-timing-function'] = "ease-in-out" should set the propert Pass e.style['animation-timing-function'] = "cubic-bezier(0.1, 0.2, 0.8, 0.9)" should set the property value Pass e.style['animation-timing-function'] = "cubic-bezier(0, -2, 1, 3)" should set the property value Pass e.style['animation-timing-function'] = "cubic-bezier(0, 0.7, 1, 1.3)" should set the property value -Fail e.style['animation-timing-function'] = "cubic-bezier(calc(-2), calc(0.7 / 2), calc(1.5), calc(0))" should set the property value +Pass e.style['animation-timing-function'] = "cubic-bezier(calc(-2), calc(0.7 / 2), calc(1.5), calc(0))" should set the property value Fail e.style['animation-timing-function'] = "cubic-bezier(0, sibling-index(), 1, sign(2em - 20px))" should set the property value Pass e.style['animation-timing-function'] = "steps(4, start)" should set the property value Pass e.style['animation-timing-function'] = "steps(2, end)" should set the property value