Skip to content

Commit 5384338

Browse files
committed
LibWeb/CSS: Implement CSSUnitValue
1 parent 0fa1099 commit 5384338

File tree

12 files changed

+201
-43
lines changed

12 files changed

+201
-43
lines changed

Libraries/LibWeb/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ set(SOURCES
132132
CSS/CSSStyleValue.cpp
133133
CSS/CSSSupportsRule.cpp
134134
CSS/CSSTransition.cpp
135+
CSS/CSSUnitValue.cpp
135136
CSS/CSSUnparsedValue.cpp
136137
CSS/CSSVariableReferenceValue.cpp
137138
CSS/Descriptor.cpp

Libraries/LibWeb/CSS/CSSNumericValue.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "CSSNumericValue.h"
88
#include <LibWeb/Bindings/CSSNumericValuePrototype.h>
99
#include <LibWeb/Bindings/Intrinsics.h>
10+
#include <LibWeb/CSS/CSSUnitValue.h>
1011
#include <LibWeb/CSS/NumericType.h>
1112
#include <LibWeb/CSS/Serialize.h>
1213

@@ -99,10 +100,13 @@ CSSNumericType CSSNumericValue::type_for_bindings() const
99100
}
100101

101102
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssnumericvalue
102-
String CSSNumericValue::to_string(SerializationParams const&) const
103+
String CSSNumericValue::to_string(SerializationParams const& params) const
103104
{
104105
// To serialize a CSSNumericValue this, given an optional minimum, a numeric value, and optional maximum, a numeric value:
105-
// FIXME: 1. If this is a CSSUnitValue, serialize a CSSUnitValue from this, passing minimum and maximum. Return the result.
106+
// 1. If this is a CSSUnitValue, serialize a CSSUnitValue from this, passing minimum and maximum. Return the result.
107+
if (auto* unit_value = as_if<CSSUnitValue>(this)) {
108+
return unit_value->serialize_unit_value(params.minimum, params.maximum);
109+
}
106110
// FIXME: 2. Otherwise, serialize a CSSMathValue from this, and return the result.
107111

108112
return {};
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include "CSSUnitValue.h"
8+
#include <LibWeb/Bindings/CSSUnitValuePrototype.h>
9+
#include <LibWeb/Bindings/Intrinsics.h>
10+
#include <LibWeb/CSS/Serialize.h>
11+
#include <LibWeb/WebIDL/ExceptionOr.h>
12+
13+
namespace Web::CSS {
14+
15+
GC_DEFINE_ALLOCATOR(CSSUnitValue);
16+
17+
GC::Ref<CSSUnitValue> CSSUnitValue::create(JS::Realm& realm, double value, FlyString unit)
18+
{
19+
// The type of a CSSUnitValue is the result of creating a type from its unit internal slot.
20+
// https://drafts.css-houdini.org/css-typed-om-1/#type-of-a-cssunitvalue
21+
auto numeric_type = NumericType::create_from_unit(unit);
22+
return realm.create<CSSUnitValue>(realm, value, move(unit), numeric_type.release_value());
23+
}
24+
25+
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunitvalue-cssunitvalue
26+
WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> CSSUnitValue::construct_impl(JS::Realm& realm, double value, FlyString unit)
27+
{
28+
// 1. If creating a type from unit returns failure, throw a TypeError and abort this algorithm.
29+
auto numeric_type = NumericType::create_from_unit(unit);
30+
if (!numeric_type.has_value())
31+
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Cannot create CSSUnitValue with unrecognized unit '{}'", unit)) };
32+
33+
// 2. Return a new CSSUnitValue with its value internal slot set to value and its unit set to unit.
34+
return realm.create<CSSUnitValue>(realm, value, move(unit), numeric_type.release_value());
35+
}
36+
37+
CSSUnitValue::CSSUnitValue(JS::Realm& realm, double value, FlyString unit, NumericType type)
38+
: CSSNumericValue(realm, move(type))
39+
, m_value(value)
40+
// AD-HOC: WPT expects the unit to be lowercase but this doesn't seem to be specified anywhere.
41+
, m_unit(unit.to_ascii_lowercase())
42+
{
43+
}
44+
45+
void CSSUnitValue::initialize(JS::Realm& realm)
46+
{
47+
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSUnitValue);
48+
Base::initialize(realm);
49+
}
50+
51+
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunitvalue-value
52+
void CSSUnitValue::set_value(double value)
53+
{
54+
// AD-HOC: No definition: https://github.com/w3c/css-houdini-drafts/issues/1146
55+
m_value = value;
56+
}
57+
58+
// https://drafts.css-houdini.org/css-typed-om-1/#serialize-a-cssunitvalue
59+
String CSSUnitValue::serialize_unit_value(Optional<double> minimum, Optional<double> maximum) const
60+
{
61+
// To serialize a CSSUnitValue this, with optional arguments minimum, a numeric value, and maximum, a numeric value:
62+
63+
// 1. Let value and unit be this‘s value and unit internal slots.
64+
65+
// 2. Set s to the result of serializing a <number> from value, per CSSOM §6.7.2 Serializing CSS Values.
66+
StringBuilder s;
67+
serialize_a_number(s, m_value);
68+
69+
// 3. If unit is:
70+
// -> "number"
71+
if (m_unit == "number"_fly_string) {
72+
// Do nothing.
73+
}
74+
// -> "percent"
75+
else if (m_unit == "percent"_fly_string) {
76+
// Append "%" to s.
77+
s.append("%"sv);
78+
}
79+
// -> anything else
80+
else {
81+
// Append unit to s.
82+
s.append(m_unit.to_ascii_lowercase());
83+
}
84+
85+
// 4. If minimum was passed and this is less than minimum, or if maximum was passed and this is greater than
86+
// maximum, or either minimum and/or maximum were passed and the relative size of this and minimum/maximum can’t
87+
// be determined with the available information at this time, prepend "calc(" to s, then append ")" to s.
88+
if ((minimum.has_value() && m_value < minimum.value())
89+
|| (maximum.has_value() && m_value > maximum.value())) {
90+
// FIXME: "or either minimum and/or maximum were passed and the relative size of this and minimum/maximum can’t be determined with the available information at this time"
91+
return MUST(String::formatted("calc({})", s.string_view()));
92+
}
93+
94+
// 5. Return s.
95+
return s.to_string_without_validation();
96+
}
97+
98+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <AK/FlyString.h>
10+
#include <LibWeb/CSS/CSSNumericValue.h>
11+
12+
namespace Web::CSS {
13+
14+
// https://drafts.css-houdini.org/css-typed-om-1/#cssunitvalue
15+
class CSSUnitValue : public CSSNumericValue {
16+
WEB_PLATFORM_OBJECT(CSSUnitValue, CSSNumericValue);
17+
GC_DECLARE_ALLOCATOR(CSSUnitValue);
18+
19+
public:
20+
[[nodiscard]] static GC::Ref<CSSUnitValue> create(JS::Realm&, double value, FlyString unit);
21+
static WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> construct_impl(JS::Realm&, double value, FlyString unit);
22+
23+
virtual ~CSSUnitValue() override = default;
24+
25+
double value() const { return m_value; }
26+
void set_value(double value);
27+
28+
FlyString const& unit() const { return m_unit; }
29+
30+
String serialize_unit_value(Optional<double> minimum, Optional<double> maximum) const;
31+
32+
private:
33+
explicit CSSUnitValue(JS::Realm&, double value, FlyString unit, NumericType type);
34+
35+
virtual void initialize(JS::Realm&) override;
36+
37+
double m_value;
38+
FlyString m_unit;
39+
};
40+
41+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#import <CSS/CSSNumericValue.idl>
2+
3+
// https://drafts.css-houdini.org/css-typed-om-1/#cssunitvalue
4+
[Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)]
5+
interface CSSUnitValue : CSSNumericValue {
6+
constructor(double value, USVString unit);
7+
attribute double value;
8+
readonly attribute USVString unit;
9+
};

Libraries/LibWeb/Forward.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ class CSSStyleRule;
257257
class CSSStyleSheet;
258258
class CSSStyleValue;
259259
class CSSSupportsRule;
260+
class CSSUnitValue;
260261
class CSSUnparsedValue;
261262
class CSSVariableReferenceValue;
262263
class CursorStyleValue;

Libraries/LibWeb/idl_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ libweb_js_bindings(CSS/CSSStyleSheet)
5353
libweb_js_bindings(CSS/CSSStyleValue)
5454
libweb_js_bindings(CSS/CSSSupportsRule)
5555
libweb_js_bindings(CSS/CSSTransition)
56+
libweb_js_bindings(CSS/CSSUnitValue)
5657
libweb_js_bindings(CSS/CSSUnparsedValue)
5758
libweb_js_bindings(CSS/CSSVariableReferenceValue)
5859
libweb_js_bindings(CSS/FontFace)

Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static bool is_platform_object(Type const& type)
5757
"CSSKeywordValue"sv,
5858
"CSSNumericValue"sv,
5959
"CSSStyleValue"sv,
60+
"CSSUnitValue"sv,
6061
"CSSUnparsedValue"sv,
6162
"CSSVariableReferenceValue"sv,
6263
"CustomStateSet"sv,

Tests/LibWeb/Text/expected/all-window-properties.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ CSSStyleSheet
6565
CSSStyleValue
6666
CSSSupportsRule
6767
CSSTransition
68+
CSSUnitValue
6869
CSSUnparsedValue
6970
CSSVariableReferenceValue
7071
CacheStorage

Tests/LibWeb/Text/expected/wpt-import/css/css-typed-om/stylevalue-serialization/cssUnitValue.tentative.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ Harness status: OK
22

33
Found 6 tests
44

5-
6 Fail
5+
1 Pass
6+
5 Fail
67
Fail CSSUnitValue with length unit constructed from IDL serializes correctly
78
Fail CSSUnitValue with unit "percent" constructed from IDL serializes correctly
89
Fail CSSUnitValue with unit "number" constructed from IDL serializes correctly
9-
Fail CSSUnitValue with integer values constructed from IDL serializes correctly
10+
Pass CSSUnitValue with integer values constructed from IDL serializes correctly
1011
Fail CSSKeywordValue from DOMString modified by "value" setter serializes correctly
1112
Fail CSSKeywordValue from CSSOM modified by "value" setter serializes correctly

0 commit comments

Comments
 (0)