Produce JS-visible string results as UTF-16 at their source, including numeric formatting, BigInt and BigFraction formatting, URI encoding, console formatting, parser errors, regular expression errors, Intl and Temporal records, LibUnicode locale boundaries, and LibWeb bindings. Handle fractional radix formatting through the UTF-16 builder view.
106 lines
4.1 KiB
C++
106 lines
4.1 KiB
C++
/*
|
|
* 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/CSS/CSSFontFeatureValuesRule.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, GC::Ref<CSSFontFeatureValuesRule> parent_rule)
|
|
{
|
|
return realm.create<CSSFontFeatureValuesMap>(realm, max_value_count, parent_rule);
|
|
}
|
|
|
|
CSSFontFeatureValuesMap::CSSFontFeatureValuesMap(JS::Realm& realm, size_t max_value_count, GC::Ref<CSSFontFeatureValuesRule> parent_rule)
|
|
: Bindings::PlatformObject(realm)
|
|
, m_map_entries(JS::Map::create(realm))
|
|
, m_max_value_count(max_value_count)
|
|
, m_parent_rule(parent_rule)
|
|
{
|
|
}
|
|
|
|
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(), Utf16String::from_utf8(feature_value_name)), JS::Array::create_from(realm(), wrapped_values.span()));
|
|
|
|
m_parent_rule->clear_caches();
|
|
|
|
return {};
|
|
}
|
|
|
|
void CSSFontFeatureValuesMap::on_map_modified_from_js(Badge<Bindings::CSSFontFeatureValuesMapPrototype>)
|
|
{
|
|
m_parent_rule->clear_caches();
|
|
}
|
|
|
|
OrderedHashMap<FlyString, Vector<u32>> CSSFontFeatureValuesMap::to_ordered_hash_map() const
|
|
{
|
|
OrderedHashMap<FlyString, Vector<u32>> result;
|
|
|
|
for (auto const& entry : *m_map_entries) {
|
|
auto key = MUST(entry.key.to_utf16_string(vm())).to_utf8_but_should_be_ported_to_utf16();
|
|
|
|
auto const& array = as<JS::Array>(entry.value.as_object());
|
|
auto array_length = MUST(MUST(array.get(vm().names.length)).to_length(vm()));
|
|
|
|
Vector<u32> values;
|
|
values.ensure_capacity(array_length);
|
|
|
|
for (size_t i = 0; i < array_length; ++i)
|
|
values.append(MUST(array.get_without_side_effects(JS::PropertyKey { i }).to_u32(vm())));
|
|
|
|
result.set(key, values);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
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);
|
|
visitor.visit(m_parent_rule);
|
|
}
|
|
|
|
}
|