LibWeb/CSS: Reify numbers, dimensions and percentages as CSSUnitValue

This commit is contained in:
Sam Atkins 2025-08-18 15:29:22 +01:00
parent 5384338788
commit 24017e4ab7
11 changed files with 105 additions and 23 deletions

View File

@ -214,6 +214,7 @@ set(SOURCES
CSS/StyleValues/CounterStyleValue.cpp
CSS/StyleValues/CursorStyleValue.cpp
CSS/StyleValues/CustomIdentStyleValue.cpp
CSS/StyleValues/DimensionStyleValue.cpp
CSS/StyleValues/DisplayStyleValue.cpp
CSS/StyleValues/EasingStyleValue.cpp
CSS/StyleValues/EdgeStyleValue.cpp

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "DimensionStyleValue.h"
#include <LibWeb/CSS/CSSUnitValue.h>
namespace Web::CSS {
Vector<Parser::ComponentValue> DimensionStyleValue::tokenize() const
{
return { Parser::Token::create_dimension(raw_value(), FlyString::from_utf8_without_validation(unit_name().bytes())) };
}
// https://drafts.css-houdini.org/css-typed-om-1/#reify-a-numeric-value
GC::Ref<CSSStyleValue> DimensionStyleValue::reify(JS::Realm& realm, String const&) const
{
// NB: Steps 1 and 2 don't apply here.
// 3. Return a new CSSUnitValue with its value internal slot set to the numeric value of num, and its unit internal
// slot set to "number" if num is a <number>, "percent" if num is a <percentage>, and nums unit if num is a
// <dimension>.
// If the value being reified is a computed value, the unit used must be the appropriate canonical unit for the
// values type, with the numeric value scaled accordingly.
// FIXME: Reify computed value correctly. That sounds like it should work by computing the value properly before we
// reach this point.
return CSSUnitValue::create(realm, raw_value(), FlyString::from_utf8_without_validation(unit_name().bytes()));
}
}

View File

@ -19,10 +19,8 @@ public:
virtual double raw_value() const = 0;
virtual StringView unit_name() const = 0;
virtual Vector<Parser::ComponentValue> tokenize() const override
{
return { Parser::Token::create_dimension(raw_value(), FlyString::from_utf8_without_validation(unit_name().bytes())) };
}
virtual Vector<Parser::ComponentValue> tokenize() const override;
virtual GC::Ref<CSSStyleValue> reify(JS::Realm&, String const& associated_property) const override;
protected:
explicit DimensionStyleValue(Type type)

View File

@ -5,6 +5,7 @@
*/
#include "IntegerStyleValue.h"
#include <LibWeb/CSS/CSSUnitValue.h>
#include <LibWeb/CSS/Parser/ComponentValue.h>
namespace Web::CSS {
@ -19,4 +20,28 @@ Vector<Parser::ComponentValue> IntegerStyleValue::tokenize() const
return { Parser::Token::create_number(Number { Number::Type::Integer, static_cast<double>(m_value) }) };
}
// https://drafts.css-houdini.org/css-typed-om-1/#reify-a-numeric-value
GC::Ref<CSSStyleValue> IntegerStyleValue::reify(JS::Realm& realm, String const& associated_property) const
{
// NB: Step 1 doesn't apply here.
// 2. If num is the unitless value 0 and num is a <dimension>, return a new CSSUnitValue with its value internal
// slot set to 0, and its unit internal slot set to "px".
if (m_value == 0) {
// NB: Determine whether the associated property expects 0 to be a <length>.
// FIXME: Do this for registered custom properties.
if (auto property_id = property_id_from_string(associated_property); property_id.has_value()
&& property_id != PropertyID::Custom
&& property_accepts_type(*property_id, ValueType::Length)) {
return CSSUnitValue::create(realm, 0, "px"_fly_string);
}
}
// 3. Return a new CSSUnitValue with its value internal slot set to the numeric value of num, and its unit internal
// slot set to "number" if num is a <number>, "percent" if num is a <percentage>, and nums unit if num is a
// <dimension>.
// If the value being reified is a computed value, the unit used must be the appropriate canonical unit for the
// values type, with the numeric value scaled accordingly.
return CSSUnitValue::create(realm, m_value, "number"_fly_string);
}
}

View File

@ -21,6 +21,7 @@ public:
virtual String to_string(SerializationMode) const override;
virtual Vector<Parser::ComponentValue> tokenize() const override;
virtual GC::Ref<CSSStyleValue> reify(JS::Realm&, String const& associated_property) const override;
bool equals(StyleValue const& other) const override
{

View File

@ -8,6 +8,7 @@
*/
#include "NumberStyleValue.h"
#include <LibWeb/CSS/CSSUnitValue.h>
#include <LibWeb/CSS/Parser/ComponentValue.h>
#include <LibWeb/CSS/Serialize.h>
@ -23,4 +24,28 @@ Vector<Parser::ComponentValue> NumberStyleValue::tokenize() const
return { Parser::Token::create_number(Number { Number::Type::Number, m_value }) };
}
// https://drafts.css-houdini.org/css-typed-om-1/#reify-a-numeric-value
GC::Ref<CSSStyleValue> NumberStyleValue::reify(JS::Realm& realm, String const& associated_property) const
{
// NB: Step 1 doesn't apply here.
// 2. If num is the unitless value 0 and num is a <dimension>, return a new CSSUnitValue with its value internal
// slot set to 0, and its unit internal slot set to "px".
if (m_value == 0) {
// NB: Determine whether the associated property expects 0 to be a <length>.
// FIXME: Do this for registered custom properties.
if (auto property_id = property_id_from_string(associated_property); property_id.has_value()
&& property_id != PropertyID::Custom
&& property_accepts_type(*property_id, ValueType::Length)) {
return CSSUnitValue::create(realm, 0, "px"_fly_string);
}
}
// 3. Return a new CSSUnitValue with its value internal slot set to the numeric value of num, and its unit internal
// slot set to "number" if num is a <number>, "percent" if num is a <percentage>, and nums unit if num is a
// <dimension>.
// If the value being reified is a computed value, the unit used must be the appropriate canonical unit for the
// values type, with the numeric value scaled accordingly.
return CSSUnitValue::create(realm, m_value, "number"_fly_string);
}
}

View File

@ -24,6 +24,7 @@ public:
virtual String to_string(SerializationMode) const override;
virtual Vector<Parser::ComponentValue> tokenize() const override;
virtual GC::Ref<CSSStyleValue> reify(JS::Realm&, String const& associated_property) const override;
bool equals(StyleValue const& other) const override
{

View File

@ -2,11 +2,11 @@ Harness status: OK
Found 6 tests
1 Pass
5 Fail
3 Pass
3 Fail
Fail CSSUnitValue with length unit constructed from IDL serializes correctly
Fail CSSUnitValue with unit "percent" constructed from IDL serializes correctly
Fail CSSUnitValue with unit "number" constructed from IDL serializes correctly
Pass CSSUnitValue with integer values constructed from IDL serializes correctly
Fail CSSKeywordValue from DOMString modified by "value" setter serializes correctly
Fail CSSKeywordValue from CSSOM modified by "value" setter serializes correctly
Pass CSSKeywordValue from DOMString modified by "value" setter serializes correctly
Pass CSSKeywordValue from CSSOM modified by "value" setter serializes correctly

View File

@ -2,11 +2,11 @@ Harness status: OK
Found 6 tests
2 Pass
4 Fail
5 Pass
1 Fail
Pass Getting a custom property not in the computed style returns undefined
Fail Getting a valid property from computed style returns the correct entry
Pass Getting a valid property from computed style returns the correct entry
Pass Getting a valid custom property from computed style returns the correct entry
Fail Getting a list-valued property from computed style returns only the first value
Fail Computed StylePropertyMap.get is not case-sensitive
Fail Computed StylePropertyMap.get reflects updates in inline style
Pass Computed StylePropertyMap.get is not case-sensitive
Pass Computed StylePropertyMap.get reflects updates in inline style

View File

@ -2,12 +2,12 @@ Harness status: OK
Found 7 tests
2 Pass
5 Fail
5 Pass
2 Fail
Pass Getting a custom property not in the CSS rule returns undefined
Pass Getting a valid property not in the CSS rule returns undefined
Fail Getting a valid property from CSS rule returns the correct entry
Pass Getting a valid property from CSS rule returns the correct entry
Fail Getting a valid custom property from CSS rule returns the correct entry
Fail Getting a list-valued property from CSS rule returns only the first value
Fail Declared StylePropertyMap.get is not case-sensitive
Fail Declared StylePropertyMap.get reflects changes in the CSS rule
Pass Declared StylePropertyMap.get is not case-sensitive
Pass Declared StylePropertyMap.get reflects changes in the CSS rule

View File

@ -2,12 +2,12 @@ Harness status: OK
Found 7 tests
2 Pass
5 Fail
5 Pass
2 Fail
Pass Getting a custom property not in the inline style returns undefined
Pass Getting a valid property not in the inline style returns undefined
Fail Getting a valid property from inline style returns the correct entry
Pass Getting a valid property from inline style returns the correct entry
Fail Getting a valid custom property from inline style returns the correct entry
Fail Getting a list-valued property from inline style returns only the first value
Fail Declared StylePropertyMap.get is not case-sensitive
Fail Declared StylePropertyMap.get reflects changes in the inline style
Pass Declared StylePropertyMap.get is not case-sensitive
Pass Declared StylePropertyMap.get reflects changes in the inline style