From 50d64b0fb730b16d6cdc81ccb1efae567e4f9914 Mon Sep 17 00:00:00 2001 From: Alex Ungurianu Date: Thu, 17 Oct 2024 23:28:09 +0100 Subject: [PATCH] LibWeb: Add and implement `CSSPropertyRule` IDL and bindings --- .../Userland/Libraries/LibWeb/CSS/BUILD.gn | 1 + .../Userland/Libraries/LibWeb/idl_files.gni | 1 + .../Text/expected/all-window-properties.txt | 1 + Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../Libraries/LibWeb/CSS/CSSPropertyRule.cpp | 76 +++++++++++++++++++ .../Libraries/LibWeb/CSS/CSSPropertyRule.h | 50 ++++++++++++ .../Libraries/LibWeb/CSS/CSSPropertyRule.idl | 11 +++ Userland/Libraries/LibWeb/CSS/CSSRule.cpp | 1 + Userland/Libraries/LibWeb/CSS/CSSRule.h | 1 + Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp | 2 + .../Libraries/LibWeb/CSS/StyleComputer.cpp | 1 + Userland/Libraries/LibWeb/Dump.cpp | 12 ++- Userland/Libraries/LibWeb/Dump.h | 1 + Userland/Libraries/LibWeb/Forward.h | 1 + Userland/Libraries/LibWeb/idl_files.cmake | 1 + 15 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/CSS/CSSPropertyRule.cpp create mode 100644 Userland/Libraries/LibWeb/CSS/CSSPropertyRule.h create mode 100644 Userland/Libraries/LibWeb/CSS/CSSPropertyRule.idl diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/CSS/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWeb/CSS/BUILD.gn index 8bc0c80dc3c..11d7d1c33da 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/CSS/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/CSS/BUILD.gn @@ -22,6 +22,7 @@ source_set("CSS") { "CSSMediaRule.cpp", "CSSNamespaceRule.cpp", "CSSNumericType.cpp", + "CSSPropertyRule.cpp", "CSSRule.cpp", "CSSRuleList.cpp", "CSSStyleDeclaration.cpp", diff --git a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni index af50c3a93f7..f624914d688 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni +++ b/Meta/gn/secondary/Userland/Libraries/LibWeb/idl_files.gni @@ -45,6 +45,7 @@ standard_idl_files = [ "//Userland/Libraries/LibWeb/CSS/CSSLayerStatementRule.idl", "//Userland/Libraries/LibWeb/CSS/CSSMediaRule.idl", "//Userland/Libraries/LibWeb/CSS/CSSNamespaceRule.idl", + "//Userland/Libraries/LibWeb/CSS/CSSPropertyRule.idl", "//Userland/Libraries/LibWeb/CSS/CSSRule.idl", "//Userland/Libraries/LibWeb/CSS/CSSRuleList.idl", "//Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.idl", diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 97f1c98cb87..679165321ff 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -44,6 +44,7 @@ CSSLayerStatementRule CSSMediaRule CSSNamespaceRule CSSNestedDeclarations +CSSPropertyRule CSSRule CSSRuleList CSSStyleDeclaration diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 894238c0fad..dca6a1c41fd 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -50,6 +50,7 @@ set(SOURCES CSS/CSSNestedDeclarations.cpp CSS/CSSNumericType.cpp CSS/CSSNamespaceRule.cpp + CSS/CSSPropertyRule.cpp CSS/CSSRule.cpp CSS/CSSRuleList.cpp CSS/CSSStyleDeclaration.cpp diff --git a/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.cpp b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.cpp new file mode 100644 index 00000000000..28a4a7d64df --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, Alex Ungurianu + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::CSS { + +JS_DEFINE_ALLOCATOR(CSSPropertyRule); + +JS::NonnullGCPtr CSSPropertyRule::create(JS::Realm& realm, FlyString name, FlyString syntax, bool inherits, Optional initial_value) +{ + return realm.heap().allocate(realm, realm, move(name), move(syntax), inherits, move(initial_value)); +} + +CSSPropertyRule::CSSPropertyRule(JS::Realm& realm, FlyString name, FlyString syntax, bool inherits, Optional initial_value) + : CSSRule(realm) + , m_name(move(name)) + , m_syntax(move(syntax)) + , m_inherits(inherits) + , m_initial_value(move(initial_value)) +{ +} + +void CSSPropertyRule::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSPropertyRule); +} + +// https://www.w3.org/TR/cssom-1/#serialize-a-css-rule +String CSSPropertyRule::serialized() const +{ + StringBuilder builder; + + // Serialization algorithm is defined in the spec below + // https://drafts.css-houdini.org/css-properties-values-api/#the-css-property-rule-interface + + // To serialize a CSSPropertyRule, return the concatenation of the following: + + // 1. The string "@property" followed by a single SPACE (U+0020). + // 2. The result of performing serialize an identifier on the rule’s name, followed by a single SPACE (U+0020). + builder.appendff("@property {} ", serialize_an_identifier(name())); + + // 3. The string "{ ", i.e., a single LEFT CURLY BRACKET (U+007B), followed by a SPACE (U+0020). + builder.append("{ "sv); + + // 4. The string "syntax:", followed by a single SPACE (U+0020). + // 5. The result of performing serialize a string on the rule’s syntax, followed by a single SEMICOLON (U+003B), followed by a SPACE (U+0020). + builder.appendff("syntax: {}; ", serialize_a_string(syntax())); + + // 6. The string "inherits:", followed by a single SPACE (U+0020). + // 7. For the rule’s inherits attribute, one of the following depending on the attribute’s value: + // true: The string "true" followed by a single SEMICOLON (U+003B), followed by a SPACE (U+0020). + // false: The string "false" followed by a single SEMICOLON (U+003B), followed by a SPACE (U+0020). + builder.appendff("inherits: {}; ", inherits()); + + // 8. If the rule’s initial-value is present, follow these substeps: + if (initial_value().has_value()) { + // 1. The string "initial-value:". + // 2. The result of performing serialize a CSS value in the rule’s initial-value followed by a single SEMICOLON (U+003B), followed by a SPACE (U+0020). + // FIXME: Follow the spec for serializing the value whenever we actually have a CSS value here. + builder.appendff("initial-value: {}; ", initial_value()); + } + // 9. A single RIGHT CURLY BRACKET (U+007D). + builder.append("}"sv); + + return MUST(builder.to_string()); +} + +} diff --git a/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.h b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.h new file mode 100644 index 00000000000..bfe4d2baa2c --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Alex Ungurianu + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +// https://drafts.css-houdini.org/css-properties-values-api/#the-css-property-rule-interface +class CSSPropertyRule final : public CSSRule { + WEB_PLATFORM_OBJECT(CSSPropertyRule, CSSRule); + JS_DECLARE_ALLOCATOR(CSSPropertyRule); + +public: + static JS::NonnullGCPtr create(JS::Realm&, FlyString name, FlyString syntax, bool inherits, Optional initial_value); + + virtual ~CSSPropertyRule() = default; + + virtual Type type() const override { return Type::Property; } + FlyString const& name() const { return m_name; } + FlyString const& syntax() const { return m_syntax; } + bool inherits() const { return m_inherits; } + Optional initial_value() const { return m_initial_value; } + +private: + CSSPropertyRule(JS::Realm&, FlyString name, FlyString syntax, bool inherits, Optional initial_value); + + virtual void initialize(JS::Realm&) override; + virtual String serialized() const override; + + FlyString m_name; + FlyString m_syntax; + bool m_inherits; + // FIXME: This should hold an actual CSS value, matching the syntax + Optional m_initial_value; +}; + +template<> +inline bool CSSRule::fast_is() const { return type() == CSSRule::Type::Property; } + +} diff --git a/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.idl b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.idl new file mode 100644 index 00000000000..fcb2c9bac8f --- /dev/null +++ b/Userland/Libraries/LibWeb/CSS/CSSPropertyRule.idl @@ -0,0 +1,11 @@ +#import + +// https://drafts.css-houdini.org/css-properties-values-api/#the-css-property-rule-interface +[Exposed=Window] +interface CSSPropertyRule : CSSRule { + readonly attribute CSSOMString name; + readonly attribute CSSOMString syntax; + readonly attribute boolean inherits; + readonly attribute CSSOMString? initialValue; + +}; diff --git a/Userland/Libraries/LibWeb/CSS/CSSRule.cpp b/Userland/Libraries/LibWeb/CSS/CSSRule.cpp index 653b8a0a1c1..35f2d5b4bf2 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSRule.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSRule.cpp @@ -81,6 +81,7 @@ FlyString const& CSSRule::parent_layer_internal_qualified_name_slow_case() const case Type::Namespace: case Type::Supports: case Type::NestedDeclarations: + case Type::Property: break; } } diff --git a/Userland/Libraries/LibWeb/CSS/CSSRule.h b/Userland/Libraries/LibWeb/CSS/CSSRule.h index c84527f35a2..3adb6a5e751 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSRule.h +++ b/Userland/Libraries/LibWeb/CSS/CSSRule.h @@ -35,6 +35,7 @@ public: LayerBlock = 100, LayerStatement = 101, NestedDeclarations = 102, + Property = 103, // FIXME: This should return `0` as a type, but type is used for a lot of dispatching }; virtual Type type() const = 0; diff --git a/Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp b/Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp index 4f21ce1d6a6..e9a62093384 100644 --- a/Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp +++ b/Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp @@ -146,6 +146,7 @@ void CSSRuleList::for_each_effective_rule(TraversalOrder order, Function #include #include +#include #include #include #include @@ -651,6 +652,9 @@ void dump_rule(StringBuilder& builder, CSS::CSSRule const& rule, int indent_leve case CSS::CSSRule::Type::Supports: dump_supports_rule(builder, verify_cast(rule), indent_levels); break; + case CSS::CSSRule::Type::Property: + dump_property_rule(builder, verify_cast(rule), indent_levels); + break; } } @@ -804,6 +808,13 @@ void dump_declaration(StringBuilder& builder, CSS::PropertyOwningCSSStyleDeclara } } +void dump_property_rule(StringBuilder& builder, CSS::CSSPropertyRule const& property, int indent_levels) +{ + (void)builder; + (void)property; + (void)indent_levels; +} + void dump_style_rule(StringBuilder& builder, CSS::CSSStyleRule const& rule, int indent_levels) { for (auto& selector : rule.selectors()) { @@ -903,5 +914,4 @@ void dump_nested_declarations(StringBuilder& builder, CSS::CSSNestedDeclarations builder.append(" Nested declarations:\n"sv); dump_declaration(builder, declarations.declaration(), indent_levels + 1); } - } diff --git a/Userland/Libraries/LibWeb/Dump.h b/Userland/Libraries/LibWeb/Dump.h index 3fa875261e8..99c6c8ad022 100644 --- a/Userland/Libraries/LibWeb/Dump.h +++ b/Userland/Libraries/LibWeb/Dump.h @@ -30,6 +30,7 @@ void dump_import_rule(StringBuilder&, CSS::CSSImportRule const&, int indent_leve void dump_media_rule(StringBuilder&, CSS::CSSMediaRule const&, int indent_levels = 0); void dump_style_rule(StringBuilder&, CSS::CSSStyleRule const&, int indent_levels = 0); void dump_supports_rule(StringBuilder&, CSS::CSSSupportsRule const&, int indent_levels = 0); +void dump_property_rule(StringBuilder&, CSS::CSSPropertyRule const&, int indent_levels = 0); void dump_namespace_rule(StringBuilder&, CSS::CSSNamespaceRule const&, int indent_levels = 0); void dump_nested_declarations(StringBuilder&, CSS::CSSNestedDeclarations const&, int indent_levels = 0); void dump_layer_block_rule(StringBuilder&, CSS::CSSLayerBlockRule const&, int indent_levels = 0); diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index b343d630fbd..6392ad692c3 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -131,6 +131,7 @@ class CSSMediaRule; class CSSNestedDeclarations; class CSSOKLab; class CSSOKLCH; +class CSSPropertyRule; class CSSRGB; class CSSRule; class CSSRuleList; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index e7cc62c322a..5cfb595e3fb 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -26,6 +26,7 @@ libweb_js_bindings(CSS/CSSMediaRule) libweb_js_bindings(CSS/CSS NAMESPACE) libweb_js_bindings(CSS/CSSNamespaceRule) libweb_js_bindings(CSS/CSSNestedDeclarations) +libweb_js_bindings(CSS/CSSPropertyRule) libweb_js_bindings(CSS/CSSRule) libweb_js_bindings(CSS/CSSRuleList) libweb_js_bindings(CSS/CSSStyleDeclaration)