LibWeb/CSS: Implement Element.computedStyleMap()

Currently the map doesn't return any values, so it's not very useful,
but this does make a few tests pass just by existing. :^)
This commit is contained in:
Sam Atkins 2025-08-11 14:27:07 +01:00
commit c768cc7208
Notes: github-actions[bot] 2025-08-13 09:16:04 +00:00
9 changed files with 62 additions and 12 deletions

View file

@ -10,3 +10,8 @@ interface StylePropertyMapReadOnly {
boolean has(USVString property); boolean has(USVString property);
readonly attribute unsigned long size; readonly attribute unsigned long size;
}; };
// https://drafts.css-houdini.org/css-typed-om-1/#computed-stylepropertymapreadonly-objects
partial interface Element {
[SameObject] StylePropertyMapReadOnly computedStyleMap();
};

View file

@ -122,6 +122,7 @@ void Element::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_custom_state_set); visitor.visit(m_custom_state_set);
visitor.visit(m_cascaded_properties); visitor.visit(m_cascaded_properties);
visitor.visit(m_computed_properties); visitor.visit(m_computed_properties);
visitor.visit(m_computed_style_map_cache);
if (m_pseudo_element_data) { if (m_pseudo_element_data) {
for (auto& pseudo_element : *m_pseudo_element_data) { for (auto& pseudo_element : *m_pseudo_element_data) {
visitor.visit(pseudo_element.value); visitor.visit(pseudo_element.value);
@ -4096,4 +4097,27 @@ void Element::set_had_duplicate_attribute_during_tokenization(Badge<HTML::HTMLPa
m_had_duplicate_attribute_during_tokenization = true; m_had_duplicate_attribute_during_tokenization = true;
} }
// https://drafts.css-houdini.org/css-typed-om-1/#dom-element-computedstylemap
GC::Ref<CSS::StylePropertyMapReadOnly> Element::computed_style_map()
{
// The computedStyleMap() method must, when called on an Element this, perform the following steps:
// 1. If thiss [[computedStyleMapCache]] internal slot is set to null, set its value to a new
// StylePropertyMapReadOnly object, whose [[declarations]] internal slot are 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, in the standard order.
//
// The computed values in the [[declarations]] of this object must remain up-to-date, changing as style
// resolution changes the properties on this and how theyre computed.
//
// NOTE: In practice, since the values are "hidden" behind a .get() method call, UAs can delay computing anything
// until a given property is actually requested.
if (m_computed_style_map_cache == nullptr) {
m_computed_style_map_cache = CSS::StylePropertyMapReadOnly::create_computed_style(realm(), AbstractElement { *this });
}
// 2. Return thiss [[computedStyleMapCache]] internal slot.
return *m_computed_style_map_cache;
}
} }

View file

@ -19,6 +19,7 @@
#include <LibWeb/CSS/Selector.h> #include <LibWeb/CSS/Selector.h>
#include <LibWeb/CSS/StyleInvalidation.h> #include <LibWeb/CSS/StyleInvalidation.h>
#include <LibWeb/CSS/StyleProperty.h> #include <LibWeb/CSS/StyleProperty.h>
#include <LibWeb/CSS/StylePropertyMapReadOnly.h>
#include <LibWeb/DOM/ChildNode.h> #include <LibWeb/DOM/ChildNode.h>
#include <LibWeb/DOM/NonDocumentTypeChildNode.h> #include <LibWeb/DOM/NonDocumentTypeChildNode.h>
#include <LibWeb/DOM/ParentNode.h> #include <LibWeb/DOM/ParentNode.h>
@ -521,6 +522,8 @@ public:
void set_had_duplicate_attribute_during_tokenization(Badge<HTML::HTMLParser>); void set_had_duplicate_attribute_during_tokenization(Badge<HTML::HTMLParser>);
bool had_duplicate_attribute_during_tokenization() const { return m_had_duplicate_attribute_during_tokenization; } bool had_duplicate_attribute_during_tokenization() const { return m_had_duplicate_attribute_during_tokenization; }
GC::Ref<CSS::StylePropertyMapReadOnly> computed_style_map();
protected: protected:
Element(Document&, DOM::QualifiedName); Element(Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override; virtual void initialize(JS::Realm&) override;
@ -603,6 +606,11 @@ private:
// Element objects have an internal [[RegisteredIntersectionObservers]] slot, which is initialized to an empty list. // Element objects have an internal [[RegisteredIntersectionObservers]] slot, which is initialized to an empty list.
OwnPtr<Vector<IntersectionObserver::IntersectionObserverRegistration>> m_registered_intersection_observers; OwnPtr<Vector<IntersectionObserver::IntersectionObserverRegistration>> m_registered_intersection_observers;
// https://drafts.css-houdini.org/css-typed-om-1/#dom-element-computedstylemapcache-slot
// Every Element has a [[computedStyleMapCache]] internal slot, initially set to null, which caches the result of
// the computedStyleMap() method when it is first called.
GC::Ptr<CSS::StylePropertyMapReadOnly> m_computed_style_map_cache;
CSSPixelPoint m_scroll_offset; CSSPixelPoint m_scroll_offset;
bool m_in_top_layer : 1 { false }; bool m_in_top_layer : 1 { false };

View file

@ -1,5 +1,6 @@
#import <Animations/Animatable.idl> #import <Animations/Animatable.idl>
#import <ARIA/ARIAMixin.idl> #import <ARIA/ARIAMixin.idl>
#import <CSS/StylePropertyMapReadOnly.idl>
#import <DOM/Attr.idl> #import <DOM/Attr.idl>
#import <DOM/ChildNode.idl> #import <DOM/ChildNode.idl>
#import <DOM/DOMTokenList.idl> #import <DOM/DOMTokenList.idl>

View file

@ -1,3 +1,12 @@
Harness status: Error Harness status: OK
Found 0 tests Found 7 tests
7 Fail
Fail Computed StylePropertyMap contains every CSS property
Fail Computed StylePropertyMap contains CSS property declarations in style rules
Fail Computed StylePropertyMap contains custom property declarations in style rules
Fail Computed StylePropertyMap contains CSS property declarations in inline styles
Fail Computed StylePropertyMap contains custom property declarations in inline rules
Fail Computed StylePropertyMap contains computed values and not resolved values
Fail Computed StylePropertyMap is live

View file

@ -2,5 +2,5 @@ Harness status: OK
Found 1 tests Found 1 tests
1 Fail 1 Pass
Fail Calling StylePropertyMap.get with an unsupported property throws a TypeError Pass Calling StylePropertyMap.get with an unsupported property throws a TypeError

View file

@ -2,8 +2,9 @@ Harness status: OK
Found 6 tests Found 6 tests
6 Fail 1 Pass
Fail Getting a custom property not in the computed style returns undefined 5 Fail
Pass Getting a custom property not in the computed style returns undefined
Fail Getting a valid property from computed style returns the correct entry Fail Getting a valid property from computed style returns the correct entry
Fail Getting a valid custom property from computed style returns the correct entry Fail Getting a valid custom property from computed style returns the correct entry
Fail Getting a list-valued property from computed style returns only the first value Fail Getting a list-valued property from computed style returns only the first value

View file

@ -2,9 +2,10 @@ Harness status: OK
Found 6 tests Found 6 tests
6 Fail 2 Pass
Fail Calling StylePropertyMap.getAll with an unsupported property throws a TypeError 4 Fail
Fail Calling StylePropertyMap.getAll with a custom property not in the property model returns an empty list Pass Calling StylePropertyMap.getAll with an unsupported property throws a TypeError
Pass Calling StylePropertyMap.getAll with a custom property not in the property model returns an empty list
Fail Calling StylePropertyMap.getAll with a valid property returns a single element list with the correct entry Fail Calling StylePropertyMap.getAll with a valid property returns a single element list with the correct entry
Fail StylePropertyMap.getAll is case-insensitive Fail StylePropertyMap.getAll is case-insensitive
Fail Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry Fail Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry

View file

@ -2,9 +2,10 @@ Harness status: OK
Found 7 tests Found 7 tests
7 Fail 2 Pass
Fail Calling StylePropertyMap.has with an unsupported property throws a TypeError 5 Fail
Fail Calling StylePropertyMap.has with a custom property not in the property model returns false Pass Calling StylePropertyMap.has with an unsupported property throws a TypeError
Pass Calling StylePropertyMap.has with a custom property not in the property model returns false
Fail Calling StylePropertyMap.has with a valid property returns true Fail Calling StylePropertyMap.has with a valid property returns true
Fail Calling StylePropertyMap.has with a valid property in mixed case returns true Fail Calling StylePropertyMap.has with a valid property in mixed case returns true
Fail Calling StylePropertyMap.has with a valid shorthand property returns true Fail Calling StylePropertyMap.has with a valid shorthand property returns true