1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:17:35 +00:00

LibWeb: Implement adoptedStyleSheets attribute for Document

https://drafts.csswg.org/cssom/#dom-documentorshadowroot-adoptedstylesheets

The attribute implementation for ShadowRoot is currently missing
because we do not yet distinguish between the style sheets of
ShadowRoot and Document, and we need to address the issue first.
This commit is contained in:
Aliaksandr Kalenik 2024-03-07 23:36:52 +01:00 committed by Andreas Kling
parent fceba6a257
commit 7c322ec710
6 changed files with 171 additions and 2 deletions

View file

@ -483,6 +483,8 @@ void Document::visit_edges(Cell::Visitor& visitor)
visitor.visit(event.event);
visitor.visit(event.target);
}
visitor.visit(m_adopted_style_sheets);
}
// https://w3c.github.io/selection-api/#dom-document-getselection
@ -4562,4 +4564,78 @@ bool Document::has_skipped_resize_observations()
return false;
}
static JS::NonnullGCPtr<WebIDL::ObservableArray> 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<void> {
auto& vm = document.vm();
if (!value.is_object())
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet");
auto& object = value.as_object();
if (!is<CSS::CSSStyleSheet>(object))
return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "CSSStyleSheet");
auto& style_sheet = static_cast<CSS::CSSStyleSheet&>(object);
// The set an indexed value algorithm for adoptedStyleSheets, given value and index, is the following:
// 1. If values 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<void> {
document.style_computer().invalidate_rule_cache();
document.invalidate_style();
return {};
});
return adopted_style_sheets;
}
JS::NonnullGCPtr<WebIDL::ObservableArray> Document::adopted_style_sheets() const
{
if (!m_adopted_style_sheets)
m_adopted_style_sheets = create_adopted_style_sheets_list(const_cast<Document&>(*this));
return *m_adopted_style_sheets;
}
WebIDL::ExceptionOr<void> Document::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&>(*this));
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 {};
}
void Document::for_each_css_style_sheet(Function<void(CSS::CSSStyleSheet&)>&& callback) const
{
for (auto& style_sheet : m_style_sheets->sheets())
callback(*style_sheet);
if (m_adopted_style_sheets) {
for (auto& entry : m_adopted_style_sheets->indexed_properties()) {
auto value_and_attributes = m_adopted_style_sheets->indexed_properties().storage()->get(entry.index());
if (value_and_attributes.has_value()) {
auto& style_sheet = verify_cast<CSS::CSSStyleSheet>(value_and_attributes->value.as_object());
callback(style_sheet);
}
}
}
}
}

View file

@ -34,6 +34,7 @@
#include <LibWeb/HTML/SharedImageRequest.h>
#include <LibWeb/HTML/VisibilityState.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
#include <LibWeb/WebIDL/ObservableArray.h>
namespace Web::DOM {
@ -131,6 +132,8 @@ public:
CSS::StyleSheetList& style_sheets();
CSS::StyleSheetList const& style_sheets() const;
void for_each_css_style_sheet(Function<void(CSS::CSSStyleSheet&)>&& callback) const;
CSS::StyleSheetList* style_sheets_for_bindings() { return &style_sheets(); }
virtual FlyString node_name() const override { return "#document"_fly_string; }
@ -598,6 +601,9 @@ public:
[[nodiscard]] bool has_active_resize_observations();
[[nodiscard]] bool has_skipped_resize_observations();
JS::NonnullGCPtr<WebIDL::ObservableArray> adopted_style_sheets() const;
WebIDL::ExceptionOr<void> set_adopted_style_sheets(JS::Value);
protected:
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
@ -832,6 +838,8 @@ private:
bool m_design_mode_enabled { false };
bool m_needs_to_resolve_paint_only_properties { true };
mutable JS::GCPtr<WebIDL::ObservableArray> m_adopted_style_sheets;
};
template<>

View file

@ -95,6 +95,7 @@ interface Document : Node {
[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;