diff --git a/Libraries/LibGfx/PainterSkia.cpp b/Libraries/LibGfx/PainterSkia.cpp index 375595912be..fda2a0cdbde 100644 --- a/Libraries/LibGfx/PainterSkia.cpp +++ b/Libraries/LibGfx/PainterSkia.cpp @@ -125,11 +125,11 @@ PainterSkia::~PainterSkia() = default; void PainterSkia::clear_rect(Gfx::FloatRect const& rect, Gfx::Color color) { - SkPaint paint; - paint.setColor(to_skia_color(color)); - paint.setBlendMode(SkBlendMode::kClear); impl().with_canvas([&](auto& canvas) { - canvas.drawRect(to_skia_rect(rect), paint); + canvas.save(); + canvas.clipRect(to_skia_rect(rect)); + canvas.clear(to_skia_color(color)); + canvas.restore(); }); } diff --git a/Libraries/LibGfx/PaintingSurface.cpp b/Libraries/LibGfx/PaintingSurface.cpp index e364dd105ed..68029c98204 100644 --- a/Libraries/LibGfx/PaintingSurface.cpp +++ b/Libraries/LibGfx/PaintingSurface.cpp @@ -30,7 +30,7 @@ struct PaintingSurface::Impl { NonnullRefPtr PaintingSurface::create_with_size(RefPtr context, IntSize size, BitmapFormat color_type, AlphaType alpha_type) { auto sk_color_type = to_skia_color_type(color_type); - auto sk_alpha_type = alpha_type == AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + auto sk_alpha_type = to_skia_alpha_type(color_type, alpha_type); auto image_info = SkImageInfo::Make(size.width(), size.height(), sk_color_type, sk_alpha_type, SkColorSpace::MakeSRGB()); if (!context) { @@ -50,7 +50,7 @@ NonnullRefPtr PaintingSurface::create_with_size(RefPtr PaintingSurface::wrap_bitmap(Bitmap& bitmap) { auto color_type = to_skia_color_type(bitmap.format()); - auto alpha_type = bitmap.alpha_type() == AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + auto alpha_type = to_skia_alpha_type(bitmap.format(), bitmap.alpha_type()); auto size = bitmap.size(); auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type, SkColorSpace::MakeSRGB()); auto surface = SkSurfaces::WrapPixels(image_info, bitmap.begin(), bitmap.pitch()); @@ -102,7 +102,7 @@ PaintingSurface::~PaintingSurface() void PaintingSurface::read_into_bitmap(Bitmap& bitmap) { auto color_type = to_skia_color_type(bitmap.format()); - auto alpha_type = bitmap.alpha_type() == AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + auto alpha_type = to_skia_alpha_type(bitmap.format(), bitmap.alpha_type()); auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type, SkColorSpace::MakeSRGB()); SkPixmap const pixmap(image_info, bitmap.begin(), bitmap.pitch()); m_impl->surface->readPixels(pixmap, 0, 0); @@ -111,7 +111,7 @@ void PaintingSurface::read_into_bitmap(Bitmap& bitmap) void PaintingSurface::write_from_bitmap(Bitmap const& bitmap) { auto color_type = to_skia_color_type(bitmap.format()); - auto alpha_type = bitmap.alpha_type() == AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + auto alpha_type = to_skia_alpha_type(bitmap.format(), bitmap.alpha_type()); auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type, SkColorSpace::MakeSRGB()); SkPixmap const pixmap(image_info, bitmap.begin(), bitmap.pitch()); m_impl->surface->writePixels(pixmap, 0, 0); diff --git a/Libraries/LibGfx/SkiaUtils.h b/Libraries/LibGfx/SkiaUtils.h index 4d484682fc1..8dc590a8d9c 100644 --- a/Libraries/LibGfx/SkiaUtils.h +++ b/Libraries/LibGfx/SkiaUtils.h @@ -40,6 +40,20 @@ constexpr SkColorType to_skia_color_type(Gfx::BitmapFormat format) VERIFY_NOT_REACHED(); } +constexpr SkAlphaType to_skia_alpha_type(Gfx::BitmapFormat format, Gfx::AlphaType alpha_type) +{ + if (format == BitmapFormat::BGRx8888 || format == BitmapFormat::RGBx8888) + return kOpaque_SkAlphaType; + + switch (alpha_type) { + case AlphaType::Premultiplied: + return kPremul_SkAlphaType; + case AlphaType::Unpremultiplied: + return kUnpremul_SkAlphaType; + } + VERIFY_NOT_REACHED(); +} + constexpr SkRect to_skia_rect(auto const& rect) { return SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()); diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index bea78210ce7..78c86b7cef8 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -149,7 +149,7 @@ void CanvasRenderingContext2D::clear_rect(float x, float y, float width, float h { if (auto* painter = this->painter()) { auto rect = Gfx::FloatRect(x, y, width, height); - painter->clear_rect(rect, Color::Transparent); + painter->clear_rect(rect, clear_color()); did_draw(rect); } } @@ -270,14 +270,23 @@ void CanvasRenderingContext2D::allocate_painting_surface_if_needed() if (m_surface || m_size.is_empty()) return; - // FIXME: implement context attribute .alpha // FIXME: implement context attribute .color_space // FIXME: implement context attribute .color_type // FIXME: implement context attribute .desynchronized // FIXME: implement context attribute .will_read_frequently + auto color_type = m_context_attributes.alpha ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888; + auto skia_backend_context = canvas_element().navigable()->traversable_navigable()->skia_backend_context(); - m_surface = Gfx::PaintingSurface::create_with_size(skia_backend_context, canvas_element().bitmap_size_for_canvas(), Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied); + m_surface = Gfx::PaintingSurface::create_with_size(skia_backend_context, canvas_element().bitmap_size_for_canvas(), color_type, Gfx::AlphaType::Premultiplied); + + // https://html.spec.whatwg.org/multipage/canvas.html#the-canvas-settings:concept-canvas-alpha + // Thus, the bitmap of such a context starts off as opaque black instead of transparent black; + // AD-HOC: Skia provides us with a full transparent surface by default; only clear the surface if alpha is disabled. + if (!m_context_attributes.alpha) { + auto* painter = this->painter(); + painter->clear_rect(m_surface->rect().to_type(), clear_color()); + } } Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y, Optional max_width) @@ -377,6 +386,12 @@ static Gfx::Path::JoinStyle to_gfx_join(Bindings::CanvasLineJoin const& join_sty VERIFY_NOT_REACHED(); } +// https://html.spec.whatwg.org/multipage/canvas.html#the-canvas-settings:concept-canvas-alpha +Gfx::Color CanvasRenderingContext2D::clear_color() const +{ + return m_context_attributes.alpha ? Gfx::Color::Transparent : Gfx::Color::Black; +} + void CanvasRenderingContext2D::stroke_internal(Gfx::Path const& path) { auto* painter = this->painter(); @@ -561,7 +576,7 @@ void CanvasRenderingContext2D::reset_to_default_state() // 1. Clear canvas's bitmap to transparent black. if (surface) { - painter()->clear_rect(surface->rect().to_type(), Color::Transparent); + painter()->clear_rect(surface->rect().to_type(), clear_color()); } // 2. Empty the list of subpaths in context's current default path. diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h index 8e459389707..ecc6c2a1858 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h @@ -160,6 +160,8 @@ private: [[nodiscard]] Gfx::Path rect_path(float x, float y, float width, float height); [[nodiscard]] Gfx::Path text_path(StringView text, float x, float y, Optional max_width); + Gfx::Color clear_color() const; + void stroke_internal(Gfx::Path const&); void fill_internal(Gfx::Path const&, Gfx::WindingRule); void clip_internal(Gfx::Path&, Gfx::WindingRule); diff --git a/Tests/LibWeb/Ref/expected/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false-ref.html b/Tests/LibWeb/Ref/expected/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false-ref.html new file mode 100644 index 00000000000..eccfc4e2cca --- /dev/null +++ b/Tests/LibWeb/Ref/expected/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false-ref.html @@ -0,0 +1,10 @@ + + +CanvasRenderingContext 2D with alpha=flase, fillRect with semi-transparent color. +

Test passes if a 100x100 black square is displayed below.

+ + diff --git a/Tests/LibWeb/Ref/input/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false.html b/Tests/LibWeb/Ref/input/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false.html new file mode 100644 index 00000000000..d6987bbccee --- /dev/null +++ b/Tests/LibWeb/Ref/input/wpt-import/html/canvas/element/manual/context-attributes/clearRect_alpha_false.html @@ -0,0 +1,15 @@ + + +CanvasRenderingContext 2D with alpha=flase, clearRect + + + + +

Test passes if a 100x100 black square is displayed below.

+ +