mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-08 12:56:23 +03: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:
parent
fceba6a257
commit
7c322ec710
Notes:
sideshowbarker
2024-07-17 00:53:02 +09:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/SerenityOS/serenity/commit/7c322ec710 Pull-request: https://github.com/SerenityOS/serenity/pull/23521 Reviewed-by: https://github.com/awesomekling
11
Tests/LibWeb/Text/expected/document-adopted-style-sheets.txt
Normal file
11
Tests/LibWeb/Text/expected/document-adopted-style-sheets.txt
Normal file
@ -0,0 +1,11 @@
|
||||
color with no adopted style sheets: rgb(0, 0, 0)
|
||||
document.adoptedStyleSheets.length=(1)
|
||||
add style sheet using Array.prototype.push(): rgb(255, 0, 0)
|
||||
document.adoptedStyleSheets.length=(0)
|
||||
delete added style sheet using Array.prototype.pop(): rgb(0, 0, 0)
|
||||
document.adoptedStyleSheets.length=(1)
|
||||
add style by assigning array to document.adoptedStyleSheets: rgb(255, 0, 0)
|
||||
document.adoptedStyleSheets.length=(1)
|
||||
add style by assigning Set to document.adoptedStyleSheets: rgb(0, 128, 0)
|
||||
assignment of non-iterable value to document.adoptedStyleSheets throws "1 is not iterable"
|
||||
assignment of value that is not CSSStyleSheet throws "Not an object of type CSSStyleSheet"
|
72
Tests/LibWeb/Text/input/document-adopted-style-sheets.html
Normal file
72
Tests/LibWeb/Text/input/document-adopted-style-sheets.html
Normal file
@ -0,0 +1,72 @@
|
||||
<script src="include.js"></script>
|
||||
<div id="testElement"></div>
|
||||
<script>
|
||||
test(() => {
|
||||
// Make sure assignment of empty array works correctly
|
||||
document.adoptedStyleSheets = [];
|
||||
|
||||
{
|
||||
const computedStyle = window.getComputedStyle(testElement);
|
||||
const color = computedStyle.getPropertyValue("color");
|
||||
println(`color with no adopted style sheets: ${color}`);
|
||||
}
|
||||
|
||||
const sheetColorRed = new CSSStyleSheet();
|
||||
sheetColorRed.replaceSync("#testElement { color: red }");
|
||||
document.adoptedStyleSheets.push(sheetColorRed);
|
||||
|
||||
println(`document.adoptedStyleSheets.length=(${document.adoptedStyleSheets.length})`);
|
||||
|
||||
{
|
||||
const computedStyle = window.getComputedStyle(testElement);
|
||||
const color = computedStyle.getPropertyValue("color");
|
||||
println(`add style sheet using Array.prototype.push(): ${color}`);
|
||||
}
|
||||
|
||||
document.adoptedStyleSheets.pop();
|
||||
|
||||
println(`document.adoptedStyleSheets.length=(${document.adoptedStyleSheets.length})`);
|
||||
|
||||
{
|
||||
const computedStyle = window.getComputedStyle(testElement);
|
||||
const color = computedStyle.getPropertyValue("color");
|
||||
println(`delete added style sheet using Array.prototype.pop(): ${color}`);
|
||||
}
|
||||
|
||||
document.adoptedStyleSheets = [sheetColorRed];
|
||||
|
||||
println(`document.adoptedStyleSheets.length=(${document.adoptedStyleSheets.length})`);
|
||||
|
||||
{
|
||||
const computedStyle = window.getComputedStyle(testElement);
|
||||
const color = computedStyle.getPropertyValue("color");
|
||||
println(`add style by assigning array to document.adoptedStyleSheets: ${color}`);
|
||||
}
|
||||
|
||||
const sheetColorGreen = new CSSStyleSheet();
|
||||
sheetColorGreen.replaceSync("#testElement { color: green }");
|
||||
document.adoptedStyleSheets.push(sheetColorGreen);
|
||||
|
||||
document.adoptedStyleSheets = new Set([sheetColorGreen]);
|
||||
|
||||
println(`document.adoptedStyleSheets.length=(${document.adoptedStyleSheets.length})`);
|
||||
|
||||
{
|
||||
const computedStyle = window.getComputedStyle(testElement);
|
||||
const color = computedStyle.getPropertyValue("color");
|
||||
println(`add style by assigning Set to document.adoptedStyleSheets: ${color}`);
|
||||
}
|
||||
|
||||
try {
|
||||
document.adoptedStyleSheets = 1;
|
||||
} catch(err) {
|
||||
println(`assignment of non-iterable value to document.adoptedStyleSheets throws "${err.message}"`);
|
||||
}
|
||||
|
||||
try {
|
||||
document.adoptedStyleSheets = ["foo"];
|
||||
} catch(err) {
|
||||
println(`assignment of value that is not CSSStyleSheet throws "${err.message}"`);
|
||||
}
|
||||
});
|
||||
</script>
|
@ -266,8 +266,9 @@ void StyleComputer::for_each_stylesheet(CascadeOrigin cascade_origin, Callback c
|
||||
callback(*m_user_style_sheet);
|
||||
}
|
||||
if (cascade_origin == CascadeOrigin::Author) {
|
||||
for (auto const& sheet : document().style_sheets().sheets())
|
||||
callback(*sheet);
|
||||
document().for_each_css_style_sheet([&](CSSStyleSheet& sheet) {
|
||||
callback(sheet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<>
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user