diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 67d9ff8df2a..5c1d1f1c7fb 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -186,6 +186,7 @@ set(SOURCES CSS/StyleInvalidation.cpp CSS/StyleInvalidationData.cpp CSS/StyleProperty.cpp + CSS/StylePropertyMapReadOnly.cpp CSS/StyleSheet.cpp CSS/StyleSheetIdentifier.cpp CSS/StyleSheetList.cpp diff --git a/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.cpp b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.cpp new file mode 100644 index 00000000000..8e2291fcc14 --- /dev/null +++ b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "StylePropertyMapReadOnly.h" +#include +#include +#include +#include +#include + +namespace Web::CSS { + +GC_DEFINE_ALLOCATOR(StylePropertyMapReadOnly); + +GC::Ref StylePropertyMapReadOnly::create_computed_style(JS::Realm& realm, DOM::AbstractElement element) +{ + return realm.create(realm, element); +} + +StylePropertyMapReadOnly::StylePropertyMapReadOnly(JS::Realm& realm, Optional element) + : Bindings::PlatformObject(realm) + , m_source_element(move(element)) +{ +} + +StylePropertyMapReadOnly::StylePropertyMapReadOnly(JS::Realm& realm, GC::Ref declaration) + : Bindings::PlatformObject(realm) + , m_source_declaration(declaration) +{ +} + +StylePropertyMapReadOnly::~StylePropertyMapReadOnly() = default; + +void StylePropertyMapReadOnly::initialize(JS::Realm& realm) +{ + WEB_SET_PROTOTYPE_FOR_INTERFACE(StylePropertyMapReadOnly); + Base::initialize(realm); +} + +void StylePropertyMapReadOnly::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + + visitor.visit(m_source_declaration); + if (m_source_element.has_value()) + m_source_element->visit(visitor); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-get +WebIDL::ExceptionOr, Empty>> StylePropertyMapReadOnly::get(String property) +{ + // 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)) }; + + // 3. Let props be the value of this’s [[declarations]] internal slot. + auto& props = m_declarations; + + // FIXME: 4. If props[property] exists, subdivide into iterations props[property], then reify the first item of the result and return it. + (void)props; + + // 5. Otherwise, return undefined. + return Empty {}; +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall +WebIDL::ExceptionOr>> StylePropertyMapReadOnly::get_all(String property) +{ + // 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)) }; + + // 3. Let props be the value of this’s [[declarations]] internal slot. + auto& props = m_declarations; + + // FIXME: 4. If props[property] exists, subdivide into iterations props[property], then reify each item of the result, and return the list. + (void)props; + + // 5. Otherwise, return an empty list. + return Vector> {}; +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-has +WebIDL::ExceptionOr StylePropertyMapReadOnly::has(String property) +{ + // 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)) }; + + // 3. Let props be the value of this’s [[declarations]] internal slot. + auto& props = m_declarations; + + // 4. If props[property] exists, return true. Otherwise, return false. + return props.contains(property); +} + +// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-size +WebIDL::UnsignedLong StylePropertyMapReadOnly::size() const +{ + // The size attribute, on getting from a StylePropertyMapReadOnly this, must perform the following steps: + + // 1. Return the size of the value of this’s [[declarations]] internal slot. + return m_declarations.size(); +} + +} diff --git a/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.h b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.h new file mode 100644 index 00000000000..8b0e5ab3041 --- /dev/null +++ b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::CSS { + +// https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymapreadonly +class StylePropertyMapReadOnly : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(StylePropertyMapReadOnly, Bindings::PlatformObject); + GC_DECLARE_ALLOCATOR(StylePropertyMapReadOnly); + +public: + [[nodiscard]] static GC::Ref create_computed_style(JS::Realm&, DOM::AbstractElement); + + virtual ~StylePropertyMapReadOnly() override; + + WebIDL::ExceptionOr, Empty>> get(String property); + WebIDL::ExceptionOr>> get_all(String property); + WebIDL::ExceptionOr has(String property); + WebIDL::UnsignedLong size() const; + +protected: + explicit StylePropertyMapReadOnly(JS::Realm&, GC::Ref); + explicit StylePropertyMapReadOnly(JS::Realm&, Optional = {}); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Cell::Visitor&) override; + + Optional m_source_element; + GC::Ptr m_source_declaration; + + // https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-declarations-slot + // A StylePropertyMapReadOnly object has a [[declarations]] internal slot, which is a map reflecting the CSS + // declaration block’s declarations. + HashMap> m_declarations; +}; + +} diff --git a/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.idl b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.idl new file mode 100644 index 00000000000..4c43062edd7 --- /dev/null +++ b/Libraries/LibWeb/CSS/StylePropertyMapReadOnly.idl @@ -0,0 +1,12 @@ +#import + +// https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymapreadonly +// FIXME: [Exposed=(Window, Worker, PaintWorklet, LayoutWorklet)] +[Exposed=(Window, Worker)] +interface StylePropertyMapReadOnly { + // FIXME: iterable>; + (undefined or CSSStyleValue) get(USVString property); + sequence getAll(USVString property); + boolean has(USVString property); + readonly attribute unsigned long size; +}; diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 8ea7d73a871..04aa34d4be2 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -223,6 +223,7 @@ class ColorMixStyleValue; class ColorSchemeStyleValue; class ColorFunctionStyleValue; class ColorStyleValue; +class ComputedProperties; class ConicGradientStyleValue; class ContentStyleValue; class CounterDefinitionsStyleValue; @@ -336,7 +337,7 @@ class Size; class ScrollbarColorStyleValue; class StringStyleValue; class StyleComputer; -class ComputedProperties; +class StylePropertyMapReadOnly; class StyleSheet; class StyleSheetList; class StyleValue; diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake index 00f778e254c..534111cb6e3 100644 --- a/Libraries/LibWeb/idl_files.cmake +++ b/Libraries/LibWeb/idl_files.cmake @@ -58,6 +58,7 @@ libweb_js_bindings(CSS/MediaQueryList) libweb_js_bindings(CSS/MediaQueryListEvent) libweb_js_bindings(CSS/Screen) libweb_js_bindings(CSS/ScreenOrientation) +libweb_js_bindings(CSS/StylePropertyMapReadOnly) libweb_js_bindings(CSS/StyleSheet) libweb_js_bindings(CSS/StyleSheetList) libweb_js_bindings(CSS/TransitionEvent) diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index cda81dbfdba..a6b89b5da10 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -409,6 +409,7 @@ Storage StorageEvent StorageManager String +StylePropertyMapReadOnly StyleSheet StyleSheetList SubmitEvent