diff --git a/Libraries/LibGfx/Bitmap.cpp b/Libraries/LibGfx/Bitmap.cpp index b4f97b4bbd7..f2f9f5e1185 100644 --- a/Libraries/LibGfx/Bitmap.cpp +++ b/Libraries/LibGfx/Bitmap.cpp @@ -245,4 +245,26 @@ bool Bitmap::visually_equals(Bitmap const& other) const return true; } +void Bitmap::set_alpha_type_destructive(AlphaType alpha_type) +{ + if (alpha_type == m_alpha_type) + return; + + if (m_alpha_type == AlphaType::Unpremultiplied) { + for (auto y = 0; y < height(); ++y) { + for (auto x = 0; x < width(); ++x) + set_pixel(x, y, get_pixel(x, y).to_premultiplied()); + } + } else if (m_alpha_type == AlphaType::Premultiplied) { + for (auto y = 0; y < height(); ++y) { + for (auto x = 0; x < width(); ++x) + set_pixel(x, y, get_pixel(x, y).to_unpremultiplied()); + } + } else { + VERIFY_NOT_REACHED(); + } + + m_alpha_type = alpha_type; +} + } diff --git a/Libraries/LibGfx/Bitmap.h b/Libraries/LibGfx/Bitmap.h index ef92c4bb5c2..b987690fd5e 100644 --- a/Libraries/LibGfx/Bitmap.h +++ b/Libraries/LibGfx/Bitmap.h @@ -145,6 +145,7 @@ public: [[nodiscard]] bool visually_equals(Bitmap const&) const; [[nodiscard]] AlphaType alpha_type() const { return m_alpha_type; } + void set_alpha_type_destructive(AlphaType); private: Bitmap(BitmapFormat, AlphaType, IntSize, BackingStore const&); diff --git a/Libraries/LibGfx/Color.h b/Libraries/LibGfx/Color.h index b0b3459d499..6b62fb4175b 100644 --- a/Libraries/LibGfx/Color.h +++ b/Libraries/LibGfx/Color.h @@ -253,6 +253,15 @@ public: return color_with_alpha; } + constexpr Color to_premultiplied() const + { + return Color( + red() * alpha() / 255, + green() * alpha() / 255, + blue() * alpha() / 255, + alpha()); + } + constexpr Color to_unpremultiplied() const { if (alpha() == 0 || alpha() == 255) diff --git a/Libraries/LibGfx/ImmutableBitmap.cpp b/Libraries/LibGfx/ImmutableBitmap.cpp index 720b411abcf..45ad362b2d9 100644 --- a/Libraries/LibGfx/ImmutableBitmap.cpp +++ b/Libraries/LibGfx/ImmutableBitmap.cpp @@ -87,6 +87,19 @@ NonnullRefPtr ImmutableBitmap::create(NonnullRefPtr bit return adopt_ref(*new ImmutableBitmap(make(impl))); } +NonnullRefPtr ImmutableBitmap::create(NonnullRefPtr bitmap, AlphaType alpha_type, ColorSpace color_space) +{ + // Convert the source bitmap to the right alpha type on a mismatch. We want to do this when converting from a + // Bitmap to an ImmutableBitmap, since at that point we usually know the right alpha type to use in context. + auto source_bitmap = bitmap; + if (source_bitmap->alpha_type() != alpha_type) { + source_bitmap = MUST(bitmap->clone()); + source_bitmap->set_alpha_type_destructive(alpha_type); + } + + return create(source_bitmap, move(color_space)); +} + NonnullRefPtr ImmutableBitmap::create_snapshot_from_painting_surface(NonnullRefPtr painting_surface) { ImmutableBitmapImpl impl; diff --git a/Libraries/LibGfx/ImmutableBitmap.h b/Libraries/LibGfx/ImmutableBitmap.h index d1565ba80c5..4c8c94b9d2a 100644 --- a/Libraries/LibGfx/ImmutableBitmap.h +++ b/Libraries/LibGfx/ImmutableBitmap.h @@ -23,6 +23,7 @@ struct ImmutableBitmapImpl; class ImmutableBitmap final : public RefCounted { public: static NonnullRefPtr create(NonnullRefPtr bitmap, ColorSpace color_space = {}); + static NonnullRefPtr create(NonnullRefPtr bitmap, AlphaType, ColorSpace color_space = {}); static NonnullRefPtr create_snapshot_from_painting_surface(NonnullRefPtr); ~ImmutableBitmap(); diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index a7694b7a304..f6f3ab882a0 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -478,7 +478,14 @@ void CanvasRenderingContext2D::put_image_data(ImageData const& image_data, float // https://html.spec.whatwg.org/multipage/canvas.html#dom-context2d-putimagedata-common if (auto* painter = this->painter()) { auto dst_rect = Gfx::FloatRect(x, y, image_data.width(), image_data.height()); - painter->draw_bitmap(dst_rect, Gfx::ImmutableBitmap::create(image_data.bitmap()), image_data.bitmap().rect(), Gfx::ScalingMode::NearestNeighbor, drawing_state().filters, 1.0f, Gfx::CompositingAndBlendingOperator::SourceOver); + painter->draw_bitmap( + dst_rect, + Gfx::ImmutableBitmap::create(image_data.bitmap(), Gfx::AlphaType::Unpremultiplied), + image_data.bitmap().rect(), + Gfx::ScalingMode::NearestNeighbor, + drawing_state().filters, + 1.0f, + Gfx::CompositingAndBlendingOperator::SourceOver); did_draw(dst_rect); } } diff --git a/Libraries/LibWeb/HTML/SharedResourceRequest.cpp b/Libraries/LibWeb/HTML/SharedResourceRequest.cpp index dd26e4aa24b..8ed274a8d8d 100644 --- a/Libraries/LibWeb/HTML/SharedResourceRequest.cpp +++ b/Libraries/LibWeb/HTML/SharedResourceRequest.cpp @@ -161,7 +161,7 @@ void SharedResourceRequest::handle_successful_fetch(URL::URL const& url_string, Vector frames; for (auto& frame : result.frames) { frames.append(AnimatedBitmapDecodedImageData::Frame { - .bitmap = Gfx::ImmutableBitmap::create(*frame.bitmap, result.color_space), + .bitmap = Gfx::ImmutableBitmap::create(*frame.bitmap, Gfx::AlphaType::Premultiplied, result.color_space), .duration = static_cast(frame.duration), }); } diff --git a/Tests/LibWeb/Screenshot/expected/image-unpremultiplied-data-ref.html b/Tests/LibWeb/Screenshot/expected/image-unpremultiplied-data-ref.html new file mode 100644 index 00000000000..1c832cd820f --- /dev/null +++ b/Tests/LibWeb/Screenshot/expected/image-unpremultiplied-data-ref.html @@ -0,0 +1,16 @@ + + + + diff --git a/Tests/LibWeb/Screenshot/images/border-radius-ref.png b/Tests/LibWeb/Screenshot/images/border-radius-ref.png index fc947c23b77..73d70a29bd6 100644 Binary files a/Tests/LibWeb/Screenshot/images/border-radius-ref.png and b/Tests/LibWeb/Screenshot/images/border-radius-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/canvas-filters.png b/Tests/LibWeb/Screenshot/images/canvas-filters.png index 6995c914d6e..fc9fa96c827 100644 Binary files a/Tests/LibWeb/Screenshot/images/canvas-filters.png and b/Tests/LibWeb/Screenshot/images/canvas-filters.png differ diff --git a/Tests/LibWeb/Screenshot/images/css-backgrounds-ref.png b/Tests/LibWeb/Screenshot/images/css-backgrounds-ref.png index c55f9510649..495b9b71246 100644 Binary files a/Tests/LibWeb/Screenshot/images/css-backgrounds-ref.png and b/Tests/LibWeb/Screenshot/images/css-backgrounds-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/image-unpremultiplied-data-ref.png b/Tests/LibWeb/Screenshot/images/image-unpremultiplied-data-ref.png new file mode 100644 index 00000000000..84924ee39ce Binary files /dev/null and b/Tests/LibWeb/Screenshot/images/image-unpremultiplied-data-ref.png differ diff --git a/Tests/LibWeb/Screenshot/images/object-fit-position.png b/Tests/LibWeb/Screenshot/images/object-fit-position.png index 99caac63595..1f4552f0c09 100644 Binary files a/Tests/LibWeb/Screenshot/images/object-fit-position.png and b/Tests/LibWeb/Screenshot/images/object-fit-position.png differ diff --git a/Tests/LibWeb/Screenshot/input/image-unpremultiplied-data.html b/Tests/LibWeb/Screenshot/input/image-unpremultiplied-data.html new file mode 100644 index 00000000000..793ec1fd484 --- /dev/null +++ b/Tests/LibWeb/Screenshot/input/image-unpremultiplied-data.html @@ -0,0 +1,3 @@ + + +