mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb/CSS: Implement CSSScale
Equivalent to the scale() transform functions. +33 WPT subtests.
This commit is contained in:
parent
d348d8d9b8
commit
456946368e
|
|
@ -137,6 +137,7 @@ set(SOURCES
|
|||
CSS/CSSRotate.cpp
|
||||
CSS/CSSRule.cpp
|
||||
CSS/CSSRuleList.cpp
|
||||
CSS/CSSScale.cpp
|
||||
CSS/CSSStyleDeclaration.cpp
|
||||
CSS/CSSStyleProperties.cpp
|
||||
CSS/CSSStyleRule.cpp
|
||||
|
|
|
|||
202
Libraries/LibWeb/CSS/CSSScale.cpp
Normal file
202
Libraries/LibWeb/CSS/CSSScale.cpp
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "CSSScale.h"
|
||||
#include <LibWeb/Bindings/CSSScalePrototype.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(CSSScale);
|
||||
|
||||
GC::Ref<CSSScale> CSSScale::create(JS::Realm& realm, Is2D is_2d, GC::Ref<CSSNumericValue> x, GC::Ref<CSSNumericValue> y, GC::Ref<CSSNumericValue> z)
|
||||
{
|
||||
return realm.create<CSSScale>(realm, is_2d, x, y, z);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ref<CSSScale>> CSSScale::construct_impl(JS::Realm& realm, CSSNumberish x, CSSNumberish y, Optional<CSSNumberish> z)
|
||||
{
|
||||
// The CSSScale(x, y, z) constructor must, when invoked, perform the following steps:
|
||||
|
||||
// 1. Let x, y, and z (if passed) be replaced by the result of rectifying a numberish value.
|
||||
auto rectified_x = rectify_a_numberish_value(realm, x);
|
||||
auto rectified_y = rectify_a_numberish_value(realm, y);
|
||||
auto rectified_z = z.map([&](auto& it) { return rectify_a_numberish_value(realm, it); });
|
||||
|
||||
// 2. If x, y, or z (if passed) don’t match <number>, throw a TypeError.
|
||||
if (!rectified_x->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale x component doesn't match <number>"sv };
|
||||
if (!rectified_y->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale y component doesn't match <number>"sv };
|
||||
if (rectified_z.has_value() && !rectified_z.value()->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale z component doesn't match <number>"sv };
|
||||
|
||||
// 3. Let this be a new CSSScale object, with its x and y internal slots set to x and y.
|
||||
// 4. If z was passed, set this’s z internal slot to z, and set this’s is2D internal slot to false.
|
||||
// 5. If z was not passed, set this’s z internal slot to a new unit value of (1, "number"), and set this’s is2D internal slot to true.
|
||||
Is2D is_2d = Is2D::No;
|
||||
if (!rectified_z.has_value()) {
|
||||
rectified_z = CSSUnitValue::create(realm, 1, "number"_fly_string);
|
||||
is_2d = Is2D::Yes;
|
||||
}
|
||||
auto this_ = CSSScale::create(realm, is_2d, rectified_x, rectified_y, rectified_z.release_value());
|
||||
|
||||
// 6. Return this.
|
||||
return this_;
|
||||
}
|
||||
|
||||
CSSScale::CSSScale(JS::Realm& realm, Is2D is_2d, GC::Ref<CSSNumericValue> x, GC::Ref<CSSNumericValue> y, GC::Ref<CSSNumericValue> z)
|
||||
: CSSTransformComponent(realm, is_2d)
|
||||
, m_x(x)
|
||||
, m_y(y)
|
||||
, m_z(z)
|
||||
{
|
||||
}
|
||||
|
||||
CSSScale::~CSSScale() = default;
|
||||
|
||||
void CSSScale::initialize(JS::Realm& realm)
|
||||
{
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSScale);
|
||||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
void CSSScale::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_x);
|
||||
visitor.visit(m_y);
|
||||
visitor.visit(m_z);
|
||||
}
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssscale
|
||||
WebIDL::ExceptionOr<Utf16String> CSSScale::to_string() const
|
||||
{
|
||||
// 1. Let s initially be the empty string.
|
||||
StringBuilder builder { StringBuilder::Mode::UTF16 };
|
||||
|
||||
// 2. If this’s is2D internal slot is false:
|
||||
if (!is_2d()) {
|
||||
|
||||
// 1. Append "scale3d(" to s.
|
||||
builder.append("scale3d("sv);
|
||||
|
||||
// 2. Serialize this’s x internal slot, and append it to s.
|
||||
builder.append(m_x->to_string());
|
||||
|
||||
// 3. Append ", " to s.
|
||||
builder.append(", "sv);
|
||||
|
||||
// 4. Serialize this’s y internal slot, and append it to s.
|
||||
builder.append(m_y->to_string());
|
||||
|
||||
// 5. Append ", " to s.
|
||||
builder.append(", "sv);
|
||||
|
||||
// 6. Serialize this’s z internal slot, and append it to s.
|
||||
builder.append(m_z->to_string());
|
||||
|
||||
// 7. Append ")" to s, and return s.
|
||||
builder.append(")"sv);
|
||||
return builder.to_utf16_string();
|
||||
}
|
||||
|
||||
// 3. Otherwise:
|
||||
else {
|
||||
// 1. Append "scale(" to s.
|
||||
builder.append("scale("sv);
|
||||
|
||||
// 2. Serialize this’s x internal slot, and append it to s.
|
||||
builder.append(m_x->to_string());
|
||||
|
||||
// 3. If this’s x and y internal slots are equal numeric values, append ")" to s and return s.
|
||||
if (m_x->is_equal_numeric_value(m_y)) {
|
||||
builder.append(")"sv);
|
||||
return builder.to_utf16_string();
|
||||
}
|
||||
|
||||
// 4. Otherwise, append ", " to s.
|
||||
builder.append(", "sv);
|
||||
|
||||
// 5. Serialize this’s y internal slot, and append it to s.
|
||||
builder.append(m_y->to_string());
|
||||
|
||||
// 6. 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>> CSSScale::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 <length>s in this involved in
|
||||
// generating the matrix are not compatible units with px (such as relative lengths or percentages), throw a
|
||||
// TypeError.
|
||||
// 2. Return matrix.
|
||||
|
||||
auto matrix = Geometry::DOMMatrix::create(realm());
|
||||
|
||||
// NB: to() throws a TypeError if the conversion can't be done.
|
||||
auto x = TRY(m_x->to("number"_fly_string))->value();
|
||||
auto y = TRY(m_y->to("number"_fly_string))->value();
|
||||
|
||||
if (is_2d())
|
||||
return matrix->scale_self(x, y, {}, {}, {}, {});
|
||||
|
||||
auto z = TRY(m_z->to("number"_fly_string))->value();
|
||||
return matrix->scale_self(x, y, z, {}, {}, {});
|
||||
}
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssscale-x
|
||||
WebIDL::ExceptionOr<void> CSSScale::set_x(CSSNumberish value)
|
||||
{
|
||||
// The x, y, and z attributes must, on setting to a new value val, rectify a numberish value from val and set the
|
||||
// corresponding internal slot to the result of that.
|
||||
// AD-HOC: WPT expects this to throw for invalid values. https://github.com/w3c/css-houdini-drafts/issues/1153
|
||||
auto rectified_x = rectify_a_numberish_value(realm(), value);
|
||||
if (!rectified_x->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale x component doesn't match <number>"sv };
|
||||
m_x = rectified_x;
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssscale-y
|
||||
WebIDL::ExceptionOr<void> CSSScale::set_y(CSSNumberish value)
|
||||
{
|
||||
// The x, y, and z attributes must, on setting to a new value val, rectify a numberish value from val and set the
|
||||
// corresponding internal slot to the result of that.
|
||||
// AD-HOC: WPT expects this to throw for invalid values. https://github.com/w3c/css-houdini-drafts/issues/1153
|
||||
auto rectified_y = rectify_a_numberish_value(realm(), value);
|
||||
if (!rectified_y->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale y component doesn't match <number>"sv };
|
||||
m_y = rectified_y;
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssscale-z
|
||||
WebIDL::ExceptionOr<void> CSSScale::set_z(CSSNumberish value)
|
||||
{
|
||||
// The x, y, and z attributes must, on setting to a new value val, rectify a numberish value from val and set the
|
||||
// corresponding internal slot to the result of that.
|
||||
// AD-HOC: WPT expects this to throw for invalid values. https://github.com/w3c/css-houdini-drafts/issues/1153
|
||||
auto rectified_z = rectify_a_numberish_value(realm(), value);
|
||||
if (!rectified_z->type().matches_number({}))
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "CSSScale z component doesn't match <number>"sv };
|
||||
m_z = rectified_z;
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
47
Libraries/LibWeb/CSS/CSSScale.h
Normal file
47
Libraries/LibWeb/CSS/CSSScale.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/CSSNumericValue.h>
|
||||
#include <LibWeb/CSS/CSSTransformComponent.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#cssscale
|
||||
class CSSScale final : public CSSTransformComponent {
|
||||
WEB_PLATFORM_OBJECT(CSSScale, CSSTransformComponent);
|
||||
GC_DECLARE_ALLOCATOR(CSSScale);
|
||||
|
||||
public:
|
||||
[[nodiscard]] static GC::Ref<CSSScale> create(JS::Realm&, Is2D, GC::Ref<CSSNumericValue> x, GC::Ref<CSSNumericValue> y, GC::Ref<CSSNumericValue> z);
|
||||
static WebIDL::ExceptionOr<GC::Ref<CSSScale>> construct_impl(JS::Realm&, CSSNumberish x, CSSNumberish y, Optional<CSSNumberish> z = {});
|
||||
|
||||
virtual ~CSSScale() override;
|
||||
|
||||
virtual WebIDL::ExceptionOr<Utf16String> to_string() const override;
|
||||
|
||||
virtual WebIDL::ExceptionOr<GC::Ref<Geometry::DOMMatrix>> to_matrix() const override;
|
||||
|
||||
CSSNumberish x() const { return GC::Root { m_x }; }
|
||||
CSSNumberish y() const { return GC::Root { m_y }; }
|
||||
CSSNumberish z() const { return GC::Root { m_z }; }
|
||||
WebIDL::ExceptionOr<void> set_x(CSSNumberish value);
|
||||
WebIDL::ExceptionOr<void> set_y(CSSNumberish value);
|
||||
WebIDL::ExceptionOr<void> set_z(CSSNumberish value);
|
||||
|
||||
private:
|
||||
explicit CSSScale(JS::Realm&, Is2D, GC::Ref<CSSNumericValue> x, GC::Ref<CSSNumericValue> y, GC::Ref<CSSNumericValue> z);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
GC::Ref<CSSNumericValue> m_x;
|
||||
GC::Ref<CSSNumericValue> m_y;
|
||||
GC::Ref<CSSNumericValue> m_z;
|
||||
};
|
||||
|
||||
}
|
||||
11
Libraries/LibWeb/CSS/CSSScale.idl
Normal file
11
Libraries/LibWeb/CSS/CSSScale.idl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#import <CSS/CSSNumericValue.idl>
|
||||
#import <CSS/CSSTransformComponent.idl>
|
||||
|
||||
// https://drafts.css-houdini.org/css-typed-om-1/#cssscale
|
||||
[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
|
||||
interface CSSScale : CSSTransformComponent {
|
||||
constructor(CSSNumberish x, CSSNumberish y, optional CSSNumberish z);
|
||||
attribute CSSNumberish x;
|
||||
attribute CSSNumberish y;
|
||||
attribute CSSNumberish z;
|
||||
};
|
||||
|
|
@ -262,6 +262,7 @@ class CSSPropertyRule;
|
|||
class CSSRotate;
|
||||
class CSSRule;
|
||||
class CSSRuleList;
|
||||
class CSSScale;
|
||||
class CSSStyleDeclaration;
|
||||
class CSSStyleProperties;
|
||||
class CSSStyleRule;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ libweb_js_bindings(CSS/CSSPropertyRule)
|
|||
libweb_js_bindings(CSS/CSSRotate)
|
||||
libweb_js_bindings(CSS/CSSRule)
|
||||
libweb_js_bindings(CSS/CSSRuleList)
|
||||
libweb_js_bindings(CSS/CSSScale)
|
||||
libweb_js_bindings(CSS/CSSStyleDeclaration)
|
||||
libweb_js_bindings(CSS/CSSStyleProperties)
|
||||
libweb_js_bindings(CSS/CSSStyleRule)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ CSSPropertyRule
|
|||
CSSRotate
|
||||
CSSRule
|
||||
CSSRuleList
|
||||
CSSScale
|
||||
CSSStyleDeclaration
|
||||
CSSStyleProperties
|
||||
CSSStyleRule
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 545 tests
|
||||
|
||||
315 Pass
|
||||
230 Fail
|
||||
324 Pass
|
||||
221 Fail
|
||||
Pass idl_test setup
|
||||
Pass idl_test validation
|
||||
Pass Partial interface Element: original interface defined
|
||||
|
|
@ -310,15 +310,15 @@ Fail CSSRotate interface: rotate must inherit property "z" with the proper type
|
|||
Fail CSSRotate interface: rotate must inherit property "angle" with the proper type
|
||||
Fail CSSTransformComponent interface: rotate must inherit property "is2D" with the proper type
|
||||
Fail CSSTransformComponent interface: rotate must inherit property "toMatrix()" with the proper type
|
||||
Fail CSSScale interface: existence and properties of interface object
|
||||
Fail CSSScale interface object length
|
||||
Fail CSSScale interface object name
|
||||
Fail CSSScale interface: existence and properties of interface prototype object
|
||||
Fail CSSScale interface: existence and properties of interface prototype object's "constructor" property
|
||||
Fail CSSScale interface: existence and properties of interface prototype object's @@unscopables property
|
||||
Fail CSSScale interface: attribute x
|
||||
Fail CSSScale interface: attribute y
|
||||
Fail CSSScale interface: attribute z
|
||||
Pass CSSScale interface: existence and properties of interface object
|
||||
Pass CSSScale interface object length
|
||||
Pass CSSScale interface object name
|
||||
Pass CSSScale interface: existence and properties of interface prototype object
|
||||
Pass CSSScale interface: existence and properties of interface prototype object's "constructor" property
|
||||
Pass CSSScale interface: existence and properties of interface prototype object's @@unscopables property
|
||||
Pass CSSScale interface: attribute x
|
||||
Pass CSSScale interface: attribute y
|
||||
Pass CSSScale interface: attribute z
|
||||
Fail CSSScale must be primary interface of scale
|
||||
Fail Stringification of scale
|
||||
Fail CSSScale interface: scale must inherit property "x" with the proper type
|
||||
|
|
|
|||
|
|
@ -2,26 +2,26 @@ Harness status: OK
|
|||
|
||||
Found 22 tests
|
||||
|
||||
22 Fail
|
||||
Fail Constructing a CSSScale with an angle CSSUnitValue for the coordinates throws a TypeError
|
||||
Fail Constructing a CSSScale with a CSSMathValue that doesn't match <number> for the coordinates throws a TypeError
|
||||
Fail Updating CSSScale.x to an angle CSSUnitValue throws a TypeError
|
||||
Fail Updating CSSScale.x to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Fail Updating CSSScale.y to an angle CSSUnitValue throws a TypeError
|
||||
Fail Updating CSSScale.y to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Fail Updating CSSScale.z to an angle CSSUnitValue throws a TypeError
|
||||
Fail Updating CSSScale.z to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Fail CSSScale can be constructed from two number coordinates
|
||||
Fail CSSScale can be constructed from three number coordinates
|
||||
Fail CSSScale can be constructed from CSSMathValue coordinates
|
||||
Fail CSSScale can be constructed from unit canceling length value coordinates
|
||||
Fail CSSScale.x can be updated to a number
|
||||
Fail CSSScale.x can be updated to a numberish
|
||||
Fail CSSScale.x can be updated to a CSSMathValue
|
||||
Fail CSSScale.y can be updated to a number
|
||||
Fail CSSScale.y can be updated to a numberish
|
||||
Fail CSSScale.y can be updated to a CSSMathValue
|
||||
Fail CSSScale.z can be updated to a number
|
||||
Fail CSSScale.z can be updated to a numberish
|
||||
Fail CSSScale.z can be updated to a CSSMathValue
|
||||
Fail Modifying CSSScale.is2D can be updated to true or false
|
||||
22 Pass
|
||||
Pass Constructing a CSSScale with an angle CSSUnitValue for the coordinates throws a TypeError
|
||||
Pass Constructing a CSSScale with a CSSMathValue that doesn't match <number> for the coordinates throws a TypeError
|
||||
Pass Updating CSSScale.x to an angle CSSUnitValue throws a TypeError
|
||||
Pass Updating CSSScale.x to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Pass Updating CSSScale.y to an angle CSSUnitValue throws a TypeError
|
||||
Pass Updating CSSScale.y to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Pass Updating CSSScale.z to an angle CSSUnitValue throws a TypeError
|
||||
Pass Updating CSSScale.z to a CSSMathValue that doesn't match <number> throws a TypeError
|
||||
Pass CSSScale can be constructed from two number coordinates
|
||||
Pass CSSScale can be constructed from three number coordinates
|
||||
Pass CSSScale can be constructed from CSSMathValue coordinates
|
||||
Pass CSSScale can be constructed from unit canceling length value coordinates
|
||||
Pass CSSScale.x can be updated to a number
|
||||
Pass CSSScale.x can be updated to a numberish
|
||||
Pass CSSScale.x can be updated to a CSSMathValue
|
||||
Pass CSSScale.y can be updated to a number
|
||||
Pass CSSScale.y can be updated to a numberish
|
||||
Pass CSSScale.y can be updated to a CSSMathValue
|
||||
Pass CSSScale.z can be updated to a number
|
||||
Pass CSSScale.z can be updated to a numberish
|
||||
Pass CSSScale.z can be updated to a CSSMathValue
|
||||
Pass Modifying CSSScale.is2D can be updated to true or false
|
||||
|
|
@ -2,9 +2,9 @@ Harness status: OK
|
|||
|
||||
Found 4 tests
|
||||
|
||||
2 Pass
|
||||
2 Fail
|
||||
3 Pass
|
||||
1 Fail
|
||||
Pass CSSTranslate.toMatrix() flattens when told it is 2d
|
||||
Pass CSSRotate.toMatrix() flattens when told it is 2d
|
||||
Fail CSSScale.toMatrix() flattens when told it is 2d
|
||||
Pass CSSScale.toMatrix() flattens when told it is 2d
|
||||
Fail CSSMatrixComponent.toMatrix() flattens when told it is 2d
|
||||
|
|
@ -2,11 +2,11 @@ Harness status: OK
|
|||
|
||||
Found 8 tests
|
||||
|
||||
2 Pass
|
||||
6 Fail
|
||||
3 Pass
|
||||
5 Fail
|
||||
Pass CSSTranslate.toMatrix() returns correct matrix
|
||||
Pass CSSRotate.toMatrix() returns correct matrix
|
||||
Fail CSSScale.toMatrix() returns correct matrix
|
||||
Pass CSSScale.toMatrix() returns correct matrix
|
||||
Fail CSSSkew.toMatrix() returns correct matrix
|
||||
Fail CSSSkewX.toMatrix() returns correct matrix
|
||||
Fail CSSSkewY.toMatrix() returns correct matrix
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user