diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index d398e48b9a..e42113cc83 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -135,6 +135,7 @@ set(SOURCES DOM/AbortSignal.cpp DOM/AbstractRange.cpp DOM/AccessibilityTreeNode.cpp + DOM/AdoptedStyleSheets.cpp DOM/Attr.cpp DOM/CDATASection.cpp DOM/CharacterData.cpp diff --git a/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.cpp b/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.cpp new file mode 100644 index 0000000000..3bd19a734e --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::DOM { + +JS::NonnullGCPtr create_adopted_style_sheets_list(Document& document) +{ + auto adopted_style_sheets = WebIDL::ObservableArray::create(document.realm()); + adopted_style_sheets->set_on_set_an_indexed_value_callback([&document](JS::Value& value) -> WebIDL::ExceptionOr { + auto& vm = document.vm(); + if (!value.is_object()) + return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet"); + auto& object = value.as_object(); + if (!is(object)) + return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet"); + auto& style_sheet = static_cast(object); + + // The set an indexed value algorithm for adoptedStyleSheets, given value and index, is the following: + // 1. If value’s constructed flag is not set, or its constructor document is not equal to this + // DocumentOrShadowRoot's node document, throw a "NotAllowedError" DOMException. + if (!style_sheet.constructed()) + return WebIDL::NotAllowedError::create(document.realm(), "StyleSheet's constructed flag is not set."_fly_string); + if (!style_sheet.constructed() || style_sheet.constructor_document().ptr() != &document) + return WebIDL::NotAllowedError::create(document.realm(), "Sharing a StyleSheet between documents is not allowed."_fly_string); + + document.style_computer().load_fonts_from_sheet(style_sheet); + document.style_computer().invalidate_rule_cache(); + document.invalidate_style(); + return {}; + }); + adopted_style_sheets->set_on_delete_an_indexed_value_callback([&document]() -> WebIDL::ExceptionOr { + document.style_computer().invalidate_rule_cache(); + document.invalidate_style(); + return {}; + }); + + return adopted_style_sheets; +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.h b/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.h new file mode 100644 index 0000000000..dbb21ab76c --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/AdoptedStyleSheets.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::DOM { + +JS::NonnullGCPtr create_adopted_style_sheets_list(Document& document); + +} diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index b4a782726a..485c3768e2 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -4564,40 +4565,6 @@ bool Document::has_skipped_resize_observations() return false; } -static JS::NonnullGCPtr create_adopted_style_sheets_list(Document& document) -{ - auto adopted_style_sheets = WebIDL::ObservableArray::create(document.realm()); - adopted_style_sheets->set_on_set_an_indexed_value_callback([&document](JS::Value& value) -> WebIDL::ExceptionOr { - auto& vm = document.vm(); - if (!value.is_object()) - return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet"); - auto& object = value.as_object(); - if (!is(object)) - return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet"); - auto& style_sheet = static_cast(object); - - // The set an indexed value algorithm for adoptedStyleSheets, given value and index, is the following: - // 1. If value’s constructed flag is not set, or its constructor document is not equal to this - // DocumentOrShadowRoot's node document, throw a "NotAllowedError" DOMException. - if (!style_sheet.constructed()) - return WebIDL::NotAllowedError::create(document.realm(), "StyleSheet's constructed flag is not set."_fly_string); - if (!style_sheet.constructed() || style_sheet.constructor_document().ptr() != &document) - return WebIDL::NotAllowedError::create(document.realm(), "Sharing a StyleSheet between documents is not allowed."_fly_string); - - document.style_computer().load_fonts_from_sheet(style_sheet); - document.style_computer().invalidate_rule_cache(); - document.invalidate_style(); - return {}; - }); - adopted_style_sheets->set_on_delete_an_indexed_value_callback([&document]() -> WebIDL::ExceptionOr { - document.style_computer().invalidate_rule_cache(); - document.invalidate_style(); - return {}; - }); - - return adopted_style_sheets; -} - JS::NonnullGCPtr Document::adopted_style_sheets() const { if (!m_adopted_style_sheets) diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl index c00419ea27..1846a3cf13 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.idl +++ b/Userland/Libraries/LibWeb/DOM/Document.idl @@ -4,6 +4,7 @@ #import #import #import +#import #import #import #import @@ -94,9 +95,6 @@ interface Document : Node { [CEReactions, NewObject] Node importNode(Node node, optional boolean deep = false); [CEReactions, ImplementedAs=adopt_node_binding] Node adoptNode(Node node); - [ImplementedAs=style_sheets_for_bindings] readonly attribute StyleSheetList styleSheets; - attribute any adoptedStyleSheets; - readonly attribute DOMString compatMode; readonly attribute DocumentType? doctype; @@ -141,3 +139,4 @@ dictionary ElementCreationOptions { }; Document includes ParentNode; Document includes GlobalEventHandlers; +Document includes DocumentOrShadowRoot; diff --git a/Userland/Libraries/LibWeb/DOM/DocumentOrShadowRoot.idl b/Userland/Libraries/LibWeb/DOM/DocumentOrShadowRoot.idl new file mode 100644 index 0000000000..aa08921b0c --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/DocumentOrShadowRoot.idl @@ -0,0 +1,8 @@ +#import + +// https://dom.spec.whatwg.org/#documentorshadowroot +interface mixin DocumentOrShadowRoot { + // https://w3c.github.io/csswg-drafts/cssom/#extensions-to-the-document-or-shadow-root-interface + [SameObject, ImplementedAs=style_sheets_for_bindings] readonly attribute StyleSheetList styleSheets; + attribute any adoptedStyleSheets; +}; diff --git a/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp b/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp index 08cf4a1cc9..8b7c255c95 100644 --- a/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp +++ b/Userland/Libraries/LibWeb/DOM/ShadowRoot.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -54,4 +55,47 @@ WebIDL::ExceptionOr ShadowRoot::set_inner_html(StringView markup) return {}; } +CSS::StyleSheetList& ShadowRoot::style_sheets() +{ + if (!m_style_sheets) + m_style_sheets = CSS::StyleSheetList::create(document()); + return *m_style_sheets; +} + +CSS::StyleSheetList const& ShadowRoot::style_sheets() const +{ + return const_cast(this)->style_sheets(); +} + +void ShadowRoot::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_style_sheets); + visitor.visit(m_adopted_style_sheets); +} + +JS::NonnullGCPtr ShadowRoot::adopted_style_sheets() const +{ + if (!m_adopted_style_sheets) + m_adopted_style_sheets = create_adopted_style_sheets_list(const_cast(document())); + return *m_adopted_style_sheets; +} + +WebIDL::ExceptionOr ShadowRoot::set_adopted_style_sheets(JS::Value new_value) +{ + if (!m_adopted_style_sheets) + m_adopted_style_sheets = create_adopted_style_sheets_list(const_cast(document())); + + m_adopted_style_sheets->clear(); + auto iterator_record = TRY(get_iterator(vm(), new_value, JS::IteratorHint::Sync)); + while (true) { + auto next = TRY(iterator_step_value(vm(), iterator_record)); + if (!next.has_value()) + break; + TRY(m_adopted_style_sheets->append(*next)); + } + + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/ShadowRoot.h b/Userland/Libraries/LibWeb/DOM/ShadowRoot.h index 17f3a52895..8aa0aa5706 100644 --- a/Userland/Libraries/LibWeb/DOM/ShadowRoot.h +++ b/Userland/Libraries/LibWeb/DOM/ShadowRoot.h @@ -8,6 +8,7 @@ #include #include +#include namespace Web::DOM { @@ -33,6 +34,17 @@ public: WebIDL::ExceptionOr inner_html() const; WebIDL::ExceptionOr set_inner_html(StringView); + CSS::StyleSheetList& style_sheets(); + CSS::StyleSheetList const& style_sheets() const; + + CSS::StyleSheetList* style_sheets_for_bindings() { return &style_sheets(); } + + JS::NonnullGCPtr adopted_style_sheets() const; + WebIDL::ExceptionOr set_adopted_style_sheets(JS::Value); + +protected: + virtual void visit_edges(Cell::Visitor&) override; + private: ShadowRoot(Document&, Element& host, Bindings::ShadowRootMode); virtual void initialize(JS::Realm&) override; @@ -46,6 +58,9 @@ private: Bindings::SlotAssignmentMode m_slot_assignment { Bindings::SlotAssignmentMode::Named }; bool m_delegates_focus { false }; bool m_available_to_element_internals { false }; + + JS::GCPtr m_style_sheets; + mutable JS::GCPtr m_adopted_style_sheets; }; template<> diff --git a/Userland/Libraries/LibWeb/DOM/ShadowRoot.idl b/Userland/Libraries/LibWeb/DOM/ShadowRoot.idl index fc286c6486..3e63bd0f8b 100644 --- a/Userland/Libraries/LibWeb/DOM/ShadowRoot.idl +++ b/Userland/Libraries/LibWeb/DOM/ShadowRoot.idl @@ -1,4 +1,5 @@ #import +#import #import // https://dom.spec.whatwg.org/#shadowroot @@ -12,6 +13,7 @@ interface ShadowRoot : DocumentFragment { }; ShadowRoot includes InnerHTML; +ShadowRoot includes DocumentOrShadowRoot; enum ShadowRootMode { "open", "closed" }; enum SlotAssignmentMode { "manual", "named" }; diff --git a/Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp b/Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp index 2c84f2be75..377d9775f3 100644 --- a/Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp +++ b/Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/DOM/StyleElementUtils.h b/Userland/Libraries/LibWeb/DOM/StyleElementUtils.h index d9bf6ffb25..c2298a657b 100644 --- a/Userland/Libraries/LibWeb/DOM/StyleElementUtils.h +++ b/Userland/Libraries/LibWeb/DOM/StyleElementUtils.h @@ -8,6 +8,7 @@ #include #include +#include namespace Web::DOM {