Serenity Operating System
1/*
2 * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/QuickSort.h>
8#include <LibWeb/Bindings/Intrinsics.h>
9#include <LibWeb/Bindings/StyleSheetListPrototype.h>
10#include <LibWeb/CSS/StyleSheetList.h>
11#include <LibWeb/DOM/Document.h>
12
13namespace Web::CSS {
14
15void StyleSheetList::add_sheet(CSSStyleSheet& sheet)
16{
17 sheet.set_style_sheet_list({}, this);
18 m_sheets.append(sheet);
19
20 sort_sheets();
21
22 if (sheet.rules().length() == 0) {
23 // NOTE: If the added sheet has no rules, we don't have to invalidate anything.
24 return;
25 }
26
27 m_document.style_computer().invalidate_rule_cache();
28 m_document.style_computer().load_fonts_from_sheet(sheet);
29 m_document.invalidate_style();
30}
31
32void StyleSheetList::remove_sheet(CSSStyleSheet& sheet)
33{
34 sheet.set_style_sheet_list({}, nullptr);
35 m_sheets.remove_first_matching([&](auto& entry) { return entry.ptr() == &sheet; });
36
37 if (sheet.rules().length() == 0) {
38 // NOTE: If the removed sheet had no rules, we don't have to invalidate anything.
39 return;
40 }
41
42 sort_sheets();
43
44 m_document.style_computer().invalidate_rule_cache();
45 m_document.invalidate_style();
46}
47
48WebIDL::ExceptionOr<JS::NonnullGCPtr<StyleSheetList>> StyleSheetList::create(DOM::Document& document)
49{
50 auto& realm = document.realm();
51 return MUST_OR_THROW_OOM(realm.heap().allocate<StyleSheetList>(realm, document));
52}
53
54StyleSheetList::StyleSheetList(DOM::Document& document)
55 : Bindings::LegacyPlatformObject(document.realm())
56 , m_document(document)
57{
58}
59
60JS::ThrowCompletionOr<void> StyleSheetList::initialize(JS::Realm& realm)
61{
62 MUST_OR_THROW_OOM(Base::initialize(realm));
63 set_prototype(&Bindings::ensure_web_prototype<Bindings::StyleSheetListPrototype>(realm, "StyleSheetList"));
64
65 return {};
66}
67
68void StyleSheetList::visit_edges(Cell::Visitor& visitor)
69{
70 Base::visit_edges(visitor);
71 visitor.visit(m_document);
72 for (auto sheet : m_sheets)
73 visitor.visit(sheet.ptr());
74}
75
76// https://www.w3.org/TR/cssom/#ref-for-dfn-supported-property-indices%E2%91%A1
77bool StyleSheetList::is_supported_property_index(u32 index) const
78{
79 // The object’s supported property indices are the numbers in the range zero to one less than the number of CSS style sheets represented by the collection.
80 // If there are no such CSS style sheets, then there are no supported property indices.
81 if (m_sheets.is_empty())
82 return false;
83
84 return index < m_sheets.size();
85}
86
87WebIDL::ExceptionOr<JS::Value> StyleSheetList::item_value(size_t index) const
88{
89 if (index >= m_sheets.size())
90 return JS::js_undefined();
91
92 return m_sheets[index].ptr();
93}
94
95void StyleSheetList::sort_sheets()
96{
97 quick_sort(m_sheets, [](JS::NonnullGCPtr<StyleSheet> a, JS::NonnullGCPtr<StyleSheet> b) {
98 return a->owner_node()->is_before(*b->owner_node());
99 });
100}
101
102}