Serenity Operating System
1/*
2 * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
3 * Copyright (c) 2022-2023, Andreas Kling <kling@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <LibWeb/Bindings/Intrinsics.h>
9#include <LibWeb/Bindings/MediaListPrototype.h>
10#include <LibWeb/CSS/MediaList.h>
11#include <LibWeb/CSS/Parser/Parser.h>
12#include <LibWeb/WebIDL/ExceptionOr.h>
13
14namespace Web::CSS {
15
16WebIDL::ExceptionOr<JS::NonnullGCPtr<MediaList>> MediaList::create(JS::Realm& realm, Vector<NonnullRefPtr<MediaQuery>>&& media)
17{
18 return MUST_OR_THROW_OOM(realm.heap().allocate<MediaList>(realm, realm, move(media)));
19}
20
21MediaList::MediaList(JS::Realm& realm, Vector<NonnullRefPtr<MediaQuery>>&& media)
22 : Bindings::LegacyPlatformObject(realm)
23 , m_media(move(media))
24{
25}
26
27JS::ThrowCompletionOr<void> MediaList::initialize(JS::Realm& realm)
28{
29 MUST_OR_THROW_OOM(Base::initialize(realm));
30 set_prototype(&Bindings::ensure_web_prototype<Bindings::MediaListPrototype>(realm, "MediaList"));
31
32 return {};
33}
34
35// https://www.w3.org/TR/cssom-1/#dom-medialist-mediatext
36DeprecatedString MediaList::media_text() const
37{
38 return serialize_a_media_query_list(m_media).release_value_but_fixme_should_propagate_errors().to_deprecated_string();
39}
40
41// https://www.w3.org/TR/cssom-1/#dom-medialist-mediatext
42void MediaList::set_media_text(DeprecatedString const& text)
43{
44 m_media.clear();
45 if (text.is_empty())
46 return;
47 m_media = parse_media_query_list(Parser::ParsingContext { realm() }, text);
48}
49
50bool MediaList::is_supported_property_index(u32 index) const
51{
52 return index < length();
53}
54
55// https://www.w3.org/TR/cssom-1/#dom-medialist-item
56DeprecatedString MediaList::item(u32 index) const
57{
58 if (!is_supported_property_index(index))
59 return {};
60
61 return m_media[index]->to_string().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
62}
63
64// https://www.w3.org/TR/cssom-1/#dom-medialist-appendmedium
65void MediaList::append_medium(DeprecatedString medium)
66{
67 // 1. Let m be the result of parsing the given value.
68 auto m = parse_media_query(Parser::ParsingContext { realm() }, medium);
69
70 // 2. If m is null, then return.
71 if (!m)
72 return;
73
74 // 3. If comparing m with any of the media queries in the collection of media queries returns true, then return.
75 auto serialized = m->to_string().release_value_but_fixme_should_propagate_errors();
76 for (auto& existing_medium : m_media) {
77 if (existing_medium->to_string().release_value_but_fixme_should_propagate_errors() == serialized)
78 return;
79 }
80
81 // 4. Append m to the collection of media queries.
82 m_media.append(m.release_nonnull());
83}
84
85// https://www.w3.org/TR/cssom-1/#dom-medialist-deletemedium
86void MediaList::delete_medium(DeprecatedString medium)
87{
88 auto m = parse_media_query(Parser::ParsingContext { realm() }, medium);
89 if (!m)
90 return;
91 m_media.remove_all_matching([&](auto& existing) -> bool {
92 return m->to_string().release_value_but_fixme_should_propagate_errors() == existing->to_string().release_value_but_fixme_should_propagate_errors();
93 });
94 // FIXME: If nothing was removed, then throw a NotFoundError exception.
95}
96
97bool MediaList::evaluate(HTML::Window const& window)
98{
99 for (auto& media : m_media)
100 media->evaluate(window);
101
102 return matches();
103}
104
105bool MediaList::matches() const
106{
107 if (m_media.is_empty()) {
108 return true;
109 }
110
111 for (auto& media : m_media) {
112 if (media->matches())
113 return true;
114 }
115 return false;
116}
117
118WebIDL::ExceptionOr<JS::Value> MediaList::item_value(size_t index) const
119{
120 if (index >= m_media.size())
121 return JS::js_undefined();
122 return JS::PrimitiveString::create(vm(), m_media[index]->to_string().release_value_but_fixme_should_propagate_errors().to_deprecated_string());
123}
124
125}