mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-04 07:09:41 +00:00
After looking into this more, the `[[declarations]]` slot does not seem to need to be a literal map of property names and values. Instead, it can just point at the source (an element or style declaration), and then direct all read or write operations to that. This means the `has()` and `delete()` methods actually work now. A few remaining failures in these tests are because of: - StylePropertyMap[ReadOnly]s not being iterable yet - We're not populating an element's custom properties map, which get fixed whenever someone gets around to producing proper computed values of them.
149 lines
6.8 KiB
C++
149 lines
6.8 KiB
C++
/*
|
||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include "StylePropertyMap.h"
|
||
#include <LibWeb/Bindings/Intrinsics.h>
|
||
#include <LibWeb/Bindings/StylePropertyMapPrototype.h>
|
||
#include <LibWeb/CSS/CSSStyleDeclaration.h>
|
||
#include <LibWeb/CSS/PropertyName.h>
|
||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||
|
||
namespace Web::CSS {
|
||
|
||
GC_DEFINE_ALLOCATOR(StylePropertyMap);
|
||
|
||
GC::Ref<StylePropertyMap> StylePropertyMap::create(JS::Realm& realm, GC::Ref<CSSStyleDeclaration> declaration)
|
||
{
|
||
return realm.create<StylePropertyMap>(realm, declaration);
|
||
}
|
||
|
||
StylePropertyMap::StylePropertyMap(JS::Realm& realm, GC::Ref<CSSStyleDeclaration> declaration)
|
||
: StylePropertyMapReadOnly(realm, declaration)
|
||
{
|
||
}
|
||
|
||
StylePropertyMap::~StylePropertyMap() = default;
|
||
|
||
CSSStyleDeclaration& StylePropertyMap::declarations()
|
||
{
|
||
// Writable StylePropertyMaps must be backed by a CSSStyleDeclaration, not an AbstractElement.
|
||
return m_declarations.get<GC::Ref<CSSStyleDeclaration>>();
|
||
}
|
||
|
||
void StylePropertyMap::initialize(JS::Realm& realm)
|
||
{
|
||
WEB_SET_PROTOTYPE_FOR_INTERFACE(StylePropertyMap);
|
||
Base::initialize(realm);
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set
|
||
WebIDL::ExceptionOr<void> StylePropertyMap::set(String property, Vector<Variant<GC::Root<CSSStyleValue>, String>> values)
|
||
{
|
||
// The set(property, ...values) method, when called on a StylePropertyMap this, must perform the following steps:
|
||
|
||
// 1. If property is not a custom property name string, set property to property ASCII lowercased.
|
||
if (!is_a_custom_property_name_string(property))
|
||
property = property.to_ascii_lowercase();
|
||
|
||
// 2. If property is not a valid CSS property, throw a TypeError.
|
||
if (!is_a_valid_css_property(property))
|
||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property)) };
|
||
|
||
// FIXME: 3. If property is a single-valued property and values has more than one item, throw a TypeError.
|
||
|
||
// FIXME: 4. If any of the items in values have a non-null [[associatedProperty]] internal slot, and that slot’s value is anything other than property, throw a TypeError.
|
||
|
||
// FIXME: 5. If the size of values is two or more, and one or more of the items are a CSSUnparsedValue or CSSVariableReferenceValue object, throw a TypeError.
|
||
// NOTE: Having 2+ values implies that you’re setting multiple items of a list-valued property, but the presence of
|
||
// a var() function in the string-based OM disables all syntax parsing, including splitting into individual
|
||
// iterations (because there might be more commas inside of the var() value, so you can’t tell how many items
|
||
// are actually going to show up). This step’s restriction preserves the same semantics in the Typed OM.
|
||
|
||
// 6. Let props be the value of this’s [[declarations]] internal slot.
|
||
auto& props = declarations();
|
||
|
||
// 7. If props[property] exists, remove it.
|
||
TRY(props.remove_property(property));
|
||
|
||
// FIXME: 8. Let values to set be an empty list.
|
||
|
||
// FIXME: 9. For each value in values, create an internal representation for property and value, and append the result to values to set.
|
||
(void)values;
|
||
|
||
// FIXME: 10. Set props[property] to values to set.
|
||
// NOTE: The property is deleted then added back so that it gets put at the end of the ordered map, which gives the
|
||
// expected behavior in the face of shorthand properties.
|
||
|
||
return {};
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-append
|
||
WebIDL::ExceptionOr<void> StylePropertyMap::append(String property, Vector<Variant<GC::Root<CSSStyleValue>, String>> values)
|
||
{
|
||
// The append(property, ...values) method, when called on a StylePropertyMap this, must perform the following steps:
|
||
|
||
// 1. If property is not a custom property name string, set property to property ASCII lowercased.
|
||
if (!is_a_custom_property_name_string(property))
|
||
property = property.to_ascii_lowercase();
|
||
|
||
// 2. If property is not a valid CSS property, throw a TypeError.
|
||
if (!is_a_valid_css_property(property))
|
||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property)) };
|
||
|
||
// FIXME: 3. If property is not a list-valued property, throw a TypeError.
|
||
|
||
// FIXME: 4. If any of the items in values have a non-null [[associatedProperty]] internal slot, and that slot’s value is anything other than property, throw a TypeError.
|
||
|
||
// FIXME: 5. If any of the items in values are a CSSUnparsedValue or CSSVariableReferenceValue object, throw a TypeError.
|
||
|
||
// NOTE: When a property is set via string-based APIs, the presence of var() in a property prevents the entire thing from being interpreted. In other words, everything besides the var() is a plain component value, not a meaningful type. This step’s restriction preserves the same semantics in the Typed OM.
|
||
|
||
// 6. Let props be the value of this’s [[declarations]] internal slot.
|
||
auto& props = declarations();
|
||
|
||
// FIXME: 7. If props[property] does not exist, set props[property] to an empty list.
|
||
(void)props;
|
||
|
||
// FIXME: 8. If props[property] contains a var() reference, throw a TypeError.
|
||
|
||
// FIXME: 9. Let temp values be an empty list.
|
||
|
||
// FIXME: 10. For each value in values, create an internal representation with property and value, and append the returned value to temp values.
|
||
(void)values;
|
||
|
||
// FIXME: 11. Append the entries of temp values to props[property].
|
||
|
||
return {};
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-delete
|
||
WebIDL::ExceptionOr<void> StylePropertyMap::delete_(String property)
|
||
{
|
||
// The delete(property) method, when called on a StylePropertyMap this, must perform the following steps:
|
||
|
||
// 1. If property is not a custom property name string, set property to property ASCII lowercased.
|
||
if (!is_a_custom_property_name_string(property))
|
||
property = property.to_ascii_lowercase();
|
||
|
||
// 2. If property is not a valid CSS property, throw a TypeError.
|
||
if (!is_a_valid_css_property(property))
|
||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property)) };
|
||
|
||
// 3. If this’s [[declarations]] internal slot contains property, remove it.
|
||
TRY(declarations().remove_property(property));
|
||
return {};
|
||
}
|
||
|
||
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-clear
|
||
WebIDL::ExceptionOr<void> StylePropertyMap::clear()
|
||
{
|
||
// The clear() method, when called on a StylePropertyMap this, must perform the following steps:
|
||
|
||
// 1. Remove all of the declarations in this’s [[declarations]] internal slot.
|
||
return declarations().set_css_text(""sv);
|
||
}
|
||
|
||
}
|