LibWeb: Implement CSSFontFeatureValuesMap

This will be used within `CSSFontFeatureValuesRule`
This commit is contained in:
Callum Law 2026-01-13 15:15:18 +13:00 committed by Sam Atkins
parent 3f8da74e63
commit fcdc05a4ee
8 changed files with 138 additions and 10 deletions

View file

@ -112,6 +112,7 @@ set(SOURCES
CSS/CSSDescriptors.cpp
CSS/CSSFontFaceDescriptors.cpp
CSS/CSSFontFaceRule.cpp
CSS/CSSFontFeatureValuesMap.cpp
CSS/CSSGroupingRule.cpp
CSS/CSSImageValue.cpp
CSS/CSSImportRule.cpp

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2026, Callum Law <callumlaw1709@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CSSFontFeatureValuesMap.h"
#include <LibJS/Runtime/Array.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
GC_DEFINE_ALLOCATOR(CSSFontFeatureValuesMap);
GC::Ref<CSSFontFeatureValuesMap> CSSFontFeatureValuesMap::create(JS::Realm& realm, size_t max_value_count)
{
return realm.create<CSSFontFeatureValuesMap>(realm, max_value_count);
}
CSSFontFeatureValuesMap::CSSFontFeatureValuesMap(JS::Realm& realm, size_t max_value_count)
: Bindings::PlatformObject(realm)
, m_map_entries(JS::Map::create(realm))
, m_max_value_count(max_value_count)
{
}
WebIDL::ExceptionOr<void> CSSFontFeatureValuesMap::set(String const& feature_value_name, Variant<u32, Vector<u32>> const& values)
{
// https://drafts.csswg.org/css-fonts-4/#cssfontfeaturevaluesmap
// The CSSFontFeatureValuesMap interface uses the default map class methods but the set method has different
// behavior. It takes a sequence of unsigned integers and associates it with a given featureValueName. The method
// behaves the same as the default map class method except that
// a single unsigned long value is treated as a sequence of a single value.
Vector<u32> value_vector = values.visit(
[](u32 single_value) { return Vector<u32> { single_value }; },
[](Vector<u32> value_vector) { return value_vector; });
// The method throws an exception if an invalid number of values is passed in.
if (value_vector.is_empty())
return WebIDL::InvalidAccessError::create(realm(), "CSSFontFeatureValuesMap.set requires at least one value."_utf16);
// If the associated feature value block only allows a limited number of values, the set method throws an
// InvalidAccessError exception when the input sequence to set contains more than the limited number of values. See
// the description of multi-valued feature value definitions for details on the maximum number of values allowed for
// a given type of feature value block.
if (value_vector.size() > m_max_value_count)
return WebIDL::InvalidAccessError::create(realm(), Utf16String::formatted("CSSFontFeatureValuesMap.set only allows a maximum of {} values for the associated feature", m_max_value_count));
Vector<JS::Value> wrapped_values;
wrapped_values.ensure_capacity(value_vector.size());
for (auto const& value : value_vector)
wrapped_values.append(JS::Value { value });
m_map_entries->map_set(JS::PrimitiveString::create(vm(), feature_value_name), JS::Array::create_from(realm(), wrapped_values.span()));
// TODO: Clear the relevant caches
return {};
}
void CSSFontFeatureValuesMap::on_map_modified_from_js(Badge<Bindings::CSSFontFeatureValuesMapPrototype>)
{
// TODO: Clear the relevant caches
}
void CSSFontFeatureValuesMap::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSFontFeatureValuesMap);
Base::initialize(realm);
}
void CSSFontFeatureValuesMap::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_map_entries);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2026, Callum Law <callumlaw1709@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/MapIterator.h>
#include <LibWeb/Bindings/CSSFontFeatureValuesMapPrototype.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
class CSSFontFeatureValuesMap final : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(CSSFontFeatureValuesMap, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(CSSFontFeatureValuesMap);
public:
static GC::Ref<CSSFontFeatureValuesMap> create(JS::Realm&, size_t max_value_count);
virtual GC::Ref<JS::Map> map_entries() { return m_map_entries; }
WebIDL::ExceptionOr<void> set(String const& feature_value_name, Variant<u32, Vector<u32>> const& values);
void on_map_modified_from_js(Badge<Bindings::CSSFontFeatureValuesMapPrototype>);
private:
CSSFontFeatureValuesMap(JS::Realm&, size_t max_value_count);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
GC::Ref<JS::Map> m_map_entries;
size_t m_max_value_count;
};
}

View file

@ -0,0 +1,5 @@
[Exposed=Window]
interface CSSFontFeatureValuesMap {
maplike<CSSOMString, sequence<unsigned long>>;
undefined set(CSSOMString featureValueName, (unsigned long or sequence<unsigned long>) values);
};

View file

@ -246,6 +246,7 @@ class CSSCounterStyleRule;
class CSSDescriptors;
class CSSFontFaceDescriptors;
class CSSFontFaceRule;
class CSSFontFeatureValuesMap;
class CSSGroupingRule;
class CSSImageValue;
class CSSImportRule;

View file

@ -29,6 +29,7 @@ libweb_js_bindings(CSS/CSSConditionRule)
libweb_js_bindings(CSS/CSSCounterStyleRule)
libweb_js_bindings(CSS/CSSFontFaceDescriptors)
libweb_js_bindings(CSS/CSSFontFaceRule)
libweb_js_bindings(CSS/CSSFontFeatureValuesMap)
libweb_js_bindings(CSS/CSSGroupingRule)
libweb_js_bindings(CSS/CSSImageValue)
libweb_js_bindings(CSS/CSSImportRule)

View file

@ -41,6 +41,7 @@ CSSConditionRule
CSSCounterStyleRule
CSSFontFaceDescriptors
CSSFontFaceRule
CSSFontFeatureValuesMap
CSSGroupingRule
CSSImageValue
CSSImportRule

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 97 tests
48 Pass
49 Fail
56 Pass
41 Fail
Pass idl_test setup
Pass idl_test validation
Pass Partial interface CSSRule: original interface defined
@ -80,14 +80,14 @@ Fail CSSFontFeatureValuesRule interface: attribute swash
Fail CSSFontFeatureValuesRule interface: attribute characterVariant
Fail CSSFontFeatureValuesRule interface: attribute styleset
Fail CSSFontFeatureValuesRule interface: attribute historicalForms
Fail CSSFontFeatureValuesMap interface: existence and properties of interface object
Fail CSSFontFeatureValuesMap interface object length
Fail CSSFontFeatureValuesMap interface object name
Fail CSSFontFeatureValuesMap interface: existence and properties of interface prototype object
Fail CSSFontFeatureValuesMap interface: existence and properties of interface prototype object's "constructor" property
Fail CSSFontFeatureValuesMap interface: existence and properties of interface prototype object's @@unscopables property
Fail CSSFontFeatureValuesMap interface: maplike<CSSOMString, [object Object]>
Fail CSSFontFeatureValuesMap interface: operation set(CSSOMString, (unsigned long or sequence<unsigned long>))
Pass CSSFontFeatureValuesMap interface: existence and properties of interface object
Pass CSSFontFeatureValuesMap interface object length
Pass CSSFontFeatureValuesMap interface object name
Pass CSSFontFeatureValuesMap interface: existence and properties of interface prototype object
Pass CSSFontFeatureValuesMap interface: existence and properties of interface prototype object's "constructor" property
Pass CSSFontFeatureValuesMap interface: existence and properties of interface prototype object's @@unscopables property
Pass CSSFontFeatureValuesMap interface: maplike<CSSOMString, [object Object]>
Pass CSSFontFeatureValuesMap interface: operation set(CSSOMString, (unsigned long or sequence<unsigned long>))
Fail CSSFontPaletteValuesRule interface: existence and properties of interface object
Fail CSSFontPaletteValuesRule interface object length
Fail CSSFontPaletteValuesRule interface object name