LibWeb/CSS: Implement CSSSkewX

Equivalent to the skewX() transform function.

+27 WPT subtests.
This commit is contained in:
Sam Atkins 2025-09-15 15:18:55 +01:00
parent 161e384521
commit b0cc1c6406
10 changed files with 196 additions and 32 deletions

View File

@ -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

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CSSSkewX.h"
#include <LibWeb/Bindings/CSSSkewXPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/CSSNumericValue.h>
#include <LibWeb/CSS/CSSUnitValue.h>
#include <LibWeb/Geometry/DOMMatrix.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
GC_DEFINE_ALLOCATOR(CSSSkewX);
GC::Ref<CSSSkewX> CSSSkewX::create(JS::Realm& realm, GC::Ref<CSSNumericValue> ax)
{
return realm.create<CSSSkewX>(realm, ax);
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssskewx-cssskewx
WebIDL::ExceptionOr<GC::Ref<CSSSkewX>> CSSSkewX::construct_impl(JS::Realm& realm, GC::Ref<CSSNumericValue> ax)
{
// The CSSSkewX(ax) constructor must, when invoked, perform the following steps:
// 1. If ax does not match <angle>, throw a TypeError.
if (!ax->type().matches_angle({}))
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSSkewX ax component doesn't match <angle>"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<CSSNumericValue> 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<Utf16String> CSSSkewX::to_string() const
{
// 1. Let s initially be "skewX(".
StringBuilder builder { StringBuilder::Mode::UTF16 };
builder.append("skewX("sv);
// 2. Serialize thiss 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<GC::Ref<Geometry::DOMMatrix>> CSSSkewX::to_matrix() const
{
// 1. Let matrix be a new DOMMatrix object, initialized to thiss 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 thiss 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 <length>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<void> CSSSkewX::set_ax(GC::Ref<CSSNumericValue> 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 <angle>"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.
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/CSS/CSSTransformComponent.h>
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<CSSSkewX> create(JS::Realm&, GC::Ref<CSSNumericValue> ax);
static WebIDL::ExceptionOr<GC::Ref<CSSSkewX>> construct_impl(JS::Realm&, GC::Ref<CSSNumericValue> ax);
virtual ~CSSSkewX() override;
virtual WebIDL::ExceptionOr<Utf16String> to_string() const override;
virtual WebIDL::ExceptionOr<GC::Ref<Geometry::DOMMatrix>> to_matrix() const override;
GC::Ref<CSSNumericValue> ax() const { return m_ax; }
WebIDL::ExceptionOr<void> set_ax(GC::Ref<CSSNumericValue> value);
virtual void set_is_2d(bool value) override;
private:
explicit CSSSkewX(JS::Realm&, GC::Ref<CSSNumericValue> ax);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Visitor&) override;
GC::Ref<CSSNumericValue> m_ax;
};
}

View File

@ -0,0 +1,9 @@
#import <CSS/CSSNumericValue.idl>
#import <CSS/CSSTransformComponent.idl>
// https://drafts.css-houdini.org/css-typed-om-1/#cssskewx
[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
interface CSSSkewX : CSSTransformComponent {
constructor(CSSNumericValue ax);
attribute CSSNumericValue ax;
};

View File

@ -264,6 +264,7 @@ class CSSRule;
class CSSRuleList;
class CSSScale;
class CSSSkew;
class CSSSkewX;
class CSSStyleDeclaration;
class CSSStyleProperties;
class CSSStyleRule;

View File

@ -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)

View File

@ -71,6 +71,7 @@ CSSRule
CSSRuleList
CSSScale
CSSSkew
CSSSkewX
CSSStyleDeclaration
CSSStyleProperties
CSSStyleRule

View File

@ -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

View File

@ -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
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

View File

@ -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