diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index bb9b0a85185..53f8b796d5a 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -116,6 +116,7 @@ set(SOURCES CSS/CSSLayerBlockRule.cpp CSS/CSSLayerStatementRule.cpp CSS/CSSMarginRule.cpp + CSS/CSSMathClamp.cpp CSS/CSSMathInvert.cpp CSS/CSSMathMax.cpp CSS/CSSMathMin.cpp diff --git a/Libraries/LibWeb/CSS/CSSMathClamp.cpp b/Libraries/LibWeb/CSS/CSSMathClamp.cpp new file mode 100644 index 00000000000..58532a0771b --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathClamp.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CSSMathClamp.h" +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +GC_DEFINE_ALLOCATOR(CSSMathClamp); + +GC::Ref CSSMathClamp::create(JS::Realm& realm, NumericType type, GC::Ref lower, GC::Ref value, GC::Ref upper) +{ + return realm.create(realm, move(type), move(lower), move(value), move(upper)); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-cssmathclamp +WebIDL::ExceptionOr> CSSMathClamp::construct_impl(JS::Realm& realm, CSSNumberish lower, CSSNumberish value, CSSNumberish upper) +{ + // The CSSMathClamp(lower, value, upper) constructor must, when called, perform the following steps: + // 1. Replace lower, value, and upper with the result of rectifying a numberish value for each. + auto lower_rectified = rectify_a_numberish_value(realm, lower); + auto value_rectified = rectify_a_numberish_value(realm, value); + auto upper_rectified = rectify_a_numberish_value(realm, upper); + + // 2. Let type be the result of adding the types of lower, value, and upper. If type is failure, throw a TypeError. + auto type = lower_rectified->type() + .added_to(value_rectified->type()) + .map([&](auto& type) { return type.added_to(upper_rectified->type()); }); + if (!type.has_value()) { + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Cannot create a CSSMathClamp with values of incompatible types"sv }; + } + + // 3. Return a new CSSMathClamp whose lower, value, and upper internal slots are set to lower, value, and upper, respectively. + return CSSMathClamp::create(realm, type->release_value(), move(lower_rectified), move(value_rectified), move(upper_rectified)); +} + +CSSMathClamp::CSSMathClamp(JS::Realm& realm, NumericType type, GC::Ref lower, GC::Ref value, GC::Ref upper) + : CSSMathValue(realm, Bindings::CSSMathOperator::Clamp, move(type)) + , m_lower(move(lower)) + , m_value(move(value)) + , m_upper(move(upper)) +{ +} + +CSSMathClamp::~CSSMathClamp() = default; + +void CSSMathClamp::initialize(JS::Realm& realm) +{ + WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSMathClamp); + Base::initialize(realm); +} + +void CSSMathClamp::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_lower); + visitor.visit(m_value); + visitor.visit(m_upper); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssmathvalue +String CSSMathClamp::serialize_math_value(Nested, Parens) const +{ + // AD-HOC: The spec is missing serialization rules for CSSMathClamp: https://github.com/w3c/css-houdini-drafts/issues/1152 + StringBuilder s; + s.append("clamp("sv); + s.append(m_lower->to_string({ .nested = true, .parenless = true })); + s.append(", "sv); + s.append(m_value->to_string({ .nested = true, .parenless = true })); + s.append(", "sv); + s.append(m_upper->to_string({ .nested = true, .parenless = true })); + s.append(")"sv); + return s.to_string_without_validation(); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-lower +GC::Ref CSSMathClamp::lower() const +{ + // AD-HOC: No spec definition. + return m_lower; +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-value +GC::Ref CSSMathClamp::value() const +{ + // AD-HOC: No spec definition. + return m_value; +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmathclamp-upper +GC::Ref CSSMathClamp::upper() const +{ + // AD-HOC: No spec definition. + return m_upper; +} + +} diff --git a/Libraries/LibWeb/CSS/CSSMathClamp.h b/Libraries/LibWeb/CSS/CSSMathClamp.h new file mode 100644 index 00000000000..6826a85a96d --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathClamp.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Web::CSS { + +// https://drafts.css-houdini.org/css-typed-om-1/#cssmathclamp +class CSSMathClamp : public CSSMathValue { + WEB_PLATFORM_OBJECT(CSSMathClamp, CSSMathValue); + GC_DECLARE_ALLOCATOR(CSSMathClamp); + +public: + [[nodiscard]] static GC::Ref create(JS::Realm&, NumericType, GC::Ref lower, GC::Ref value, GC::Ref upper); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, CSSNumberish lower, CSSNumberish value, CSSNumberish upper); + + virtual ~CSSMathClamp() override; + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Visitor&) override; + + GC::Ref lower() const; + GC::Ref value() const; + GC::Ref upper() const; + + virtual String serialize_math_value(Nested, Parens) const override; + +private: + CSSMathClamp(JS::Realm&, NumericType, GC::Ref lower, GC::Ref value, GC::Ref upper); + GC::Ref m_lower; + GC::Ref m_value; + GC::Ref m_upper; +}; + +} diff --git a/Libraries/LibWeb/CSS/CSSMathClamp.idl b/Libraries/LibWeb/CSS/CSSMathClamp.idl new file mode 100644 index 00000000000..e22e155659f --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSMathClamp.idl @@ -0,0 +1,11 @@ +#import +#import + +// https://drafts.css-houdini.org/css-typed-om-1/#cssmathclamp +[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)] +interface CSSMathClamp : CSSMathValue { + constructor(CSSNumberish lower, CSSNumberish value, CSSNumberish upper); + readonly attribute CSSNumericValue lower; + readonly attribute CSSNumericValue value; + readonly attribute CSSNumericValue upper; +}; diff --git a/Libraries/LibWeb/CSS/CSSMathMin.cpp b/Libraries/LibWeb/CSS/CSSMathMin.cpp index f918a8951ad..ad9e0792b5d 100644 --- a/Libraries/LibWeb/CSS/CSSMathMin.cpp +++ b/Libraries/LibWeb/CSS/CSSMathMin.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index a6da29a1063..85a1d2ae5c4 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -242,6 +242,7 @@ class CSSKeywordValue; class CSSLayerBlockRule; class CSSLayerStatementRule; class CSSMarginRule; +class CSSMathClamp; class CSSMathInvert; class CSSMathMax; class CSSMathMin; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 8f18514dc3f..cb70c8b6ae0 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -36,6 +36,7 @@ libweb_js_bindings(CSS/CSSKeywordValue) libweb_js_bindings(CSS/CSSLayerBlockRule) libweb_js_bindings(CSS/CSSLayerStatementRule) libweb_js_bindings(CSS/CSSMarginRule) +libweb_js_bindings(CSS/CSSMathClamp) libweb_js_bindings(CSS/CSSMathInvert) libweb_js_bindings(CSS/CSSMathMax) libweb_js_bindings(CSS/CSSMathMin) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 6f01c4e33c0..d14ecf1261e 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -49,6 +49,7 @@ CSSKeywordValue CSSLayerBlockRule CSSLayerStatementRule CSSMarginRule +CSSMathClamp CSSMathInvert CSSMathMax CSSMathMin diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.txt index 6055c864758..94eb4ad1f68 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.txt @@ -1,3 +1,30 @@ -Harness status: Error +Harness status: OK -Found 0 tests +Found 25 tests + +25 Pass +Pass CSSMathMax with one argument serializes correctly +Pass CSSMathMax with more than one argument serializes correctly +Pass CSSMathMax with pixel arguments serializes correctly +Pass CSSMathMax containing nested CSSMathValues serializes correctly +Pass CSSMathMin with one argument serializes correctly +Pass CSSMathMin with more than one argument serializes correctly +Pass CSSMathMin with pixel arguments serializes correctly +Pass CSSMathMin containing nested CSSMathValues serializes correctly +Pass CSSMathClamp with lower, value and upper arguments serializes correctly +Pass CSSMathClamp with pixel arguments serializes correctly +Pass CSSMathClamp containing nested CSSMathValues serializes correctly +Pass CSSMathSum with one argument serializes correctly +Pass CSSMathSum with more than one argument serializes correctly +Pass CSSMathSum with a CSSMathNegate as first value serializes correctly +Pass CSSMathSum containing a CSSMathNegate after first value serializes correctly +Pass CSSMathSum nested inside a CSSMathValue serializes correctly +Pass CSSMathNegate serializes correctly +Pass CSSMathNegate nested inside a CSSMathValue serializes correctly +Pass CSSMathProduct with one argument serializes correctly +Pass CSSMathProduct with more than one argument serializes correctly +Pass CSSMathProduct with a CSSMathInvert as first value serializes correctly +Pass CSSMathProduct containing a CSSMathInvert after first value serializes correctly +Pass CSSMathProduct nested inside a CSSMathValue serializes correctly +Pass CSSMathInvert serializes correctly +Pass CSSMathInvert nested inside a CSSMathValue serializes correctly \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.txt index adf14f44720..81ae994e2c4 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.txt @@ -1,8 +1,8 @@ -Harness status: Error +Harness status: OK -Found 20 tests +Found 23 tests -20 Pass +23 Pass Pass Constructing a CSSMathSum with no arguments throws a SyntaxError Pass CSSMathSum can be constructed from a single number CSSUnitValue Pass CSSMathSum can be constructed from more than one number CSSUnitValue @@ -22,4 +22,7 @@ Pass CSSMathMax.operator is readonly Pass CSSMathNegate can be constructed from a single numberish value Pass CSSMathNegate.operator is readonly Pass CSSMathInvert can be constructed from a single numberish value -Pass CSSMathInvert.operator is readonly \ No newline at end of file +Pass CSSMathInvert.operator is readonly +Pass Constructing a CSSMathClamp with less than 3 arguments throws a SyntaxError +Pass Constructing a CSSMathClamp with different unit arguments throws a SyntaxError +Pass CSSMathClamp.operator is readonly \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.txt index 7e47d3adbde..cf8e639b7e6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.txt @@ -2,8 +2,8 @@ Harness status: OK Found 17 tests -5 Pass -12 Fail +6 Pass +11 Fail Fail Converting a CSSUnitValue to an invalid unit throws SyntaxError Pass Converting a CSSNumericValue with invalid sum value throws TypeError Pass Converting a CSSNumericValue with sum value containing more than one value throws TypeError @@ -17,7 +17,7 @@ Pass Converting a CSSMathMin to a single unit with different units throws a Type Fail Converting a CSSMathMax to a single unit finds the max value Pass Converting a CSSMathMax to a single unit with different units throws a TypeError Fail Converting a CSSMathClamp to a single unit returns the clamped value -Fail Converting a CSSMathClamp to a single unit with different units throws a TypeError +Pass Converting a CSSMathClamp to a single unit with different units throws a TypeError Fail Converting a CSSMathNegate to a single unit negates its value Fail Converting a CSSMathInvert to a single unit inverts its value and units Fail Converting a complex expression to a single unit \ No newline at end of file