瀏覽代碼

LibWeb: Implement CSSRule.parentRule and .parentStyleSheet

Both of these are supposed to be set when the CSSRule is created. The
spec is silent on setting it when a CSSRule is added to a parent. So,
this is a bit ad-hoc.

The parent rule gets set whenever a rule is added to a new parent. The
parent stylesheet gets set whenever the rule or one of its ancestors is
added to a different stylesheet. There may be some nuance there that
I'm missing, but I'm sure we'll find out quickly once we have WPT
running!
Sam Atkins 3 年之前
父節點
當前提交
c718ba5947

+ 17 - 7
Userland/Libraries/LibWeb/CSS/CSSGroupingRule.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
+ * Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
@@ -12,18 +12,21 @@ namespace Web::CSS {
 CSSGroupingRule::CSSGroupingRule(NonnullRefPtrVector<CSSRule>&& rules)
 CSSGroupingRule::CSSGroupingRule(NonnullRefPtrVector<CSSRule>&& rules)
     : m_rules(CSSRuleList::create(move(rules)))
     : m_rules(CSSRuleList::create(move(rules)))
 {
 {
+    for (auto& rule : *m_rules)
+        rule.set_parent_rule(this);
 }
 }
 
 
-size_t CSSGroupingRule::insert_rule(StringView, size_t)
+DOM::ExceptionOr<u32> CSSGroupingRule::insert_rule(StringView rule, u32 index)
 {
 {
-    // https://www.w3.org/TR/cssom-1/#insert-a-css-rule
-    TODO();
+    TRY(m_rules->insert_a_css_rule(rule, index));
+    // NOTE: The spec doesn't say where to set the parent rule, so we'll do it here.
+    m_rules->item(index)->set_parent_rule(this);
+    return index;
 }
 }
 
 
-void CSSGroupingRule::delete_rule(size_t)
+DOM::ExceptionOr<void> CSSGroupingRule::delete_rule(u32 index)
 {
 {
-    // https://www.w3.org/TR/cssom-1/#remove-a-css-rule
-    TODO();
+    return m_rules->remove_a_css_rule(index);
 }
 }
 
 
 void CSSGroupingRule::for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const
 void CSSGroupingRule::for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const
@@ -31,4 +34,11 @@ void CSSGroupingRule::for_each_effective_style_rule(Function<void(CSSStyleRule c
     m_rules->for_each_effective_style_rule(callback);
     m_rules->for_each_effective_style_rule(callback);
 }
 }
 
 
+void CSSGroupingRule::set_parent_style_sheet(CSSStyleSheet* parent_style_sheet)
+{
+    CSSRule::set_parent_style_sheet(parent_style_sheet);
+    for (auto& rule : *m_rules)
+        rule.set_parent_style_sheet(parent_style_sheet);
+}
+
 }
 }

+ 4 - 2
Userland/Libraries/LibWeb/CSS/CSSGroupingRule.h

@@ -26,11 +26,13 @@ public:
     CSSRuleList const& css_rules() const { return m_rules; }
     CSSRuleList const& css_rules() const { return m_rules; }
     CSSRuleList& css_rules() { return m_rules; }
     CSSRuleList& css_rules() { return m_rules; }
     NonnullRefPtr<CSSRuleList> css_rules_for_bindings() { return m_rules; }
     NonnullRefPtr<CSSRuleList> css_rules_for_bindings() { return m_rules; }
-    size_t insert_rule(StringView rule, size_t index = 0);
-    void delete_rule(size_t index);
+    DOM::ExceptionOr<u32> insert_rule(StringView rule, u32 index = 0);
+    DOM::ExceptionOr<void> delete_rule(u32 index);
 
 
     virtual void for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const;
     virtual void for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const;
 
 
+    virtual void set_parent_style_sheet(CSSStyleSheet*) override;
+
 protected:
 protected:
     explicit CSSGroupingRule(NonnullRefPtrVector<CSSRule>&&);
     explicit CSSGroupingRule(NonnullRefPtrVector<CSSRule>&&);
 
 

+ 18 - 0
Userland/Libraries/LibWeb/CSS/CSSRule.cpp

@@ -1,10 +1,12 @@
 /*
 /*
  * Copyright (c) 2021, the SerenityOS developers.
  * Copyright (c) 2021, the SerenityOS developers.
+ * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
 #include <LibWeb/CSS/CSSRule.h>
 #include <LibWeb/CSS/CSSRule.h>
+#include <LibWeb/CSS/CSSStyleSheet.h>
 
 
 namespace Web::CSS {
 namespace Web::CSS {
 
 
@@ -21,4 +23,20 @@ void CSSRule::set_css_text(StringView)
     // On setting the cssText attribute must do nothing.
     // On setting the cssText attribute must do nothing.
 }
 }
 
 
+void CSSRule::set_parent_rule(CSSRule* parent_rule)
+{
+    if (parent_rule)
+        m_parent_rule = parent_rule->make_weak_ptr();
+    else
+        m_parent_rule = nullptr;
+}
+
+void CSSRule::set_parent_style_sheet(CSSStyleSheet* parent_style_sheet)
+{
+    if (parent_style_sheet)
+        m_parent_style_sheet = parent_style_sheet->make_weak_ptr();
+    else
+        m_parent_style_sheet = nullptr;
+}
+
 }
 }

+ 9 - 0
Userland/Libraries/LibWeb/CSS/CSSRule.h

@@ -39,11 +39,20 @@ public:
     String css_text() const;
     String css_text() const;
     void set_css_text(StringView);
     void set_css_text(StringView);
 
 
+    CSSRule* parent_rule() { return m_parent_rule; }
+    void set_parent_rule(CSSRule*);
+
+    CSSStyleSheet* parent_style_sheet() { return m_parent_style_sheet; }
+    virtual void set_parent_style_sheet(CSSStyleSheet*);
+
     template<typename T>
     template<typename T>
     bool fast_is() const = delete;
     bool fast_is() const = delete;
 
 
 protected:
 protected:
     virtual String serialized() const = 0;
     virtual String serialized() const = 0;
+
+    WeakPtr<CSSRule> m_parent_rule;
+    WeakPtr<CSSStyleSheet> m_parent_style_sheet;
 };
 };
 
 
 }
 }

+ 6 - 0
Userland/Libraries/LibWeb/CSS/CSSRule.idl

@@ -1,7 +1,13 @@
+#import <CSS/CSSStyleSheet.idl>
+
+[Exposed=Window]
 interface CSSRule {
 interface CSSRule {
 
 
     attribute CSSOMString cssText;
     attribute CSSOMString cssText;
 
 
+    readonly attribute CSSRule? parentRule;
+    readonly attribute CSSStyleSheet? parentStyleSheet;
+
     readonly attribute unsigned short type;
     readonly attribute unsigned short type;
 
 
     const unsigned short STYLE_RULE = 1;
     const unsigned short STYLE_RULE = 1;

+ 3 - 1
Userland/Libraries/LibWeb/CSS/CSSRuleList.cpp

@@ -80,7 +80,9 @@ DOM::ExceptionOr<void> CSSRuleList::remove_a_css_rule(u32 index)
     // 5. Remove rule old rule from list at the zero-indexed position index.
     // 5. Remove rule old rule from list at the zero-indexed position index.
     m_rules.remove(index);
     m_rules.remove(index);
 
 
-    // FIXME: 6. Set old rule’s parent CSS rule and parent CSS style sheet to null.
+    // 6. Set old rule’s parent CSS rule and parent CSS style sheet to null.
+    old_rule.set_parent_rule(nullptr);
+    old_rule.set_parent_style_sheet(nullptr);
 
 
     return {};
     return {};
 }
 }

+ 8 - 1
Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp

@@ -17,6 +17,9 @@ CSSStyleSheet::CSSStyleSheet(NonnullRefPtrVector<CSSRule> rules, Optional<AK::UR
 {
 {
     if (location.has_value())
     if (location.has_value())
         set_location(location->to_string());
         set_location(location->to_string());
+
+    for (auto& rule : *m_rules)
+        rule.set_parent_style_sheet(this);
 }
 }
 
 
 // https://www.w3.org/TR/cssom/#dom-cssstylesheet-insertrule
 // https://www.w3.org/TR/cssom/#dom-cssstylesheet-insertrule
@@ -36,9 +39,13 @@ DOM::ExceptionOr<unsigned> CSSStyleSheet::insert_rule(StringView rule, unsigned
     // FIXME: 5. If parsed rule is an @import rule, and the constructed flag is set, throw a SyntaxError DOMException.
     // FIXME: 5. If parsed rule is an @import rule, and the constructed flag is set, throw a SyntaxError DOMException.
 
 
     // 6. Return the result of invoking insert a CSS rule rule in the CSS rules at index.
     // 6. Return the result of invoking insert a CSS rule rule in the CSS rules at index.
-    auto result = m_rules->insert_a_css_rule(parsed_rule.release_nonnull(), index);
+    auto parsed_rule_nonnull = parsed_rule.release_nonnull();
+    auto result = m_rules->insert_a_css_rule(parsed_rule_nonnull, index);
 
 
     if (!result.is_exception()) {
     if (!result.is_exception()) {
+        // NOTE: The spec doesn't say where to set the parent style sheet, so we'll do it here.
+        parsed_rule_nonnull->set_parent_style_sheet(this);
+
         if (m_style_sheet_list) {
         if (m_style_sheet_list) {
             m_style_sheet_list->document().style_computer().invalidate_rule_cache();
             m_style_sheet_list->document().style_computer().invalidate_rule_cache();
             m_style_sheet_list->document().invalidate_style();
             m_style_sheet_list->document().invalidate_style();