LibWeb/CSS: Implement CSSNumericValue.to()
Some checks are pending
CI / Linux, x86_64, Sanitizer, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
CI / macOS, arm64, Sanitizer, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer, GNU (push) Waiting to run

Tries to convert the CSSNumericValue to a CSSUnitValue with the given
unit.

This gets us the remaining 11 WPT subtests for this method.
This commit is contained in:
Sam Atkins 2025-09-11 17:00:26 +01:00 committed by Jelle Raaijmakers
commit a139ad1c44
Notes: github-actions[bot] 2025-09-12 11:46:37 +00:00
6 changed files with 73 additions and 14 deletions

View file

@ -71,6 +71,39 @@ bool CSSNumericValue::equals_for_bindings(Vector<CSSNumberish> values) const
return true;
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-to
WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> CSSNumericValue::to(FlyString const& unit) const
{
// The to(unit) method converts an existing CSSNumericValue this into another one with the specified unit, if
// possible. When called, it must perform the following steps:
// 1. Let type be the result of creating a type from unit. If type is failure, throw a SyntaxError.
auto maybe_type = NumericType::create_from_unit(unit);
if (!maybe_type.has_value())
return WebIDL::SyntaxError::create(realm(), Utf16String::formatted("Unrecognized unit '{}'", unit));
// 2. Let sum be the result of creating a sum value from this. If sum is failure, throw a TypeError.
auto sum = create_a_sum_value();
if (!sum.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unable to create a sum from input '{}'", to_string())) };
// 3. If sum has more than one item, throw a TypeError.
// Otherwise, let item be the result of creating a CSSUnitValue from the sole item in sum, then converting it to
// unit. If item is failure, throw a TypeError.
if (sum->size() > 1)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Sum contains more than one item"sv };
auto item = CSSUnitValue::create_from_sum_value_item(realm(), sum->first());
if (!item)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unable to create CSSUnitValue from input '{}'", to_string())) };
auto converted_item = item->converted_to_unit(unit);
if (!converted_item)
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Unable to convert input '{}' to unit '{}'", to_string(), unit)) };
// 4. Return item.
return converted_item.as_nonnull();
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-type
CSSNumericType CSSNumericValue::type_for_bindings() const
{

View file

@ -52,6 +52,8 @@ public:
bool equals_for_bindings(Vector<CSSNumberish>) const;
virtual bool is_equal_numeric_value(GC::Ref<CSSNumericValue> other) const = 0;
WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> to(FlyString const& unit) const;
virtual Optional<SumValue> create_a_sum_value() const = 0;
CSSNumericType type_for_bindings() const;

View file

@ -1,4 +1,5 @@
#import <CSS/CSSStyleValue.idl>
#import <CSS/CSSUnitValue.idl>
// https://drafts.css-houdini.org/css-typed-om-1/#enumdef-cssnumericbasetype
enum CSSNumericBaseType {
@ -35,7 +36,7 @@ interface CSSNumericValue : CSSStyleValue {
[ImplementedAs=equals_for_bindings] boolean equals(CSSNumberish... value);
// FIXME: CSSUnitValue to(USVString unit);
CSSUnitValue to(USVString unit);
// FIXME: CSSMathSum toSum(USVString... units);
[ImplementedAs=type_for_bindings] CSSNumericType type();

View file

@ -23,6 +23,29 @@ GC::Ref<CSSUnitValue> CSSUnitValue::create(JS::Realm& realm, double value, FlySt
return realm.create<CSSUnitValue>(realm, value, move(unit), numeric_type.release_value());
}
// https://drafts.css-houdini.org/css-typed-om-1/#create-a-cssunitvalue-from-a-sum-value-item
GC::Ptr<CSSUnitValue> CSSUnitValue::create_from_sum_value_item(JS::Realm& realm, SumValueItem const& item)
{
// 1. If item has more than one entry in its unit map, return failure.
if (item.unit_map.size() > 1)
return {};
// 2. If item has no entries in its unit map, return a new CSSUnitValue whose unit internal slot is set to
// "number", and whose value internal slot is set to items value.
if (item.unit_map.is_empty())
return CSSUnitValue::create(realm, item.value, "number"_fly_string);
// 3. Otherwise, item has a single entry in its unit map. If that entrys value is anything other than 1, return
// failure.
auto single_type_entry = item.unit_map.begin();
if (single_type_entry->value != 1)
return {};
// 4. Otherwise, return a new CSSUnitValue whose unit internal slot is set to that entrys key, and whose value
// internal slot is set to items value.
return CSSUnitValue::create(realm, item.value, single_type_entry->key);
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunitvalue-cssunitvalue
WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> CSSUnitValue::construct_impl(JS::Realm& realm, double value, FlyString unit)
{

View file

@ -18,6 +18,7 @@ class CSSUnitValue final : public CSSNumericValue {
public:
[[nodiscard]] static GC::Ref<CSSUnitValue> create(JS::Realm&, double value, FlyString unit);
static GC::Ptr<CSSUnitValue> create_from_sum_value_item(JS::Realm&, SumValueItem const&);
static WebIDL::ExceptionOr<GC::Ref<CSSUnitValue>> construct_impl(JS::Realm&, double value, FlyString unit);
virtual ~CSSUnitValue() override = default;

View file

@ -2,22 +2,21 @@ Harness status: OK
Found 17 tests
6 Pass
11 Fail
Fail Converting a CSSUnitValue to an invalid unit throws SyntaxError
17 Pass
Pass Converting a CSSUnitValue to an invalid unit throws SyntaxError
Pass Converting a CSSNumericValue with invalid sum value throws TypeError
Pass Converting a CSSNumericValue with sum value containing more than one value throws TypeError
Pass Converting a CSSUnitValue to an incompatible unit throws TypeError
Fail Converting a CSSUnitValue to its own unit returns itself
Fail Converting a CSSUnitValue to its canonical unit returns correct value
Fail Converting a CSSMathSum to a single unit adds the values
Fail Converting a CSSMathProduct to a single unit multiplies the values
Fail Converting a CSSMathMin to a single unit finds the min value
Pass Converting a CSSUnitValue to its own unit returns itself
Pass Converting a CSSUnitValue to its canonical unit returns correct value
Pass Converting a CSSMathSum to a single unit adds the values
Pass Converting a CSSMathProduct to a single unit multiplies the values
Pass Converting a CSSMathMin to a single unit finds the min value
Pass Converting a CSSMathMin to a single unit with different units throws a TypeError
Fail Converting a CSSMathMax to a single unit finds the max value
Pass Converting a CSSMathMax to a single unit finds the max value
Pass Converting a CSSMathMax to a single unit with different units throws a TypeError
Fail Converting a CSSMathClamp to a single unit returns the clamped value
Pass Converting a CSSMathClamp to a single unit returns the clamped value
Pass Converting a CSSMathClamp to a single unit with different units throws a TypeError
Fail Converting a CSSMathNegate to a single unit negates its value
Fail Converting a CSSMathInvert to a single unit inverts its value and units
Fail Converting a complex expression to a single unit
Pass Converting a CSSMathNegate to a single unit negates its value
Pass Converting a CSSMathInvert to a single unit inverts its value and units
Pass Converting a complex expression to a single unit