LibWeb/CSS: Take PropertyNameAndID in in style-only CSSSD methods

StylePropertyMap only ever works with style properties - never
descriptors. Switching `has_property()` and `get_property_style_value()`
to taking PropertyNameAndID skips some duplicate work.
This commit is contained in:
Sam Atkins 2025-09-26 12:08:54 +01:00
commit 2f02ccc5c1
Notes: github-actions[bot] 2025-10-02 12:47:49 +00:00
7 changed files with 36 additions and 73 deletions

View file

@ -8,7 +8,7 @@
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/StylePropertyMapReadOnlyPrototype.h>
#include <LibWeb/CSS/CSSStyleDeclaration.h>
#include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/PropertyNameAndID.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
@ -45,25 +45,23 @@ void StylePropertyMapReadOnly::visit_edges(Cell::Visitor& visitor)
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get
WebIDL::ExceptionOr<Variant<GC::Ref<CSSStyleValue>, Empty>> StylePropertyMapReadOnly::get(String property)
WebIDL::ExceptionOr<Variant<GC::Ref<CSSStyleValue>, Empty>> StylePropertyMapReadOnly::get(String property_name)
{
// The get(property) method, when called on a StylePropertyMapReadOnly 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)) };
auto property = PropertyNameAndID::from_name(property_name);
if (!property.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property_name)) };
// 3. Let props be the value of thiss [[declarations]] internal slot.
auto& props = m_declarations;
// 4. If props[property] exists, subdivide into iterations props[property], then reify the first item of the result and return it.
if (auto property_value = get_style_value(props, property)) {
if (auto property_value = get_style_value(props, property.value())) {
// FIXME: Subdivide into iterations, and only reify/return the first.
return property_value->reify(realm(), property);
return property_value->reify(realm(), property->name());
}
// 5. Otherwise, return undefined.
@ -71,25 +69,23 @@ WebIDL::ExceptionOr<Variant<GC::Ref<CSSStyleValue>, Empty>> StylePropertyMapRead
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall
WebIDL::ExceptionOr<Vector<GC::Ref<CSSStyleValue>>> StylePropertyMapReadOnly::get_all(String property)
WebIDL::ExceptionOr<Vector<GC::Ref<CSSStyleValue>>> StylePropertyMapReadOnly::get_all(String property_name)
{
// The getAll(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)) };
auto property = PropertyNameAndID::from_name(property_name);
if (!property.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property_name)) };
// 3. Let props be the value of thiss [[declarations]] internal slot.
auto& props = m_declarations;
// 4. If props[property] exists, subdivide into iterations props[property], then reify each item of the result, and return the list.
if (auto property_value = get_style_value(props, property)) {
if (auto property_value = get_style_value(props, property.value())) {
// FIXME: Subdivide into iterations.
return Vector { property_value->reify(realm(), property) };
return Vector { property_value->reify(realm(), property->name()) };
}
// 5. Otherwise, return an empty list.
@ -97,17 +93,15 @@ WebIDL::ExceptionOr<Vector<GC::Ref<CSSStyleValue>>> StylePropertyMapReadOnly::ge
}
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-has
WebIDL::ExceptionOr<bool> StylePropertyMapReadOnly::has(String property)
WebIDL::ExceptionOr<bool> StylePropertyMapReadOnly::has(String property_name)
{
// The has(property) method, when called on a StylePropertyMapReadOnly 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)) };
auto property = PropertyNameAndID::from_name(property_name);
if (!property.has_value())
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("'{}' is not a valid CSS property", property_name)) };
// 3. Let props be the value of thiss [[declarations]] internal slot.
auto& props = m_declarations;
@ -119,20 +113,17 @@ WebIDL::ExceptionOr<bool> StylePropertyMapReadOnly::has(String property)
// "the name and computed value of every longhand CSS property supported by the User Agent, every
// registered custom property, and every non-registered custom property which is not set to its initial
// value on this"
auto property_id = property_id_from_string(property);
if (!property_id.has_value())
return false;
// Ensure style is computed on the element before we try to read it, so we can check custom properties.
element.document().update_style();
if (property_id == PropertyID::Custom) {
if (element.get_custom_property(property))
if (property->is_custom_property()) {
if (element.get_custom_property(property->name()))
return true;
return element.document().registered_custom_properties().contains(property);
return element.document().registered_custom_properties().contains(property->name());
}
return true;
},
[&property](GC::Ref<CSSStyleDeclaration>& declaration) {
return declaration->has_property(property);
return declaration->has_property(property.value());
});
}
@ -164,7 +155,7 @@ WebIDL::UnsignedLong StylePropertyMapReadOnly::size() const
[](GC::Ref<CSSStyleDeclaration> const& declaration) { return declaration->length(); });
}
RefPtr<StyleValue const> StylePropertyMapReadOnly::get_style_value(Source& source, String property)
RefPtr<StyleValue const> StylePropertyMapReadOnly::get_style_value(Source& source, PropertyNameAndID const& property)
{
return source.visit(
[&property](DOM::AbstractElement& element) -> RefPtr<StyleValue const> {
@ -172,23 +163,20 @@ RefPtr<StyleValue const> StylePropertyMapReadOnly::get_style_value(Source& sourc
// "the name and computed value of every longhand CSS property supported by the User Agent, every
// registered custom property, and every non-registered custom property which is not set to its initial
// value on this"
auto property_id = property_id_from_string(property);
if (!property_id.has_value())
return nullptr;
// Ensure style is computed on the element before we try to read it.
element.document().update_style();
if (property_id == PropertyID::Custom) {
if (auto custom_property = element.get_custom_property(property))
if (property.is_custom_property()) {
if (auto custom_property = element.get_custom_property(property.name()))
return custom_property;
if (auto registered_custom_property = element.document().registered_custom_properties().get(property); registered_custom_property.has_value())
if (auto registered_custom_property = element.document().registered_custom_properties().get(property.name()); registered_custom_property.has_value())
return registered_custom_property.value()->initial_style_value();
return nullptr;
}
if (*property_id >= first_longhand_property_id && *property_id <= last_longhand_property_id) {
if (property.id() >= first_longhand_property_id && property.id() <= last_longhand_property_id) {
// FIXME: This will only ever be null for pseudo-elements. What should we do in that case?
if (auto computed_properties = element.computed_properties())
return computed_properties->property(property_id.value());
return computed_properties->property(property.id());
}
return nullptr;