From b0cc1c64062055a611263fa83e723072f43bb4ba Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 15 Sep 2025 15:18:55 +0100 Subject: [PATCH] LibWeb/CSS: Implement CSSSkewX Equivalent to the skewX() transform function. +27 WPT subtests. --- Libraries/LibWeb/CMakeLists.txt | 1 + Libraries/LibWeb/CSS/CSSSkewX.cpp | 109 ++++++++++++++++++ Libraries/LibWeb/CSS/CSSSkewX.h | 42 +++++++ Libraries/LibWeb/CSS/CSSSkewX.idl | 9 ++ Libraries/LibWeb/Forward.h | 1 + Libraries/LibWeb/idl_files.cmake | 1 + .../Text/expected/all-window-properties.txt | 1 + .../css/css-typed-om/idlharness.txt | 18 +-- .../cssSkewX.tentative.txt | 40 +++---- .../cssTransformComponent-toMatrix.txt | 6 +- 10 files changed, 196 insertions(+), 32 deletions(-) create mode 100644 Libraries/LibWeb/CSS/CSSSkewX.cpp create mode 100644 Libraries/LibWeb/CSS/CSSSkewX.h create mode 100644 Libraries/LibWeb/CSS/CSSSkewX.idl diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 130a45e2149..a4821e84a6d 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -139,6 +139,7 @@ set(SOURCES CSS/CSSRuleList.cpp CSS/CSSScale.cpp CSS/CSSSkew.cpp + CSS/CSSSkewX.cpp CSS/CSSStyleDeclaration.cpp CSS/CSSStyleProperties.cpp CSS/CSSStyleRule.cpp diff --git a/Libraries/LibWeb/CSS/CSSSkewX.cpp b/Libraries/LibWeb/CSS/CSSSkewX.cpp new file mode 100644 index 00000000000..86599142d7c --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSSkewX.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "CSSSkewX.h" +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +GC_DEFINE_ALLOCATOR(CSSSkewX); + +GC::Ref CSSSkewX::create(JS::Realm& realm, GC::Ref ax) +{ + return realm.create(realm, ax); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssskewx-cssskewx +WebIDL::ExceptionOr> CSSSkewX::construct_impl(JS::Realm& realm, GC::Ref ax) +{ + // The CSSSkewX(ax) constructor must, when invoked, perform the following steps: + + // 1. If ax does not match , throw a TypeError. + if (!ax->type().matches_angle({})) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSSkewX ax component doesn't match "sv }; + + // 2. Return a new CSSSkewX object with its ax internal slot set to ax, and its is2D internal slot set to true. + return CSSSkewX::create(realm, ax); +} + +CSSSkewX::CSSSkewX(JS::Realm& realm, GC::Ref ax) + : CSSTransformComponent(realm, Is2D::Yes) + , m_ax(ax) +{ +} + +CSSSkewX::~CSSSkewX() = default; + +void CSSSkewX::initialize(JS::Realm& realm) +{ + WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSSkewX); + Base::initialize(realm); +} + +void CSSSkewX::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_ax); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssskewx +WebIDL::ExceptionOr CSSSkewX::to_string() const +{ + // 1. Let s initially be "skewX(". + StringBuilder builder { StringBuilder::Mode::UTF16 }; + builder.append("skewX("sv); + + // 2. Serialize this’s ax internal slot, and append it to s. + builder.append(m_ax->to_string()); + + // 3. Append ")" to s, and return s. + builder.append(")"sv); + return builder.to_utf16_string(); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix +WebIDL::ExceptionOr> CSSSkewX::to_matrix() const +{ + // 1. Let matrix be a new DOMMatrix object, initialized to this’s equivalent 4x4 transform matrix, as defined in + // CSS Transforms 1 § 12. Mathematical Description of Transform Functions, and with its is2D internal slot set + // to the same value as this’s is2D internal slot. + // NOTE: Recall that the is2D flag affects what transform, and thus what equivalent matrix, a + // CSSTransformComponent represents. + // As the entries of such a matrix are defined relative to the px unit, if any s in this involved in + // generating the matrix are not compatible units with px (such as relative lengths or percentages), throw a + // TypeError. + auto matrix = Geometry::DOMMatrix::create(realm()); + + // NB: to() throws a TypeError if the conversion can't be done. + auto ax_rad = TRY(m_ax->to("rad"_fly_string))->value(); + matrix->set_m21(tanf(ax_rad)); + + // 2. Return matrix. + return matrix; +} + +WebIDL::ExceptionOr CSSSkewX::set_ax(GC::Ref ax) +{ + // AD-HOC: Not specced. https://github.com/w3c/css-houdini-drafts/issues/1153 + // WPT expects this to throw for invalid values. + if (!ax->type().matches_angle({})) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSSkewX ax component doesn't match "sv }; + m_ax = ax; + return {}; +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssskew-is2d +void CSSSkewX::set_is_2d(bool) +{ + // The is2D attribute of a CSSSkewX, CSSSkewXX, or CSSSkewXY object must, on setting, do nothing. +} + +} diff --git a/Libraries/LibWeb/CSS/CSSSkewX.h b/Libraries/LibWeb/CSS/CSSSkewX.h new file mode 100644 index 00000000000..23c677400b2 --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSSkewX.h @@ -0,0 +1,42 @@ +/* + * 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/#cssskewx +class CSSSkewX final : public CSSTransformComponent { + WEB_PLATFORM_OBJECT(CSSSkewX, CSSTransformComponent); + GC_DECLARE_ALLOCATOR(CSSSkewX); + +public: + [[nodiscard]] static GC::Ref create(JS::Realm&, GC::Ref ax); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, GC::Ref ax); + + virtual ~CSSSkewX() override; + + virtual WebIDL::ExceptionOr to_string() const override; + + virtual WebIDL::ExceptionOr> to_matrix() const override; + + GC::Ref ax() const { return m_ax; } + WebIDL::ExceptionOr set_ax(GC::Ref value); + + virtual void set_is_2d(bool value) override; + +private: + explicit CSSSkewX(JS::Realm&, GC::Ref ax); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Visitor&) override; + + GC::Ref m_ax; +}; + +} diff --git a/Libraries/LibWeb/CSS/CSSSkewX.idl b/Libraries/LibWeb/CSS/CSSSkewX.idl new file mode 100644 index 00000000000..4cdec76ff8b --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSSkewX.idl @@ -0,0 +1,9 @@ +#import +#import + +// https://drafts.css-houdini.org/css-typed-om-1/#cssskewx +[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)] +interface CSSSkewX : CSSTransformComponent { + constructor(CSSNumericValue ax); + attribute CSSNumericValue ax; +}; diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index aa12159216c..1a369ae9e49 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -264,6 +264,7 @@ class CSSRule; class CSSRuleList; class CSSScale; class CSSSkew; +class CSSSkewX; class CSSStyleDeclaration; class CSSStyleProperties; class CSSStyleRule; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index b3e6894aa0a..d91c72f2263 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -59,6 +59,7 @@ libweb_js_bindings(CSS/CSSRule) libweb_js_bindings(CSS/CSSRuleList) libweb_js_bindings(CSS/CSSScale) libweb_js_bindings(CSS/CSSSkew) +libweb_js_bindings(CSS/CSSSkewX) libweb_js_bindings(CSS/CSSStyleDeclaration) libweb_js_bindings(CSS/CSSStyleProperties) libweb_js_bindings(CSS/CSSStyleRule) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 8134c6f481d..0c7f50a4bde 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -71,6 +71,7 @@ CSSRule CSSRuleList CSSScale CSSSkew +CSSSkewX CSSStyleDeclaration CSSStyleProperties CSSStyleRule diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/idlharness.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/idlharness.txt index e00a983cb3f..708dd33592f 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/idlharness.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/idlharness.txt @@ -2,8 +2,8 @@ Harness status: OK Found 545 tests -332 Pass -213 Fail +339 Pass +206 Fail Pass idl_test setup Pass idl_test validation Pass Partial interface Element: original interface defined @@ -340,13 +340,13 @@ Fail CSSSkew interface: skew must inherit property "ax" with the proper type Fail CSSSkew interface: skew must inherit property "ay" with the proper type Fail CSSTransformComponent interface: skew must inherit property "is2D" with the proper type Fail CSSTransformComponent interface: skew must inherit property "toMatrix()" with the proper type -Fail CSSSkewX interface: existence and properties of interface object -Fail CSSSkewX interface object length -Fail CSSSkewX interface object name -Fail CSSSkewX interface: existence and properties of interface prototype object -Fail CSSSkewX interface: existence and properties of interface prototype object's "constructor" property -Fail CSSSkewX interface: existence and properties of interface prototype object's @@unscopables property -Fail CSSSkewX interface: attribute ax +Pass CSSSkewX interface: existence and properties of interface object +Pass CSSSkewX interface object length +Pass CSSSkewX interface object name +Pass CSSSkewX interface: existence and properties of interface prototype object +Pass CSSSkewX interface: existence and properties of interface prototype object's "constructor" property +Pass CSSSkewX interface: existence and properties of interface prototype object's @@unscopables property +Pass CSSSkewX interface: attribute ax Fail CSSSkewX must be primary interface of skewX Fail Stringification of skewX Fail CSSSkewX interface: skewX must inherit property "ax" with the proper type diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.txt index cd0725102ae..c823fe483df 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.txt @@ -2,23 +2,23 @@ Harness status: OK Found 19 tests -19 Fail -Fail Constructing a CSSSkewX with a keyword throws a TypeError -Fail Constructing a CSSSkewX with a double throws a TypeError -Fail Constructing a CSSSkewX with a unitless zero throws a TypeError -Fail Constructing a CSSSkewX with a string angle throws a TypeError -Fail Constructing a CSSSkewX with a number CSSUnitValue throws a TypeError -Fail Constructing a CSSSkewX with a time dimension CSSUnitValue throws a TypeError -Fail Constructing a CSSSkewX with a CSSMathValue of length type throws a TypeError -Fail Updating CSSSkewX.ax with a keyword throws a TypeError -Fail Updating CSSSkewX.ax with a double throws a TypeError -Fail Updating CSSSkewX.ax with a unitless zero throws a TypeError -Fail Updating CSSSkewX.ax with a string angle throws a TypeError -Fail Updating CSSSkewX.ax with a number CSSUnitValue throws a TypeError -Fail Updating CSSSkewX.ax with a time dimension CSSUnitValue throws a TypeError -Fail Updating CSSSkewX.ax with a CSSMathValue of length type throws a TypeError -Fail CSSSkewX can be constructed from an angle CSSUnitValue -Fail CSSSkewX can be constructed from a CSSMathValue of angle type -Fail CSSSkew.ax can be updated to an angle CSSUnitValue -Fail CSSSkew.ax can be updated to a CSSMathValue of angle type -Fail Modifying skewX.is2D is a no-op \ No newline at end of file +19 Pass +Pass Constructing a CSSSkewX with a keyword throws a TypeError +Pass Constructing a CSSSkewX with a double throws a TypeError +Pass Constructing a CSSSkewX with a unitless zero throws a TypeError +Pass Constructing a CSSSkewX with a string angle throws a TypeError +Pass Constructing a CSSSkewX with a number CSSUnitValue throws a TypeError +Pass Constructing a CSSSkewX with a time dimension CSSUnitValue throws a TypeError +Pass Constructing a CSSSkewX with a CSSMathValue of length type throws a TypeError +Pass Updating CSSSkewX.ax with a keyword throws a TypeError +Pass Updating CSSSkewX.ax with a double throws a TypeError +Pass Updating CSSSkewX.ax with a unitless zero throws a TypeError +Pass Updating CSSSkewX.ax with a string angle throws a TypeError +Pass Updating CSSSkewX.ax with a number CSSUnitValue throws a TypeError +Pass Updating CSSSkewX.ax with a time dimension CSSUnitValue throws a TypeError +Pass Updating CSSSkewX.ax with a CSSMathValue of length type throws a TypeError +Pass CSSSkewX can be constructed from an angle CSSUnitValue +Pass CSSSkewX can be constructed from a CSSMathValue of angle type +Pass CSSSkew.ax can be updated to an angle CSSUnitValue +Pass CSSSkew.ax can be updated to a CSSMathValue of angle type +Pass Modifying skewX.is2D is a no-op \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.txt index 8a59b84bd58..5a6cae7b3b7 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.txt @@ -2,13 +2,13 @@ Harness status: OK Found 8 tests -4 Pass -4 Fail +5 Pass +3 Fail Pass CSSTranslate.toMatrix() returns correct matrix Pass CSSRotate.toMatrix() returns correct matrix Pass CSSScale.toMatrix() returns correct matrix Pass CSSSkew.toMatrix() returns correct matrix -Fail CSSSkewX.toMatrix() returns correct matrix +Pass CSSSkewX.toMatrix() returns correct matrix Fail CSSSkewY.toMatrix() returns correct matrix Fail CSSPerspective.toMatrix() returns correct matrix Fail CSSMatrixComponent.toMatrix() returns correct matrix \ No newline at end of file