From 2198091bbcd8ccd9445f12b6628e4b2d1268451b Mon Sep 17 00:00:00 2001 From: DexesTTP Date: Sat, 30 Apr 2022 11:21:21 +0200 Subject: [PATCH] LibWeb: Abstract the image decoding via Web::ImageDecoding::Decoder After this change, LibWeb now expects Web::ImageDecoding::Decoder to be pre-initialized with a concrete implementation before using the webpage. The previous implementation, based on the ImageDecoder service, has been provided directly through an adapter in LibWebClient, and is now used as the default value by WebContent. --- Userland/Libraries/LibWeb/CMakeLists.txt | 2 +- .../Libraries/LibWeb/HTML/HTMLLinkElement.cpp | 2 +- Userland/Libraries/LibWeb/ImageDecoding.cpp | 27 ++++++++---- Userland/Libraries/LibWeb/ImageDecoding.h | 31 ++++++++++++-- .../Libraries/LibWeb/Loader/FrameLoader.cpp | 5 +-- .../Libraries/LibWeb/Loader/ImageResource.cpp | 4 +- Userland/Libraries/LibWebView/CMakeLists.txt | 3 +- .../LibWebView/ImageDecoderClientAdapter.cpp | 41 +++++++++++++++++++ .../LibWebView/ImageDecoderClientAdapter.h | 32 +++++++++++++++ .../Services/WebContent/WebContentClient.ipc | 1 + Userland/Services/WebContent/main.cpp | 4 ++ 11 files changed, 132 insertions(+), 20 deletions(-) create mode 100644 Userland/Libraries/LibWebView/ImageDecoderClientAdapter.cpp create mode 100644 Userland/Libraries/LibWebView/ImageDecoderClientAdapter.h diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index cf84ad68be..c34632302a 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -377,7 +377,7 @@ set(GENERATED_SOURCES ) serenity_lib(LibWeb web) -target_link_libraries(LibWeb LibCore LibJS LibMarkdown LibGemini LibGUI LibGfx LibTextCodec LibProtocol LibImageDecoderClient LibWasm LibXML) +target_link_libraries(LibWeb LibCore LibJS LibMarkdown LibGemini LibGUI LibGfx LibTextCodec LibProtocol LibWasm LibXML) link_with_unicode_data(LibWeb) generate_js_wrappers(LibWeb) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp index 03680401c8..5684d6a70b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLLinkElement.cpp @@ -155,7 +155,7 @@ bool HTMLLinkElement::load_favicon_and_use_if_window_is_active() return false; RefPtr favicon_bitmap; - auto decoded_image = Web::image_decoder_client().decode_image(resource()->encoded_data()); + auto decoded_image = Web::ImageDecoding::Decoder::the().decode_image(resource()->encoded_data()); if (!decoded_image.has_value() || decoded_image->frames.is_empty()) { dbgln("Could not decode favicon {}", resource()->url()); return false; diff --git a/Userland/Libraries/LibWeb/ImageDecoding.cpp b/Userland/Libraries/LibWeb/ImageDecoding.cpp index 44967a8860..fc2aefee4e 100644 --- a/Userland/Libraries/LibWeb/ImageDecoding.cpp +++ b/Userland/Libraries/LibWeb/ImageDecoding.cpp @@ -1,23 +1,32 @@ /* * Copyright (c) 2021, Andreas Kling + * Copyright (c) 2022, Dex♪ * * SPDX-License-Identifier: BSD-2-Clause */ #include -namespace Web { +namespace Web::ImageDecoding { -ImageDecoderClient::Client& image_decoder_client() +static RefPtr s_decoder; + +Decoder::Decoder() = default; + +Decoder::~Decoder() = default; + +void Decoder::initialize(RefPtr&& decoder) { - static RefPtr image_decoder_client; - if (!image_decoder_client) { - image_decoder_client = ImageDecoderClient::Client::try_create().release_value_but_fixme_should_propagate_errors(); - image_decoder_client->on_death = [&] { - image_decoder_client = nullptr; - }; + s_decoder = move(decoder); +} + +Decoder& Decoder::the() +{ + if (!s_decoder) [[unlikely]] { + dbgln("Web::ImageDecoding::Decoder was not initialized!"); + VERIFY_NOT_REACHED(); } - return *image_decoder_client; + return *s_decoder; } } diff --git a/Userland/Libraries/LibWeb/ImageDecoding.h b/Userland/Libraries/LibWeb/ImageDecoding.h index 081b4e123c..2c462aae2c 100644 --- a/Userland/Libraries/LibWeb/ImageDecoding.h +++ b/Userland/Libraries/LibWeb/ImageDecoding.h @@ -1,15 +1,40 @@ /* * Copyright (c) 2020-2021, Andreas Kling + * Copyright (c) 2022, Dex♪ * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once -#include +#include +#include +#include -namespace Web { +namespace Web::ImageDecoding { -ImageDecoderClient::Client& image_decoder_client(); +struct Frame { + RefPtr bitmap; + size_t duration { 0 }; +}; + +struct DecodedImage { + bool is_animated { false }; + u32 loop_count { 0 }; + Vector frames; +}; + +class Decoder : public RefCounted { +public: + virtual ~Decoder(); + + static void initialize(RefPtr&&); + static Decoder& the(); + + virtual Optional decode_image(ReadonlyBytes) = 0; + +protected: + explicit Decoder(); +}; } diff --git a/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp b/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp index 1b54366e0b..6defe4cb2a 100644 --- a/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/FrameLoader.cpp @@ -75,8 +75,7 @@ static bool build_text_document(DOM::Document& document, ByteBuffer const& data) static bool build_image_document(DOM::Document& document, ByteBuffer const& data) { - NonnullRefPtr decoder = image_decoder_client(); - auto image = decoder->decode_image(data); + auto image = ImageDecoding::Decoder::the().decode_image(data); if (!image.has_value() || image->frames.is_empty()) return false; auto const& frame = image->frames[0]; @@ -209,7 +208,7 @@ bool FrameLoader::load(LoadRequest& request, Type type) if (data.is_empty()) return; RefPtr favicon_bitmap; - auto decoded_image = image_decoder_client().decode_image(data); + auto decoded_image = ImageDecoding::Decoder::the().decode_image(data); if (!decoded_image.has_value() || decoded_image->frames.is_empty()) { dbgln("Could not decode favicon {}", favicon_url); } else { diff --git a/Userland/Libraries/LibWeb/Loader/ImageResource.cpp b/Userland/Libraries/LibWeb/Loader/ImageResource.cpp index 874f4d4ee4..ac2704f4c4 100644 --- a/Userland/Libraries/LibWeb/Loader/ImageResource.cpp +++ b/Userland/Libraries/LibWeb/Loader/ImageResource.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -46,8 +47,7 @@ void ImageResource::decode_if_needed() const if (!m_decoded_frames.is_empty()) return; - NonnullRefPtr decoder = image_decoder_client(); - auto image = decoder->decode_image(encoded_data()); + auto image = ImageDecoding::Decoder::the().decode_image(encoded_data()); if (image.has_value()) { m_loop_count = image.value().loop_count; diff --git a/Userland/Libraries/LibWebView/CMakeLists.txt b/Userland/Libraries/LibWebView/CMakeLists.txt index 5a62bbc5a9..d0da3aef1e 100644 --- a/Userland/Libraries/LibWebView/CMakeLists.txt +++ b/Userland/Libraries/LibWebView/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES DOMTreeModel.cpp + ImageDecoderClientAdapter.cpp OutOfProcessWebView.cpp StylePropertiesModel.cpp WebContentClient.cpp @@ -13,6 +14,6 @@ set(GENERATED_SOURCES ) serenity_lib(LibWebView webview) -target_link_libraries(LibWebView LibGfx LibGUI LibIPC LibWeb) +target_link_libraries(LibWebView LibGfx LibGUI LibImageDecoderClient LibIPC LibWeb) add_subdirectory(DumpLayoutTree) diff --git a/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.cpp b/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.cpp new file mode 100644 index 0000000000..47fa6e1878 --- /dev/null +++ b/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022, Dex♪ + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace WebView { + +NonnullRefPtr ImageDecoderClientAdapter::create() +{ + return adopt_ref(*new ImageDecoderClientAdapter()); +} + +Optional ImageDecoderClientAdapter::decode_image(ReadonlyBytes bytes) +{ + if (!m_client) { + m_client = ImageDecoderClient::Client::try_create().release_value_but_fixme_should_propagate_errors(); + m_client->on_death = [&] { + m_client = nullptr; + }; + } + + auto result_or_empty = m_client->decode_image(bytes); + if (!result_or_empty.has_value()) + return {}; + auto result = result_or_empty.release_value(); + + Web::ImageDecoding::DecodedImage decoded_image; + decoded_image.is_animated = result.is_animated; + decoded_image.loop_count = result.loop_count; + for (auto const& frame : result.frames) { + decoded_image.frames.empend(move(frame.bitmap), frame.duration); + } + + return decoded_image; +} + +} diff --git a/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.h b/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.h new file mode 100644 index 0000000000..e46b0e6974 --- /dev/null +++ b/Userland/Libraries/LibWebView/ImageDecoderClientAdapter.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Dex♪ + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace ImageDecoderClient { +class Client; +} + +namespace WebView { + +class ImageDecoderClientAdapter : public Web::ImageDecoding::Decoder { +public: + static NonnullRefPtr create(); + + virtual ~ImageDecoderClientAdapter() override = default; + + virtual Optional decode_image(ReadonlyBytes) override; + +private: + explicit ImageDecoderClientAdapter() = default; + + RefPtr m_client; +}; + +} diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index a0f329fc97..aaa5c67138 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -1,6 +1,7 @@ #include #include #include +#include endpoint WebContentClient { diff --git a/Userland/Services/WebContent/main.cpp b/Userland/Services/WebContent/main.cpp index 351fd4b159..42c5292dd9 100644 --- a/Userland/Services/WebContent/main.cpp +++ b/Userland/Services/WebContent/main.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include ErrorOr serenity_main(Main::Arguments) @@ -22,6 +24,8 @@ ErrorOr serenity_main(Main::Arguments) TRY(Core::System::unveil("/tmp/portal/websocket", "rw")); TRY(Core::System::unveil(nullptr, nullptr)); + Web::ImageDecoding::Decoder::initialize(WebView::ImageDecoderClientAdapter::create()); + auto client = TRY(IPC::take_over_accepted_client_from_system_server()); return event_loop.exec(); }