diff --git a/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp index a17a45e2d04..600debb1574 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/PNGLoader.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -239,11 +240,11 @@ ErrorOr PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in case PNG_BLEND_OP_SOURCE: // All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region. painter->clear_rect(frame_rect, Gfx::Color::Transparent); - painter->draw_bitmap(frame_rect, *decoded_frame_bitmap, decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, 1.0f); + painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), Gfx::ScalingMode::NearestNeighbor, 1.0f); break; case PNG_BLEND_OP_OVER: // The frame should be composited onto the output buffer based on its alpha, using a simple OVER operation as described in the "Alpha Channel Processing" section of the PNG specification. - painter->draw_bitmap(frame_rect, *decoded_frame_bitmap, decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, 1.0f); + painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*decoded_frame_bitmap), decoded_frame_bitmap->rect(), ScalingMode::NearestNeighbor, 1.0f); break; default: VERIFY_NOT_REACHED(); @@ -262,7 +263,7 @@ ErrorOr PNGLoadingContext::read_frames(png_structp png_ptr, png_infop in case PNG_DISPOSE_OP_PREVIOUS: // The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame. painter->clear_rect(frame_rect, Gfx::Color::Transparent); - painter->draw_bitmap(frame_rect, *prev_output_buffer, IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, 1.0f); + painter->draw_bitmap(frame_rect, Gfx::ImmutableBitmap::create(*prev_output_buffer), IntRect { x, y, width, height }, Gfx::ScalingMode::NearestNeighbor, 1.0f); break; default: VERIFY_NOT_REACHED(); diff --git a/Userland/Libraries/LibGfx/ImmutableBitmap.cpp b/Userland/Libraries/LibGfx/ImmutableBitmap.cpp index 655ec423c84..79a52b15210 100644 --- a/Userland/Libraries/LibGfx/ImmutableBitmap.cpp +++ b/Userland/Libraries/LibGfx/ImmutableBitmap.cpp @@ -6,16 +6,105 @@ #include +#include +#include + namespace Gfx { +struct ImmutableBitmapImpl { + sk_sp sk_image; + SkBitmap sk_bitmap; + RefPtr gfx_bitmap; +}; + +int ImmutableBitmap::width() const +{ + return m_impl->sk_image->width(); +} + +int ImmutableBitmap::height() const +{ + return m_impl->sk_image->height(); +} + +IntRect ImmutableBitmap::rect() const +{ + return { {}, size() }; +} + +IntSize ImmutableBitmap::size() const +{ + return { width(), height() }; +} + +Gfx::AlphaType ImmutableBitmap::alpha_type() const +{ + return m_impl->sk_image->alphaType() == kPremul_SkAlphaType ? Gfx::AlphaType::Premultiplied : Gfx::AlphaType::Unpremultiplied; +} + +SkImage const* ImmutableBitmap::sk_image() const +{ + return m_impl->sk_image.get(); +} + +RefPtr ImmutableBitmap::bitmap() const +{ + return m_impl->gfx_bitmap; +} + +Color ImmutableBitmap::get_pixel(int x, int y) const +{ + if (m_impl->gfx_bitmap) { + return m_impl->gfx_bitmap->get_pixel(x, y); + } + VERIFY_NOT_REACHED(); +} + +static SkColorType to_skia_color_type(Gfx::BitmapFormat format) +{ + switch (format) { + case Gfx::BitmapFormat::Invalid: + return kUnknown_SkColorType; + case Gfx::BitmapFormat::BGRA8888: + case Gfx::BitmapFormat::BGRx8888: + return kBGRA_8888_SkColorType; + case Gfx::BitmapFormat::RGBA8888: + return kRGBA_8888_SkColorType; + case Gfx::BitmapFormat::RGBx8888: + return kRGB_888x_SkColorType; + default: + return kUnknown_SkColorType; + } +} + +static SkAlphaType to_skia_alpha_type(Gfx::AlphaType alpha_type) +{ + switch (alpha_type) { + case AlphaType::Premultiplied: + return kPremul_SkAlphaType; + case AlphaType::Unpremultiplied: + return kUnpremul_SkAlphaType; + default: + VERIFY_NOT_REACHED(); + } +} + NonnullRefPtr ImmutableBitmap::create(NonnullRefPtr bitmap) { - return adopt_ref(*new ImmutableBitmap(move(bitmap))); + ImmutableBitmapImpl impl; + auto info = SkImageInfo::Make(bitmap->width(), bitmap->height(), to_skia_color_type(bitmap->format()), to_skia_alpha_type(bitmap->alpha_type())); + impl.sk_bitmap.installPixels(info, const_cast(static_cast(bitmap->scanline(0))), bitmap->pitch()); + impl.sk_bitmap.setImmutable(); + impl.sk_image = impl.sk_bitmap.asImage(); + impl.gfx_bitmap = bitmap; + return adopt_ref(*new ImmutableBitmap(make(impl))); } -ImmutableBitmap::ImmutableBitmap(NonnullRefPtr bitmap) - : m_bitmap(move(bitmap)) +ImmutableBitmap::ImmutableBitmap(NonnullOwnPtr impl) + : m_impl(move(impl)) { } +ImmutableBitmap::~ImmutableBitmap() = default; + } diff --git a/Userland/Libraries/LibGfx/ImmutableBitmap.h b/Userland/Libraries/LibGfx/ImmutableBitmap.h index e8cf46ed066..e6b491c1e3d 100644 --- a/Userland/Libraries/LibGfx/ImmutableBitmap.h +++ b/Userland/Libraries/LibGfx/ImmutableBitmap.h @@ -7,31 +7,41 @@ #pragma once #include +#include #include #include #include #include +class SkImage; + namespace Gfx { +struct ImmutableBitmapImpl; + class ImmutableBitmap final : public RefCounted { public: static NonnullRefPtr create(NonnullRefPtr bitmap); - ~ImmutableBitmap() = default; + ~ImmutableBitmap(); - Bitmap const& bitmap() const { return *m_bitmap; } + int width() const; + int height() const; + IntRect rect() const; + IntSize size() const; - size_t width() const { return m_bitmap->width(); } - size_t height() const { return m_bitmap->height(); } + Gfx::AlphaType alpha_type() const; - IntRect rect() const { return m_bitmap->rect(); } - IntSize size() const { return m_bitmap->size(); } + SkImage const* sk_image() const; + + Color get_pixel(int x, int y) const; + + RefPtr bitmap() const; private: - NonnullRefPtr m_bitmap; + NonnullOwnPtr m_impl; - explicit ImmutableBitmap(NonnullRefPtr bitmap); + explicit ImmutableBitmap(NonnullOwnPtr bitmap); }; } diff --git a/Userland/Libraries/LibGfx/Painter.h b/Userland/Libraries/LibGfx/Painter.h index 3710ecf9c73..161a5e4ff49 100644 --- a/Userland/Libraries/LibGfx/Painter.h +++ b/Userland/Libraries/LibGfx/Painter.h @@ -23,7 +23,7 @@ public: virtual void clear_rect(Gfx::FloatRect const&, Gfx::Color) = 0; virtual void fill_rect(Gfx::FloatRect const&, Gfx::Color) = 0; - virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, float global_alpha) = 0; + virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, float global_alpha) = 0; virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness) = 0; virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, float thickness, float global_alpha) = 0; diff --git a/Userland/Libraries/LibGfx/PainterSkia.cpp b/Userland/Libraries/LibGfx/PainterSkia.cpp index 5093cfb2736..df86ad6c3ca 100644 --- a/Userland/Libraries/LibGfx/PainterSkia.cpp +++ b/Userland/Libraries/LibGfx/PainterSkia.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Andreas Kling + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,7 @@ #define AK_DONT_REPLACE_STD #include +#include #include #include @@ -28,35 +30,6 @@ namespace Gfx { -static SkColorType to_skia_color_type(Gfx::BitmapFormat format) -{ - switch (format) { - case Gfx::BitmapFormat::Invalid: - return kUnknown_SkColorType; - case Gfx::BitmapFormat::BGRA8888: - case Gfx::BitmapFormat::BGRx8888: - return kBGRA_8888_SkColorType; - case Gfx::BitmapFormat::RGBA8888: - return kRGBA_8888_SkColorType; - case Gfx::BitmapFormat::RGBx8888: - return kRGB_888x_SkColorType; - default: - return kUnknown_SkColorType; - } -} - -static SkAlphaType to_skia_alpha_type(Gfx::AlphaType alpha_type) -{ - switch (alpha_type) { - case AlphaType::Premultiplied: - return kPremul_SkAlphaType; - case AlphaType::Unpremultiplied: - return kUnpremul_SkAlphaType; - default: - VERIFY_NOT_REACHED(); - } -} - struct PainterSkia::Impl { RefPtr painting_surface; @@ -134,17 +107,13 @@ static SkSamplingOptions to_skia_sampling_options(Gfx::ScalingMode scaling_mode) } } -void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, float global_alpha) +void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, float global_alpha) { - SkBitmap sk_bitmap; - SkImageInfo info = SkImageInfo::Make(src_bitmap.width(), src_bitmap.height(), to_skia_color_type(src_bitmap.format()), to_skia_alpha_type(src_bitmap.alpha_type())); - sk_bitmap.installPixels(info, const_cast(static_cast(src_bitmap.scanline(0))), src_bitmap.pitch()); - SkPaint paint; paint.setAlpha(static_cast(global_alpha * 255)); impl().canvas()->drawImageRect( - sk_bitmap.asImage(), + src_bitmap.sk_image(), to_skia_rect(src_rect), to_skia_rect(dst_rect), to_skia_sampling_options(scaling_mode), diff --git a/Userland/Libraries/LibGfx/PainterSkia.h b/Userland/Libraries/LibGfx/PainterSkia.h index ba0f3b0390e..577ead75097 100644 --- a/Userland/Libraries/LibGfx/PainterSkia.h +++ b/Userland/Libraries/LibGfx/PainterSkia.h @@ -20,7 +20,7 @@ public: virtual void clear_rect(Gfx::FloatRect const&, Color) override; virtual void fill_rect(Gfx::FloatRect const&, Color) override; - virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, float global_alpha) override; + virtual void draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode, float global_alpha) override; virtual void stroke_path(Gfx::Path const&, Gfx::Color, float thickness) override; virtual void stroke_path(Gfx::Path const&, Gfx::PaintStyle const&, float thickness, float global_alpha) override; virtual void fill_path(Gfx::Path const&, Gfx::Color, Gfx::WindingRule) override; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index 1c4460c168d..8deffbce2a5 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -169,7 +169,7 @@ Optional ImageStyleValue::color_if_single_pixel_bitmap() const { if (auto const* b = bitmap(m_current_frame_index)) { if (b->width() == 1 && b->height() == 1) - return b->bitmap().get_pixel(0, 0); + return b->get_pixel(0, 0); } return {}; } diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp index a32504087ad..21480e61da5 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp +++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp @@ -13,10 +13,20 @@ namespace Web::HTML { static void default_source_size(CanvasImageSource const& image, float& source_width, float& source_height) { image.visit( + [&source_width, &source_height](JS::Handle const& source) { + if (source->immutable_bitmap()) { + source_width = source->immutable_bitmap()->width(); + source_height = source->immutable_bitmap()->height(); + } else { + // FIXME: This is very janky and not correct. + source_width = source->width(); + source_height = source->height(); + } + }, [&source_width, &source_height](JS::Handle const& source) { - if (source->bitmap()) { - source_width = source->bitmap()->width(); - source_height = source->bitmap()->height(); + if (source->current_image_bitmap()) { + source_width = source->current_image_bitmap()->width(); + source_height = source->current_image_bitmap()->height(); } else { // FIXME: This is very janky and not correct. source_width = source->width()->anim_val()->value(); diff --git a/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp b/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp index 1fecd41ebdd..384f4c3787c 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp @@ -46,8 +46,8 @@ void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFun // 6. The resulting bitmap is what is to be rendered, with the same origin and same scale. - auto const bitmap_width = m_bitmap->width(); - auto const bitmap_height = m_bitmap->height(); + auto const bitmap_width = m_immutable_bitmap->width(); + auto const bitmap_height = m_immutable_bitmap->height(); paint([=, this](auto point) { point.translate_by(physical_bounding_box.location()); @@ -78,8 +78,8 @@ void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFun VERIFY_NOT_REACHED(); } }(); - if (m_bitmap->rect().contains(point)) - return m_bitmap->get_pixel(point); + if (m_immutable_bitmap->rect().contains(point)) + return m_immutable_bitmap->get_pixel(point.x(), point.y()); return Gfx::Color(); }); } @@ -129,14 +129,11 @@ WebIDL::ExceptionOr> CanvasPattern::create(JS::Realm& r // Note: Bitmap won't be null here, as if it were it would have "bad" usability. auto bitmap = image.visit( - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { - auto snapshot = source->surface()->create_snapshot(); - return snapshot->bitmap(); - }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }); + [](JS::Handle const& source) -> RefPtr { return source->immutable_bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return source->current_image_bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return source->surface()->create_snapshot(); }, + [](JS::Handle const& source) -> RefPtr { return Gfx::ImmutableBitmap::create(*source->bitmap()); }, + [](JS::Handle const& source) -> RefPtr { return Gfx::ImmutableBitmap::create(*source->bitmap()); }); // 6. Let pattern be a new CanvasPattern object with the image image and the repetition behavior given by repetition. auto pattern = TRY_OR_THROW_OOM(realm.vm(), CanvasPatternPaintStyle::create(*bitmap, *repetition_value)); diff --git a/Userland/Libraries/LibWeb/HTML/CanvasPattern.h b/Userland/Libraries/LibWeb/HTML/CanvasPattern.h index 592a619cf56..c67f2ee91ac 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasPattern.h +++ b/Userland/Libraries/LibWeb/HTML/CanvasPattern.h @@ -21,7 +21,7 @@ public: NoRepeat }; - static ErrorOr> create(Gfx::Bitmap const& bitmap, Repetition repetition) + static ErrorOr> create(Gfx::ImmutableBitmap const& bitmap, Repetition repetition) { return adopt_nonnull_ref_or_enomem(new (nothrow) CanvasPatternPaintStyle(bitmap, repetition)); } @@ -29,13 +29,13 @@ public: virtual void paint(Gfx::IntRect physical_bounding_box, PaintFunction paint) const override; private: - CanvasPatternPaintStyle(Gfx::Bitmap const& bitmap, Repetition repetition) - : m_bitmap(bitmap) + CanvasPatternPaintStyle(Gfx::ImmutableBitmap const& immutable_bitmap, Repetition repetition) + : m_immutable_bitmap(immutable_bitmap) , m_repetition(repetition) { } - NonnullRefPtr m_bitmap; + NonnullRefPtr m_immutable_bitmap; Repetition m_repetition { Repetition::Repeat }; }; diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 572cd8af639..811b9a4ccdb 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -124,14 +124,22 @@ WebIDL::ExceptionOr CanvasRenderingContext2D::draw_image_internal(CanvasIm return {}; auto bitmap = image.visit( - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { - auto snapshot = source->surface()->create_snapshot(); - return snapshot->bitmap(); + [](JS::Handle const& source) -> RefPtr { + return source->immutable_bitmap(); }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, - [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }); + [](JS::Handle const& source) -> RefPtr { + return source->current_image_bitmap(); + }, + [](JS::Handle const& source) -> RefPtr { + auto surface = source->surface(); + if (!surface) + return {}; + return source->surface()->create_snapshot(); + }, + [](JS::Handle const& source) -> RefPtr { return Gfx::ImmutableBitmap::create(*source->bitmap()); }, + [](JS::Handle const& source) -> RefPtr { + return Gfx::ImmutableBitmap::create(*source->bitmap()); + }); if (!bitmap) return {}; @@ -394,7 +402,6 @@ WebIDL::ExceptionOr> CanvasRenderingContext2D::get_image_da if (!canvas_element().surface()) return image_data; auto const snapshot = canvas_element().surface()->create_snapshot(); - auto const& bitmap = snapshot->bitmap(); // 5. Let the source rectangle be the rectangle whose corners are the four points (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh). auto source_rect = Gfx::Rect { x, y, abs_width, abs_height }; @@ -405,17 +412,17 @@ WebIDL::ExceptionOr> CanvasRenderingContext2D::get_image_da if (width < 0 || height < 0) { source_rect = source_rect.translated(min(width, 0), min(height, 0)); } - auto source_rect_intersected = source_rect.intersected(bitmap.rect()); + auto source_rect_intersected = source_rect.intersected(snapshot->rect()); // 6. Set the pixel values of imageData to be the pixels of this's output bitmap in the area specified by the source rectangle in the bitmap's coordinate space units, converted from this's color space to imageData's colorSpace using 'relative-colorimetric' rendering intent. // NOTE: Internally we must use premultiplied alpha, but ImageData should hold unpremultiplied alpha. This conversion // might result in a loss of precision, but is according to spec. // See: https://html.spec.whatwg.org/multipage/canvas.html#premultiplied-alpha-and-the-2d-rendering-context - ASSERT(bitmap.alpha_type() == Gfx::AlphaType::Premultiplied); + ASSERT(snapshot->alpha_type() == Gfx::AlphaType::Premultiplied); ASSERT(image_data->bitmap().alpha_type() == Gfx::AlphaType::Unpremultiplied); auto painter = Gfx::Painter::create(image_data->bitmap()); - painter->draw_bitmap(image_data->bitmap().rect().to_type(), bitmap, source_rect_intersected, Gfx::ScalingMode::NearestNeighbor, drawing_state().global_alpha); + painter->draw_bitmap(image_data->bitmap().rect().to_type(), *snapshot, source_rect_intersected, Gfx::ScalingMode::NearestNeighbor, drawing_state().global_alpha); // 7. Set the pixels values of imageData for areas of the source rectangle that are outside of the output bitmap to transparent black. // NOTE: No-op, already done during creation. @@ -428,7 +435,7 @@ void CanvasRenderingContext2D::put_image_data(ImageData const& image_data, float { if (auto* painter = this->painter()) { auto dst_rect = Gfx::FloatRect(x, y, image_data.width(), image_data.height()); - painter->draw_bitmap(dst_rect, image_data.bitmap(), image_data.bitmap().rect(), Gfx::ScalingMode::NearestNeighbor, 1.0f); + painter->draw_bitmap(dst_rect, Gfx::ImmutableBitmap::create(image_data.bitmap()), image_data.bitmap().rect(), Gfx::ScalingMode::NearestNeighbor, 1.0f); did_draw(dst_rect); } } @@ -622,11 +629,11 @@ WebIDL::ExceptionOr check_usability_of_image(CanvasI // FIXME: If image's current request's state is broken, then throw an "InvalidStateError" DOMException. // If image is not fully decodable, then return bad. - if (!image_element->bitmap()) + if (!image_element->immutable_bitmap()) return { CanvasImageSourceUsability::Bad }; // If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad. - if (image_element->bitmap()->width() == 0 || image_element->bitmap()->height() == 0) + if (image_element->immutable_bitmap()->width() == 0 || image_element->immutable_bitmap()->height() == 0) return { CanvasImageSourceUsability::Bad }; return Optional {}; }, @@ -635,11 +642,11 @@ WebIDL::ExceptionOr check_usability_of_image(CanvasI // FIXME: If image's current request's state is broken, then throw an "InvalidStateError" DOMException. // If image is not fully decodable, then return bad. - if (!image_element->bitmap()) + if (!image_element->current_image_bitmap()) return { CanvasImageSourceUsability::Bad }; // If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad. - if (image_element->bitmap()->width() == 0 || image_element->bitmap()->height() == 0) + if (image_element->current_image_bitmap()->width() == 0 || image_element->current_image_bitmap()->height() == 0) return { CanvasImageSourceUsability::Bad }; return Optional {}; }, diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp index b50b4a5aa30..e11f4bec403 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp @@ -269,7 +269,9 @@ String HTMLCanvasElement::to_data_url(StringView type, Optional quality) // 3. Let file be a serialization of this canvas element's bitmap as a file, passing type and quality if given. auto snapshot = m_surface->create_snapshot(); - auto file = serialize_bitmap(snapshot->bitmap(), type, move(quality)); + auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, m_surface->size())); + m_surface->read_into_bitmap(*bitmap); + auto file = serialize_bitmap(bitmap, type, move(quality)); // 4. If file is null then return "data:,". if (file.is_error()) { @@ -301,8 +303,8 @@ WebIDL::ExceptionOr HTMLCanvasElement::to_blob(JS::NonnullGCPtrcreate_snapshot(); - bitmap_result = snapshot->bitmap(); + bitmap_result = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, m_surface->size())); + m_surface->read_into_bitmap(*bitmap_result); } // 4. Run these steps in parallel: diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp index d969fb13993..e8883815831 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2023, Andreas Kling + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -120,13 +121,6 @@ RefPtr HTMLImageElement::immutable_bitmap() const return current_image_bitmap(); } -RefPtr HTMLImageElement::bitmap() const -{ - if (auto immutable_bitmap = this->immutable_bitmap()) - return immutable_bitmap->bitmap(); - return {}; -} - bool HTMLImageElement::is_image_available() const { return m_current_request && m_current_request->is_available(); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h index 2c1c03d15d7..2a2d9ed8473 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2023, Andreas Kling + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -43,7 +44,6 @@ public: String src() const { return get_attribute_value(HTML::AttributeNames::src); } RefPtr immutable_bitmap() const; - RefPtr bitmap() const; unsigned width() const; WebIDL::ExceptionOr set_width(unsigned); diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index dff882b0db0..6ccaa562b1e 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2021, Andreas Kling * Copyright (c) 2021, Max Wipfli + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -337,7 +338,7 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix if (is(*node)) { auto& image_element = verify_cast(*node); auto image_url = image_element.document().parse_url(image_element.src()); - m_navigable->page().client().page_did_request_image_context_menu(viewport_position, image_url, "", modifiers, image_element.bitmap()); + m_navigable->page().client().page_did_request_image_context_menu(viewport_position, image_url, "", modifiers, image_element.immutable_bitmap()->bitmap()); } else if (is(*node)) { auto& media_element = verify_cast(*node); diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index 55f1eff50fd..74acd1acd80 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -381,18 +381,13 @@ void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitm { auto src_rect = to_skia_rect(command.src_rect); auto dst_rect = to_skia_rect(command.dst_rect); - auto bitmap = to_skia_bitmap(command.bitmap->bitmap()); - auto image = SkImages::RasterFromBitmap(bitmap); auto& canvas = surface().canvas(); SkPaint paint; - canvas.drawImageRect(image, src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint); + canvas.drawImageRect(command.bitmap->sk_image(), src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint); } void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const& command) { - auto bitmap = to_skia_bitmap(command.bitmap->bitmap()); - auto image = SkImages::RasterFromBitmap(bitmap); - SkMatrix matrix; auto dst_rect = command.dst_rect.to_type(); auto src_size = command.bitmap->size().to_type(); @@ -402,7 +397,7 @@ void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutable auto tile_mode_x = command.repeat.x ? SkTileMode::kRepeat : SkTileMode::kDecal; auto tile_mode_y = command.repeat.y ? SkTileMode::kRepeat : SkTileMode::kDecal; - auto shader = image->makeShader(tile_mode_x, tile_mode_y, sampling_options, matrix); + auto shader = command.bitmap->sk_image()->makeShader(tile_mode_x, tile_mode_y, sampling_options, matrix); SkPaint paint; paint.setShader(shader); diff --git a/Userland/Libraries/LibWeb/SVG/SVGImageElement.h b/Userland/Libraries/LibWeb/SVG/SVGImageElement.h index a792ed5c262..9e427a27925 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGImageElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGImageElement.h @@ -29,15 +29,6 @@ public: Gfx::Rect bounding_box() const; - // FIXME: This is a hack for images used as CanvasImageSource. Do something more elegant. - RefPtr bitmap() const - { - auto bitmap = current_image_bitmap(); - if (!bitmap) - return nullptr; - return bitmap->bitmap(); - } - // ^Layout::ImageProvider virtual bool is_image_available() const override; virtual Optional intrinsic_width() const override; diff --git a/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp b/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp index 3364a67b1c3..9c68bda7c53 100644 --- a/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp @@ -52,7 +52,9 @@ ErrorOr, WebDriver::Error> draw_boundi // - Height: paint height Gfx::IntRect paint_rect { rect.x(), rect.y(), paint_width, paint_height }; - auto backing_store = Web::Painting::BitmapBackingStore(canvas.surface()->create_snapshot()->bitmap()); + auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, canvas.surface()->size())); + canvas.surface()->read_into_bitmap(*bitmap); + auto backing_store = Web::Painting::BitmapBackingStore(bitmap); browsing_context.page().client().paint(paint_rect.to_type(), backing_store); // 7. Return success with canvas. diff --git a/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h index 92b500dcf8e..5578b3985a6 100644 --- a/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h +++ b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h @@ -15,7 +15,7 @@ class OpenGLContext { public: static OwnPtr create(Gfx::PaintingSurface&); - virtual void present(Gfx::Bitmap const&) = 0; + virtual void present() = 0; void clear_buffer_to_default_values(); virtual GLenum gl_get_error() = 0; diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp index 68c9378094a..589b8a1f2f2 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp @@ -53,7 +53,7 @@ void WebGLRenderingContextBase::present() // FIXME: Is this the operation it means? m_context->gl_flush(); - m_context->present(canvas_element().surface()->create_snapshot()->bitmap()); + m_context->present(); // "By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above. // This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object.