From f4a5c136c3ab05e084ce1172805d1dab376c8125 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Fri, 24 Nov 2023 14:45:45 +0100 Subject: [PATCH] LibGfx+LibWeb: Add ImmutableBitmap for images bitmap caching in painter Before this change, we used Gfx::Bitmap to represent both decoded images that are not going to be mutated and bitmaps corresponding to canvases that could be mutated. This change introduces a wrapper for bitmaps that are not going to be mutated, so the painter could do caching: texture caching in the case of GPU painter and potentially scaled bitmap caching in the case of CPU painter. --- Userland/Libraries/LibGfx/CMakeLists.txt | 1 + Userland/Libraries/LibGfx/Forward.h | 1 + Userland/Libraries/LibGfx/ImmutableBitmap.cpp | 24 +++++++++++ Userland/Libraries/LibGfx/ImmutableBitmap.h | 40 +++++++++++++++++++ .../CSS/StyleValues/ImageStyleValue.cpp | 4 +- .../LibWeb/CSS/StyleValues/ImageStyleValue.h | 2 +- .../HTML/AnimatedBitmapDecodedImageData.cpp | 2 +- .../HTML/AnimatedBitmapDecodedImageData.h | 5 ++- .../Libraries/LibWeb/HTML/DecodedImageData.h | 2 +- .../LibWeb/HTML/HTMLImageElement.cpp | 4 +- .../Libraries/LibWeb/HTML/HTMLImageElement.h | 6 ++- .../LibWeb/HTML/HTMLObjectElement.cpp | 2 +- .../Libraries/LibWeb/HTML/HTMLObjectElement.h | 2 +- .../LibWeb/HTML/SharedImageRequest.cpp | 2 +- .../Libraries/LibWeb/Layout/ImageProvider.h | 2 +- .../LibWeb/Painting/ImagePaintable.cpp | 2 +- .../Painting/PaintingCommandExecutorCPU.cpp | 7 ++++ .../Painting/PaintingCommandExecutorCPU.h | 1 + .../Painting/PaintingCommandExecutorGPU.cpp | 21 ++++++---- .../Painting/PaintingCommandExecutorGPU.h | 1 + .../LibWeb/Painting/RecordingPainter.cpp | 13 ++++++ .../LibWeb/Painting/RecordingPainter.h | 13 ++++++ .../LibWeb/SVG/SVGDecodedImageData.cpp | 18 +++++---- .../LibWeb/SVG/SVGDecodedImageData.h | 6 +-- 24 files changed, 146 insertions(+), 35 deletions(-) create mode 100644 Userland/Libraries/LibGfx/ImmutableBitmap.cpp create mode 100644 Userland/Libraries/LibGfx/ImmutableBitmap.h diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 7e2ca487c4..7915ad4520 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -60,6 +60,7 @@ set(SOURCES ImageFormats/WebPLoader.cpp ImageFormats/WebPLoaderLossless.cpp ImageFormats/WebPLoaderLossy.cpp + ImmutableBitmap.cpp Painter.cpp Palette.cpp Path.cpp diff --git a/Userland/Libraries/LibGfx/Forward.h b/Userland/Libraries/LibGfx/Forward.h index 93a1314c3e..43c6b9c28d 100644 --- a/Userland/Libraries/LibGfx/Forward.h +++ b/Userland/Libraries/LibGfx/Forward.h @@ -9,6 +9,7 @@ namespace Gfx { class Bitmap; +class ImmutableBitmap; class CharacterBitmap; class Color; diff --git a/Userland/Libraries/LibGfx/ImmutableBitmap.cpp b/Userland/Libraries/LibGfx/ImmutableBitmap.cpp new file mode 100644 index 0000000000..ddff95c21f --- /dev/null +++ b/Userland/Libraries/LibGfx/ImmutableBitmap.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Gfx { + +static size_t s_next_immutable_bitmap_id = 0; + +NonnullRefPtr ImmutableBitmap::create(NonnullRefPtr bitmap) +{ + return adopt_ref(*new ImmutableBitmap(move(bitmap))); +} + +ImmutableBitmap::ImmutableBitmap(NonnullRefPtr bitmap) + : m_bitmap(move(bitmap)) + , m_id(s_next_immutable_bitmap_id++) +{ +} + +} diff --git a/Userland/Libraries/LibGfx/ImmutableBitmap.h b/Userland/Libraries/LibGfx/ImmutableBitmap.h new file mode 100644 index 0000000000..a414df16ba --- /dev/null +++ b/Userland/Libraries/LibGfx/ImmutableBitmap.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Gfx { + +class ImmutableBitmap final : public RefCounted { +public: + static NonnullRefPtr create(NonnullRefPtr bitmap); + + ~ImmutableBitmap() = default; + + Bitmap const& bitmap() const { return *m_bitmap; } + + size_t width() const { return m_bitmap->width(); } + size_t height() const { return m_bitmap->height(); } + + IntRect rect() const { return m_bitmap->rect(); } + IntSize size() const { return m_bitmap->size(); } + + size_t id() const { return m_id; } + +private: + NonnullRefPtr m_bitmap; + size_t m_id; + + explicit ImmutableBitmap(NonnullRefPtr bitmap); +}; + +} diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index f7e499dfd9..d94b1300cd 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -91,7 +91,7 @@ bool ImageStyleValue::is_paintable() const return image_data(); } -Gfx::Bitmap const* ImageStyleValue::bitmap(size_t frame_index, Gfx::IntSize size) const +Gfx::ImmutableBitmap const* ImageStyleValue::bitmap(size_t frame_index, Gfx::IntSize size) const { if (auto image_data = this->image_data()) return image_data->bitmap(frame_index, size); @@ -128,7 +128,7 @@ void ImageStyleValue::paint(PaintContext& context, DevicePixelRect const& dest_r { if (auto const* b = bitmap(m_current_frame_index, dest_rect.size().to_type()); b != nullptr) { auto scaling_mode = to_gfx_scaling_mode(image_rendering, b->rect(), dest_rect.to_type()); - context.painter().draw_scaled_bitmap(dest_rect.to_type(), *b, b->rect(), scaling_mode); + context.painter().draw_scaled_immutable_bitmap(dest_rect.to_type(), *b, b->rect(), scaling_mode); } } diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h index 5650085cf7..65a43bc088 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.h @@ -56,7 +56,7 @@ private: JS::GCPtr m_image_request; void animate(); - Gfx::Bitmap const* bitmap(size_t frame_index, Gfx::IntSize = {}) const; + Gfx::ImmutableBitmap const* bitmap(size_t frame_index, Gfx::IntSize = {}) const; AK::URL m_url; WeakPtr m_document; diff --git a/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.cpp b/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.cpp index 4ad58719d0..edd677baa2 100644 --- a/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.cpp +++ b/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.cpp @@ -23,7 +23,7 @@ AnimatedBitmapDecodedImageData::AnimatedBitmapDecodedImageData(Vector&& f AnimatedBitmapDecodedImageData::~AnimatedBitmapDecodedImageData() = default; -RefPtr AnimatedBitmapDecodedImageData::bitmap(size_t frame_index, Gfx::IntSize) const +RefPtr AnimatedBitmapDecodedImageData::bitmap(size_t frame_index, Gfx::IntSize) const { if (frame_index >= m_frames.size()) return nullptr; diff --git a/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.h b/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.h index bb32319bcf..ac8c65dc5b 100644 --- a/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.h +++ b/Userland/Libraries/LibWeb/HTML/AnimatedBitmapDecodedImageData.h @@ -6,6 +6,7 @@ #pragma once +#include #include namespace Web::HTML { @@ -13,14 +14,14 @@ namespace Web::HTML { class AnimatedBitmapDecodedImageData final : public DecodedImageData { public: struct Frame { - RefPtr bitmap; + RefPtr bitmap; int duration { 0 }; }; static ErrorOr> create(Vector&&, size_t loop_count, bool animated); virtual ~AnimatedBitmapDecodedImageData() override; - virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize = {}) const override; + virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize = {}) const override; virtual int frame_duration(size_t frame_index) const override; virtual size_t frame_count() const override { return m_frames.size(); } diff --git a/Userland/Libraries/LibWeb/HTML/DecodedImageData.h b/Userland/Libraries/LibWeb/HTML/DecodedImageData.h index d0b856be4b..35e701f0f5 100644 --- a/Userland/Libraries/LibWeb/HTML/DecodedImageData.h +++ b/Userland/Libraries/LibWeb/HTML/DecodedImageData.h @@ -18,7 +18,7 @@ class DecodedImageData : public RefCounted { public: virtual ~DecodedImageData(); - virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize = {}) const = 0; + virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize = {}) const = 0; virtual int frame_duration(size_t frame_index) const = 0; virtual size_t frame_count() const = 0; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp index 3c042ab81f..34a91259c4 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -120,7 +120,7 @@ JS::GCPtr HTMLImageElement::create_layout_node(NonnullRefPtr(document(), *this, move(style), *this); } -RefPtr HTMLImageElement::bitmap() const +RefPtr HTMLImageElement::immutable_bitmap() const { return current_image_bitmap(); } @@ -146,7 +146,7 @@ Optional HTMLImageElement::intrinsic_aspect_ratio() const return {}; } -RefPtr HTMLImageElement::current_image_bitmap(Gfx::IntSize size) const +RefPtr HTMLImageElement::current_image_bitmap(Gfx::IntSize size) const { if (auto data = m_current_request->image_data()) return data->bitmap(m_current_frame_index, size); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h index e60aedd32b..771c8cfd54 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,8 @@ public: DeprecatedString alt() const { return deprecated_attribute(HTML::AttributeNames::alt); } DeprecatedString src() const { return deprecated_attribute(HTML::AttributeNames::src); } - RefPtr bitmap() const; + RefPtr immutable_bitmap() const; + RefPtr bitmap() const { return immutable_bitmap()->bitmap(); } unsigned width() const; WebIDL::ExceptionOr set_width(unsigned); @@ -89,7 +91,7 @@ public: virtual Optional intrinsic_width() const override; virtual Optional intrinsic_height() const override; virtual Optional intrinsic_aspect_ratio() const override; - virtual RefPtr current_image_bitmap(Gfx::IntSize = {}) const override; + virtual RefPtr current_image_bitmap(Gfx::IntSize = {}) const override; virtual void set_visible_in_viewport(bool) override; void set_lazy_load_resumption_steps(Function); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp index 123f8abd48..208c82b582 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp @@ -382,7 +382,7 @@ Optional HTMLObjectElement::intrinsic_aspect_ratio() const return {}; } -RefPtr HTMLObjectElement::current_image_bitmap(Gfx::IntSize size) const +RefPtr HTMLObjectElement::current_image_bitmap(Gfx::IntSize size) const { if (auto image_data = this->image_data()) return image_data->bitmap(0, size); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h index dbc7eabb26..9e909c4a36 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h @@ -76,7 +76,7 @@ private: virtual Optional intrinsic_width() const override; virtual Optional intrinsic_height() const override; virtual Optional intrinsic_aspect_ratio() const override; - virtual RefPtr current_image_bitmap(Gfx::IntSize = {}) const override; + virtual RefPtr current_image_bitmap(Gfx::IntSize = {}) const override; virtual void set_visible_in_viewport(bool) override; Representation m_representation { Representation::Unknown }; diff --git a/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp b/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp index 97aef9dff9..556f1b843b 100644 --- a/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp +++ b/Userland/Libraries/LibWeb/HTML/SharedImageRequest.cpp @@ -159,7 +159,7 @@ void SharedImageRequest::handle_successful_fetch(AK::URL const& url_string, Stri Vector frames; for (auto& frame : result.value().frames) { frames.append(AnimatedBitmapDecodedImageData::Frame { - .bitmap = frame.bitmap, + .bitmap = Gfx::ImmutableBitmap::create(*frame.bitmap), .duration = static_cast(frame.duration), }); } diff --git a/Userland/Libraries/LibWeb/Layout/ImageProvider.h b/Userland/Libraries/LibWeb/Layout/ImageProvider.h index 878d31f9bd..290f38afd9 100644 --- a/Userland/Libraries/LibWeb/Layout/ImageProvider.h +++ b/Userland/Libraries/LibWeb/Layout/ImageProvider.h @@ -19,7 +19,7 @@ public: virtual Optional intrinsic_height() const = 0; virtual Optional intrinsic_aspect_ratio() const = 0; - virtual RefPtr current_image_bitmap(Gfx::IntSize) const = 0; + virtual RefPtr current_image_bitmap(Gfx::IntSize) const = 0; virtual void set_visible_in_viewport(bool) = 0; }; diff --git a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp index d8ccf18f90..98983439e2 100644 --- a/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ImagePaintable.cpp @@ -175,7 +175,7 @@ void ImagePaintable::paint(PaintContext& context, PaintPhase phase) const (int)scaled_bitmap_height }; - context.painter().draw_scaled_bitmap(draw_rect.intersected(image_int_rect), *bitmap, bitmap_rect.intersected(bitmap_intersect), scaling_mode); + context.painter().draw_scaled_immutable_bitmap(draw_rect.intersected(image_int_rect), *bitmap, bitmap_rect.intersected(bitmap_intersect), scaling_mode); } } } diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp index 61077c1f6f..fd020aef63 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.cpp @@ -64,6 +64,13 @@ CommandResult PaintingCommandExecutorCPU::draw_scaled_bitmap(Gfx::IntRect const& return CommandResult::Continue; } +CommandResult PaintingCommandExecutorCPU::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) +{ + auto& painter = this->painter(); + painter.draw_scaled_bitmap(dst_rect, immutable_bitmap.bitmap(), src_rect, 1, scaling_mode); + return CommandResult::Continue; +} + CommandResult PaintingCommandExecutorCPU::set_clip_rect(Gfx::IntRect const& rect) { auto& painter = this->painter(); diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h index ba208420f6..5d089794eb 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorCPU.h @@ -17,6 +17,7 @@ public: CommandResult draw_text(Gfx::IntRect const& rect, String const& raw_text, Gfx::TextAlignment alignment, Color const&, Gfx::TextElision, Gfx::TextWrapping, Optional> const&) override; CommandResult fill_rect(Gfx::IntRect const& rect, Color const&) override; CommandResult draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) override; + CommandResult draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) override; CommandResult set_clip_rect(Gfx::IntRect const& rect) override; CommandResult clear_clip_rect() override; CommandResult set_font(Gfx::Font const&) override; diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp index 9cbfb51ec1..18df9fe990 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.cpp @@ -44,25 +44,30 @@ CommandResult PaintingCommandExecutorGPU::fill_rect(Gfx::IntRect const& rect, Co return CommandResult::Continue; } -CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) +static AccelGfx::Painter::ScalingMode to_accelgfx_scaling_mode(Gfx::Painter::ScalingMode scaling_mode) { - // FIXME: We should avoid using Gfx::Painter specific enums in painting commands - AccelGfx::Painter::ScalingMode accel_scaling_mode; switch (scaling_mode) { case Gfx::Painter::ScalingMode::NearestNeighbor: case Gfx::Painter::ScalingMode::BoxSampling: case Gfx::Painter::ScalingMode::SmoothPixels: case Gfx::Painter::ScalingMode::None: - accel_scaling_mode = AccelGfx::Painter::ScalingMode::NearestNeighbor; - break; + return AccelGfx::Painter::ScalingMode::NearestNeighbor; case Gfx::Painter::ScalingMode::BilinearBlend: - accel_scaling_mode = AccelGfx::Painter::ScalingMode::Bilinear; - break; + return AccelGfx::Painter::ScalingMode::Bilinear; default: VERIFY_NOT_REACHED(); } +} - painter().draw_scaled_bitmap(dst_rect, bitmap, src_rect, accel_scaling_mode); +CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) +{ + painter().draw_scaled_bitmap(dst_rect, bitmap, src_rect, to_accelgfx_scaling_mode(scaling_mode)); + return CommandResult::Continue; +} + +CommandResult PaintingCommandExecutorGPU::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) +{ + painter().draw_scaled_bitmap(dst_rect, immutable_bitmap.bitmap(), src_rect, to_accelgfx_scaling_mode(scaling_mode)); return CommandResult::Continue; } diff --git a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h index 66ed48f664..f9eb72556d 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h +++ b/Userland/Libraries/LibWeb/Painting/PaintingCommandExecutorGPU.h @@ -17,6 +17,7 @@ public: CommandResult draw_text(Gfx::IntRect const& rect, String const& raw_text, Gfx::TextAlignment alignment, Color const&, Gfx::TextElision, Gfx::TextWrapping, Optional> const&) override; CommandResult fill_rect(Gfx::IntRect const& rect, Color const&) override; CommandResult draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) override; + CommandResult draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) override; CommandResult set_clip_rect(Gfx::IntRect const& rect) override; CommandResult clear_clip_rect() override; CommandResult set_font(Gfx::Font const&) override; diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp index b2fc3e7cf7..eb38d5565f 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.cpp @@ -157,6 +157,16 @@ void RecordingPainter::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bit }); } +void RecordingPainter::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) +{ + push_command(DrawScaledImmutableBitmap { + .dst_rect = state().translation.map(dst_rect), + .bitmap = bitmap, + .src_rect = src_rect, + .scaling_mode = scaling_mode, + }); +} + void RecordingPainter::draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness, Gfx::Painter::LineStyle style, Color alternate_color) { push_command(DrawLine { @@ -436,6 +446,9 @@ void RecordingPainter::execute(PaintingCommandExecutor& executor) [&](DrawScaledBitmap const& command) { return executor.draw_scaled_bitmap(command.dst_rect, command.bitmap, command.src_rect, command.scaling_mode); }, + [&](DrawScaledImmutableBitmap const& command) { + return executor.draw_scaled_immutable_bitmap(command.dst_rect, command.bitmap, command.src_rect, command.scaling_mode); + }, [&](SetClipRect const& command) { return executor.set_clip_rect(command.rect); }, diff --git a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h index fbf09dec76..b1ee715e5e 100644 --- a/Userland/Libraries/LibWeb/Painting/RecordingPainter.h +++ b/Userland/Libraries/LibWeb/Painting/RecordingPainter.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -76,6 +77,15 @@ struct DrawScaledBitmap { [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } }; +struct DrawScaledImmutableBitmap { + Gfx::IntRect dst_rect; + NonnullRefPtr bitmap; + Gfx::IntRect src_rect; + Gfx::Painter::ScalingMode scaling_mode; + + [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } +}; + struct SetClipRect { Gfx::IntRect rect; }; @@ -314,6 +324,7 @@ using PaintingCommand = Variant< DrawText, FillRect, DrawScaledBitmap, + DrawScaledImmutableBitmap, SetClipRect, ClearClipRect, SetFont, @@ -351,6 +362,7 @@ public: virtual CommandResult draw_text(Gfx::IntRect const&, String const&, Gfx::TextAlignment alignment, Color const&, Gfx::TextElision, Gfx::TextWrapping, Optional> const&) = 0; virtual CommandResult fill_rect(Gfx::IntRect const&, Color const&) = 0; virtual CommandResult draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) = 0; + virtual CommandResult draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const&, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode) = 0; virtual CommandResult set_clip_rect(Gfx::IntRect const& rect) = 0; virtual CommandResult clear_clip_rect() = 0; virtual CommandResult set_font(Gfx::Font const& font) = 0; @@ -435,6 +447,7 @@ public: void draw_rect(Gfx::IntRect const& rect, Color color, bool rough = false); void draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode = Gfx::Painter::ScalingMode::NearestNeighbor); + void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode = Gfx::Painter::ScalingMode::NearestNeighbor); void draw_line(Gfx::IntPoint from, Gfx::IntPoint to, Color color, int thickness = 1, Gfx::Painter::LineStyle style = Gfx::Painter::LineStyle::Solid, Color alternate_color = Color::Transparent); diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp index 494d610940..f0c79a246f 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp @@ -101,8 +101,9 @@ SVGDecodedImageData::SVGDecodedImageData(NonnullOwnPtr page, NonnullOwnPtr SVGDecodedImageData::~SVGDecodedImageData() = default; -void SVGDecodedImageData::render(Gfx::IntSize size) const +RefPtr SVGDecodedImageData::render(Gfx::IntSize size) const { + auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors(); VERIFY(m_document->navigable()); m_document->navigable()->set_viewport_rect({ 0, 0, size.width(), size.height() }); m_document->update_layout(); @@ -112,21 +113,22 @@ void SVGDecodedImageData::render(Gfx::IntSize size) const m_document->paintable()->paint_all_phases(context); - Painting::PaintingCommandExecutorCPU executor { *m_bitmap }; + Painting::PaintingCommandExecutorCPU executor { *bitmap }; recording_painter.execute(executor); + + return bitmap; } -RefPtr SVGDecodedImageData::bitmap(size_t, Gfx::IntSize size) const +RefPtr SVGDecodedImageData::bitmap(size_t, Gfx::IntSize size) const { if (size.is_empty()) return nullptr; - if (m_bitmap && m_bitmap->size() == size) - return m_bitmap; + if (m_immutable_bitmap && m_immutable_bitmap->size() == size) + return m_immutable_bitmap; - m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors(); - render(size); - return m_bitmap; + m_immutable_bitmap = Gfx::ImmutableBitmap::create(*render(size)); + return m_immutable_bitmap; } Optional SVGDecodedImageData::intrinsic_width() const diff --git a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h index 7254832b7d..c308e4c0c5 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h +++ b/Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.h @@ -16,7 +16,7 @@ public: static ErrorOr> create(Page&, AK::URL const&, ByteBuffer encoded_svg); virtual ~SVGDecodedImageData() override; - virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize) const override; + virtual RefPtr bitmap(size_t frame_index, Gfx::IntSize) const override; virtual Optional intrinsic_width() const override; virtual Optional intrinsic_height() const override; @@ -34,8 +34,8 @@ private: class SVGPageClient; SVGDecodedImageData(NonnullOwnPtr, NonnullOwnPtr, JS::Handle, JS::Handle); - void render(Gfx::IntSize) const; - mutable RefPtr m_bitmap; + RefPtr render(Gfx::IntSize) const; + mutable RefPtr m_immutable_bitmap; NonnullOwnPtr m_page; NonnullOwnPtr m_page_client;