diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index a0ad7fc120..3c814b461f 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -315,6 +315,7 @@ set(SOURCES HTML/HTMLVideoElement.cpp HTML/ImageData.cpp HTML/ImageRequest.cpp + HTML/ListOfAvailableImages.cpp HTML/Location.cpp HTML/MediaError.cpp HTML/MessageChannel.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 9ea97816b6..5860bf85e8 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -330,6 +331,8 @@ JS::ThrowCompletionOr Document::initialize(JS::Realm& realm) m_selection = MUST_OR_THROW_OOM(heap().allocate(realm, realm, *this)); + m_list_of_available_images = TRY_OR_THROW_OOM(realm.vm(), try_make()); + return {}; } @@ -2567,4 +2570,14 @@ void Document::make_active() HTML::relevant_settings_object(window).execution_ready = true; } +HTML::ListOfAvailableImages& Document::list_of_available_images() +{ + return *m_list_of_available_images; +} + +HTML::ListOfAvailableImages const& Document::list_of_available_images() const +{ + return *m_list_of_available_images; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 36a325fe2c..0861256125 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -474,6 +474,9 @@ public: void set_salvageable(bool value) { m_salvageable = value; }; + HTML::ListOfAvailableImages& list_of_available_images(); + HTML::ListOfAvailableImages const& list_of_available_images() const; + protected: virtual JS::ThrowCompletionOr initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; @@ -639,6 +642,9 @@ private: // NOTE: This is a cache to make finding the first element O(1). JS::GCPtr m_first_base_element_with_href_in_tree_order; + + // https://html.spec.whatwg.org/multipage/images.html#list-of-available-images + OwnPtr m_list_of_available_images; }; template<> diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index aa7dc45915..8061f085cf 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -373,6 +373,7 @@ class HTMLUnknownElement; class HTMLVideoElement; class ImageData; class ImageRequest; +class ListOfAvailableImages; class Location; class MediaError; class MessageChannel; diff --git a/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.cpp b/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.cpp new file mode 100644 index 0000000000..0fd0cec290 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::HTML { + +ListOfAvailableImages::ListOfAvailableImages() = default; +ListOfAvailableImages::~ListOfAvailableImages() = default; + +bool ListOfAvailableImages::Key::operator==(Key const& other) const +{ + return url == other.url && mode == other.mode && origin == other.origin; +} + +u32 ListOfAvailableImages::Key::hash() const +{ + if (!cached_hash.has_value()) { + u32 url_hash = Traits::hash(url); + u32 mode_hash = static_cast(mode); + u32 origin_hash = 0; + if (origin.has_value()) + origin_hash = Traits::hash(origin.value()); + cached_hash = pair_int_hash(url_hash, pair_int_hash(mode_hash, origin_hash)); + } + return cached_hash.value(); +} + +ErrorOr> ListOfAvailableImages::Entry::create(NonnullRefPtr image_data, bool ignore_higher_layer_caching) +{ + return adopt_nonnull_ref_or_enomem(new (nothrow) Entry(move(image_data), ignore_higher_layer_caching)); +} + +ListOfAvailableImages::Entry::Entry(NonnullRefPtr data, bool ignore_higher_layer_caching) + : ignore_higher_layer_caching(ignore_higher_layer_caching) + , image_data(move(data)) +{ +} + +ListOfAvailableImages::Entry::~Entry() = default; + +ErrorOr ListOfAvailableImages::add(Key const& key, NonnullRefPtr image_data, bool ignore_higher_layer_caching) +{ + auto entry = TRY(Entry::create(move(image_data), ignore_higher_layer_caching)); + TRY(m_images.try_set(key, move(entry))); + return {}; +} + +void ListOfAvailableImages::remove(Key const& key) +{ + m_images.remove(key); +} + +RefPtr ListOfAvailableImages::get(Key const& key) const +{ + auto it = m_images.find(key); + if (it == m_images.end()) + return nullptr; + return it->value; +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.h b/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.h new file mode 100644 index 0000000000..3591a395b7 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/ListOfAvailableImages.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Web::HTML { + +// https://html.spec.whatwg.org/multipage/images.html#list-of-available-images +class ListOfAvailableImages { +public: + struct Key { + AK::URL url; + HTML::CORSSettingAttribute mode; + Optional origin; + + [[nodiscard]] bool operator==(Key const& other) const; + [[nodiscard]] u32 hash() const; + + private: + mutable Optional cached_hash; + }; + + struct Entry final : public RefCounted { + static ErrorOr> create(NonnullRefPtr, bool ignore_higher_layer_caching); + ~Entry(); + + bool ignore_higher_layer_caching { false }; + NonnullRefPtr image_data; + + private: + Entry(NonnullRefPtr, bool ignore_higher_layer_caching); + }; + + ListOfAvailableImages(); + ~ListOfAvailableImages(); + + ErrorOr add(Key const&, NonnullRefPtr, bool ignore_higher_layer_caching); + void remove(Key const&); + [[nodiscard]] RefPtr get(Key const&) const; + +private: + HashMap> m_images; +}; + +} + +namespace AK { + +template<> +struct Traits : public GenericTraits { + static unsigned hash(Web::HTML::ListOfAvailableImages::Key const& key) + { + return key.hash(); + } + static bool equals(Web::HTML::ListOfAvailableImages::Key const& a, Web::HTML::ListOfAvailableImages::Key const& b) + { + return a == b; + } +}; + +}