diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index 3de5f3268877..c8a06a3f794b 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -6,6 +6,7 @@ #include #include +#include namespace Gfx { @@ -13,7 +14,8 @@ Painter::~Painter() = default; NonnullOwnPtr Painter::create(NonnullRefPtr target_bitmap) { - return make(move(target_bitmap)); + auto painting_surface = PaintingSurface::wrap_bitmap(target_bitmap); + return make(painting_surface); } } diff --git a/Userland/Libraries/LibGfx/PainterSkia.cpp b/Userland/Libraries/LibGfx/PainterSkia.cpp index 03f10765ae33..9bb57826e5ba 100644 --- a/Userland/Libraries/LibGfx/PainterSkia.cpp +++ b/Userland/Libraries/LibGfx/PainterSkia.cpp @@ -56,21 +56,17 @@ static SkAlphaType to_skia_alpha_type(Gfx::AlphaType alpha_type) } struct PainterSkia::Impl { - NonnullRefPtr gfx_bitmap; - OwnPtr sk_bitmap; - OwnPtr sk_canvas; + RefPtr painting_surface; - Impl(NonnullRefPtr target_bitmap) - : gfx_bitmap(move(target_bitmap)) + Impl(Gfx::PaintingSurface& surface) + : painting_surface(surface) { - sk_bitmap = make(); - SkImageInfo info = SkImageInfo::Make(gfx_bitmap->width(), gfx_bitmap->height(), to_skia_color_type(gfx_bitmap->format()), to_skia_alpha_type(gfx_bitmap->alpha_type())); - sk_bitmap->installPixels(info, gfx_bitmap->scanline(0), gfx_bitmap->pitch()); - - sk_canvas = make(*sk_bitmap); } - SkCanvas* canvas() { return sk_canvas; } + SkCanvas* canvas() const + { + return &painting_surface->canvas(); + } }; static constexpr SkRect to_skia_rect(auto const& rect) @@ -99,8 +95,8 @@ static SkPathFillType to_skia_path_fill_type(Gfx::WindingRule winding_rule) VERIFY_NOT_REACHED(); } -PainterSkia::PainterSkia(NonnullRefPtr target_bitmap) - : m_impl(adopt_own(*new Impl { move(target_bitmap) })) +PainterSkia::PainterSkia(NonnullRefPtr painting_surface) + : m_impl(adopt_own(*new Impl { move(painting_surface) })) { } diff --git a/Userland/Libraries/LibGfx/PainterSkia.h b/Userland/Libraries/LibGfx/PainterSkia.h index b0440f39d660..ba0f3b0390e8 100644 --- a/Userland/Libraries/LibGfx/PainterSkia.h +++ b/Userland/Libraries/LibGfx/PainterSkia.h @@ -9,12 +9,13 @@ #include #include #include +#include namespace Gfx { class PainterSkia final : public Painter { public: - explicit PainterSkia(NonnullRefPtr); + explicit PainterSkia(NonnullRefPtr); virtual ~PainterSkia() override; virtual void clear_rect(Gfx::FloatRect const&, Color) override; diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp index 5cfe17501ee8..eb06bc6d67cf 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp +++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasDrawImage.cpp @@ -11,15 +11,25 @@ namespace Web::HTML { static void default_source_size(CanvasImageSource const& image, float& source_width, float& source_height) { - image.visit([&source_width, &source_height](auto const& source) { - if (source->bitmap()) { - source_width = source->bitmap()->width(); - source_height = source->bitmap()->height(); - } else { - source_width = source->width(); - source_height = source->height(); - } - }); + image.visit( + [&source_width, &source_height](JS::Handle const& source) { + if (source->surface()) { + source_width = source->surface()->size().width(); + source_height = source->surface()->size().height(); + } else { + source_width = source->width(); + source_height = source->height(); + } + }, + [&source_width, &source_height](auto const& source) { + if (source->bitmap()) { + source_width = source->bitmap()->width(); + source_height = source->bitmap()->height(); + } else { + source_width = source->width(); + source_height = source->height(); + } + }); } WebIDL::ExceptionOr CanvasDrawImage::draw_image(Web::HTML::CanvasImageSource const& image, float destination_x, float destination_y) diff --git a/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp b/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp index c58fa97e2e89..879ece3744f1 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasPattern.cpp @@ -126,10 +126,14 @@ WebIDL::ExceptionOr> CanvasPattern::create(JS::Realm& r return WebIDL::SyntaxError::create(realm, "Repetition value is not valid"_fly_string); // Note: Bitmap won't be null here, as if it were it would have "bad" usability. - auto const& bitmap = *image.visit([](auto const& source) -> Gfx::Bitmap const* { return source->bitmap(); }); + auto bitmap = image.visit( + [](JS::Handle const& source) -> RefPtr { return source->surface()->create_snapshot(); }, + [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return *source->bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return &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)); + auto pattern = TRY_OR_THROW_OOM(realm.vm(), CanvasPatternPaintStyle::create(*bitmap, *repetition_value)); // FIXME: 7. If image is not origin-clean, then mark pattern as not origin-clean. diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 08d491895833..5b682bc838ea 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -120,7 +121,11 @@ WebIDL::ExceptionOr CanvasRenderingContext2D::draw_image_internal(CanvasIm if (usability == CanvasImageSourceUsability::Bad) return {}; - auto const* bitmap = image.visit([](auto const& source) -> Gfx::Bitmap const* { return source->bitmap(); }); + auto const bitmap = image.visit( + [](JS::Handle const& source) -> RefPtr { return source->surface()->create_snapshot(); }, + [](JS::Handle const& source) -> RefPtr { return source->bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return source->bitmap(); }, + [](JS::Handle const& source) -> RefPtr { return source->bitmap(); }); if (!bitmap) return {}; @@ -179,11 +184,11 @@ void CanvasRenderingContext2D::did_draw(Gfx::FloatRect const&) Gfx::Painter* CanvasRenderingContext2D::painter() { - if (!canvas_element().bitmap()) { - if (!canvas_element().create_bitmap()) + if (!canvas_element().surface()) { + if (!canvas_element().allocate_painting_surface()) return nullptr; canvas_element().document().invalidate_display_list(); - m_painter = Gfx::Painter::create(*canvas_element().bitmap()); + m_painter = make(*canvas_element().surface()); } return m_painter.ptr(); } @@ -341,23 +346,23 @@ WebIDL::ExceptionOr> CanvasRenderingContext2D::get_image_da auto image_data = TRY(ImageData::create(realm(), width, height, settings)); // NOTE: We don't attempt to create the underlying bitmap here; if it doesn't exist, it's like copying only transparent black pixels (which is a no-op). - if (!canvas_element().bitmap()) + if (!canvas_element().surface()) return image_data; - auto const& bitmap = *canvas_element().bitmap(); + auto const bitmap = canvas_element().surface()->create_snapshot(); // 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, width, height }; - auto source_rect_intersected = source_rect.intersected(bitmap.rect()); + auto source_rect_intersected = source_rect.intersected(bitmap->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(bitmap->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(), *bitmap, 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. @@ -378,11 +383,11 @@ void CanvasRenderingContext2D::put_image_data(ImageData const& image_data, float // https://html.spec.whatwg.org/multipage/canvas.html#reset-the-rendering-context-to-its-default-state void CanvasRenderingContext2D::reset_to_default_state() { - auto* bitmap = canvas_element().bitmap(); + auto surface = canvas_element().surface(); // 1. Clear canvas's bitmap to transparent black. - if (bitmap) { - painter()->clear_rect(bitmap->rect().to_type(), Color::Transparent); + if (surface) { + painter()->clear_rect(surface->rect().to_type(), Color::Transparent); } // 2. Empty the list of subpaths in context's current default path. @@ -394,8 +399,8 @@ void CanvasRenderingContext2D::reset_to_default_state() // 4. Reset everything that drawing state consists of to their initial values. reset_drawing_state(); - if (bitmap) - did_draw(bitmap->rect().to_type()); + if (surface) + did_draw(surface->rect().to_type()); } // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-measuretext diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp index 1d3594cdcf03..e16ee0389b85 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -115,7 +116,7 @@ void HTMLCanvasElement::reset_context_to_default_state() WebIDL::ExceptionOr HTMLCanvasElement::set_width(unsigned value) { TRY(set_attribute(HTML::AttributeNames::width, MUST(String::number(value)))); - m_bitmap = nullptr; + m_surface = nullptr; reset_context_to_default_state(); return {}; } @@ -123,7 +124,7 @@ WebIDL::ExceptionOr HTMLCanvasElement::set_width(unsigned value) WebIDL::ExceptionOr HTMLCanvasElement::set_height(unsigned value) { TRY(set_attribute(HTML::AttributeNames::height, MUST(String::number(value)))); - m_bitmap = nullptr; + m_surface = nullptr; reset_context_to_default_state(); return {}; } @@ -204,20 +205,23 @@ static Gfx::IntSize bitmap_size_for_canvas(HTMLCanvasElement const& canvas, size return Gfx::IntSize(width, height); } -bool HTMLCanvasElement::create_bitmap(size_t minimum_width, size_t minimum_height) +bool HTMLCanvasElement::allocate_painting_surface(size_t minimum_width, size_t minimum_height) { + if (m_surface) + return true; + + auto traversable = document().navigable()->traversable_navigable(); + VERIFY(traversable); + auto size = bitmap_size_for_canvas(*this, minimum_width, minimum_height); if (size.is_empty()) { - m_bitmap = nullptr; + m_surface = nullptr; return false; } - if (!m_bitmap || m_bitmap->size() != size) { - auto bitmap_or_error = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, size); - if (bitmap_or_error.is_error()) - return false; - m_bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors(); + if (!m_surface || m_surface->size() != size) { + m_surface = Gfx::PaintingSurface::create_with_size(traversable->skia_backend_context(), size, Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied); } - return m_bitmap; + return m_surface; } struct SerializeBitmapResult { @@ -252,18 +256,19 @@ static ErrorOr serialize_bitmap(Gfx::Bitmap const& bitmap String HTMLCanvasElement::to_data_url(StringView type, Optional quality) { // It is possible the the canvas doesn't have a associated bitmap so create one - if (!bitmap()) - create_bitmap(); + if (!m_surface) { + allocate_painting_surface(); + } // FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException. // 2. If this canvas element's bitmap has no pixels (i.e. either its horizontal dimension or its vertical dimension is zero) // then return the string "data:,". (This is the shortest data: URL; it represents the empty string in a text/plain resource.) - if (!m_bitmap) + if (!m_surface) return "data:,"_string; // 3. Let file be a serialization of this canvas element's bitmap as a file, passing type and quality if given. - auto file = serialize_bitmap(*m_bitmap, type, move(quality)); + auto file = serialize_bitmap(*m_surface->create_snapshot(), type, move(quality)); // 4. If file is null then return "data:,". if (file.is_error()) { @@ -283,8 +288,9 @@ String HTMLCanvasElement::to_data_url(StringView type, Optional quality) WebIDL::ExceptionOr HTMLCanvasElement::to_blob(JS::NonnullGCPtr callback, StringView type, Optional quality) { // It is possible the the canvas doesn't have a associated bitmap so create one - if (!bitmap()) - create_bitmap(); + if (!m_surface) { + allocate_painting_surface(); + } // FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException. @@ -293,8 +299,9 @@ WebIDL::ExceptionOr HTMLCanvasElement::to_blob(JS::NonnullGCPtrclone()); + if (m_surface) { + bitmap_result = m_surface->create_snapshot(); + } // 4. Run these steps in parallel: Platform::EventLoopPlugin::the().deferred_invoke([this, callback, bitmap_result, type, quality] { @@ -326,6 +333,10 @@ WebIDL::ExceptionOr HTMLCanvasElement::to_blob(JS::NonnullGCPtrflush(); + } + m_context.visit( [](JS::NonnullGCPtr&) { // Do nothing, CRC2D writes directly to the canvas bitmap. diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h index e8a9ab75b501..479bdd55d272 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -22,9 +23,9 @@ class HTMLCanvasElement final : public HTMLElement { virtual ~HTMLCanvasElement() override; - Gfx::Bitmap const* bitmap() const { return m_bitmap; } - Gfx::Bitmap* bitmap() { return m_bitmap; } - bool create_bitmap(size_t minimum_width = 0, size_t minimum_height = 0); + bool allocate_painting_surface(size_t minimum_width = 0, size_t minimum_height = 0); + RefPtr surface() { return m_surface; } + RefPtr surface() const { return m_surface; } JS::ThrowCompletionOr get_context(String const& type, JS::Value options); @@ -58,7 +59,7 @@ class HTMLCanvasElement final : public HTMLElement { JS::ThrowCompletionOr create_webgl_context(JS::Value options); void reset_context_to_default_state(); - RefPtr m_bitmap; + RefPtr m_surface; Variant, JS::NonnullGCPtr, Empty> m_context; }; diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h index 19e8e493ad72..4d52c474fe81 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h @@ -97,6 +97,8 @@ class TraversableNavigable final : public Navigable { void paint(Web::DevicePixelRect const&, Painting::BackingStore&, Web::PaintOptions); + RefPtr skia_backend_context() const { return m_skia_backend_context; } + private: TraversableNavigable(JS::NonnullGCPtr); diff --git a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp index eade794b9742..82aab97950f9 100644 --- a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include namespace Web::Painting { @@ -36,11 +37,13 @@ void CanvasPaintable::paint(PaintContext& context, PaintPhase phase) const auto canvas_rect = context.rounded_device_rect(absolute_rect()); ScopedCornerRadiusClip corner_clip { context, canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) }; - if (layout_box().dom_node().bitmap()) { + if (layout_box().dom_node().surface()) { + auto surface = layout_box().dom_node().surface(); + // FIXME: Remove this const_cast. const_cast(layout_box().dom_node()).present(); - auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), layout_box().dom_node().bitmap()->rect(), canvas_rect.to_type()); - context.display_list_recorder().draw_scaled_bitmap(canvas_rect.to_type(), *layout_box().dom_node().bitmap(), layout_box().dom_node().bitmap()->rect(), scaling_mode); + auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(), surface->rect(), canvas_rect.to_type()); + context.display_list_recorder().draw_painting_surface(canvas_rect.to_type(), *layout_box().dom_node().surface(), surface->rect(), scaling_mode); } } } diff --git a/Userland/Libraries/LibWeb/Painting/Command.h b/Userland/Libraries/LibWeb/Painting/Command.h index 5196e83ce7a7..659da4effd7a 100644 --- a/Userland/Libraries/LibWeb/Painting/Command.h +++ b/Userland/Libraries/LibWeb/Painting/Command.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,16 @@ struct DrawScaledBitmap { void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); } }; +struct DrawPaintingSurface { + Gfx::IntRect dst_rect; + NonnullRefPtr surface; + Gfx::IntRect src_rect; + Gfx::ScalingMode scaling_mode; + + [[nodiscard]] Gfx::IntRect bounding_rect() const { return dst_rect; } + void translate_by(Gfx::IntPoint const& offset) { dst_rect.translate_by(offset); } +}; + struct DrawScaledImmutableBitmap { Gfx::IntRect dst_rect; NonnullRefPtr bitmap; @@ -392,6 +403,7 @@ using Command = Variant< DrawGlyphRun, FillRect, DrawScaledBitmap, + DrawPaintingSurface, DrawScaledImmutableBitmap, DrawRepeatedImmutableBitmap, Save, diff --git a/Userland/Libraries/LibWeb/Painting/DisplayList.cpp b/Userland/Libraries/LibWeb/Painting/DisplayList.cpp index be641277ee55..0a0631da0172 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayList.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayList.cpp @@ -71,6 +71,7 @@ void DisplayListPlayer::execute(DisplayList& display_list) HANDLE_COMMAND(DrawGlyphRun, draw_glyph_run) else HANDLE_COMMAND(FillRect, fill_rect) else HANDLE_COMMAND(DrawScaledBitmap, draw_scaled_bitmap) + else HANDLE_COMMAND(DrawPaintingSurface, draw_painting_surface) else HANDLE_COMMAND(DrawScaledImmutableBitmap, draw_scaled_immutable_bitmap) else HANDLE_COMMAND(DrawRepeatedImmutableBitmap, draw_repeated_immutable_bitmap) else HANDLE_COMMAND(AddClipRect, add_clip_rect) diff --git a/Userland/Libraries/LibWeb/Painting/DisplayList.h b/Userland/Libraries/LibWeb/Painting/DisplayList.h index 3ffbb5049616..9d40c5c4e964 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayList.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayList.h @@ -45,6 +45,7 @@ class DisplayListPlayer { virtual void draw_glyph_run(DrawGlyphRun const&) = 0; virtual void fill_rect(FillRect const&) = 0; virtual void draw_scaled_bitmap(DrawScaledBitmap const&) = 0; + virtual void draw_painting_surface(DrawPaintingSurface const&) = 0; virtual void draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const&) = 0; virtual void draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const&) = 0; virtual void save(Save const&) = 0; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index f2de178fccb1..1d4f1f299be9 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -218,6 +218,17 @@ void DisplayListPlayerSkia::fill_rect(FillRect const& command) canvas.drawRect(to_skia_rect(rect), paint); } +void DisplayListPlayerSkia::draw_painting_surface(DrawPaintingSurface const& command) +{ + auto src_rect = to_skia_rect(command.src_rect); + auto dst_rect = to_skia_rect(command.dst_rect); + auto& sk_surface = command.surface->sk_surface(); + auto& canvas = surface().canvas(); + auto image = sk_surface.makeImageSnapshot(); + SkPaint paint; + canvas.drawImageRect(image, src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint); +} + void DisplayListPlayerSkia::draw_scaled_bitmap(DrawScaledBitmap const& command) { auto src_rect = to_skia_rect(command.src_rect); diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h index 33141424fcff..c5929afa21de 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h @@ -32,6 +32,7 @@ class DisplayListPlayerSkia : public DisplayListPlayer { private: void draw_glyph_run(DrawGlyphRun const&) override; void fill_rect(FillRect const&) override; + void draw_painting_surface(DrawPaintingSurface const&) override; void draw_scaled_bitmap(DrawScaledBitmap const&) override; void draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const&) override; void draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const&) override; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp index 231260b444bc..69e1e9da6411 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.cpp @@ -193,6 +193,18 @@ void DisplayListRecorder::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx:: }); } +void DisplayListRecorder::draw_painting_surface(Gfx::IntRect const& dst_rect, NonnullRefPtr surface, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode) +{ + if (dst_rect.is_empty()) + return; + append(DrawPaintingSurface { + .dst_rect = state().translation.map(dst_rect), + .surface = surface, + .src_rect = src_rect, + .scaling_mode = scaling_mode, + }); +} + void DisplayListRecorder::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode) { if (dst_rect.is_empty()) diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h index e329e57e88a4..409bafe8e2b4 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListRecorder.h @@ -88,6 +88,7 @@ class DisplayListRecorder { 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::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); + void draw_painting_surface(Gfx::IntRect const& dst_rect, NonnullRefPtr, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); void draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode = Gfx::ScalingMode::NearestNeighbor); void draw_repeated_immutable_bitmap(Gfx::IntRect dst_rect, Gfx::IntRect clip_rect, NonnullRefPtr bitmap, Gfx::ScalingMode scaling_mode, DrawRepeatedImmutableBitmap::Repeat); diff --git a/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp b/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp index a2f72c7a7fb6..b041a31f67bc 100644 --- a/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp +++ b/Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp @@ -29,7 +29,7 @@ static Response encode_canvas_element(HTML::HTMLCanvasElement& canvas) // FIXME: 1. If the canvas element’s bitmap’s origin-clean flag is set to false, return error with error code unable to capture screen. // 2. If the canvas element’s bitmap has no pixels (i.e. either its horizontal dimension or vertical dimension is zero) then return error with error code unable to capture screen. - if (canvas.bitmap()->width() == 0 || canvas.bitmap()->height() == 0) + if (canvas.surface()->size().is_empty()) return Error::from_code(ErrorCode::UnableToCaptureScreen, "Captured screenshot is empty"sv); // 3. Let file be a serialization of the canvas element’s bitmap as a file, using "image/png" as an argument. @@ -78,7 +78,7 @@ Response capture_element_screenshot(Painter const& painter, Page& page, DOM::Ele MUST(canvas.set_height(paint_height)); // FIXME: 5. Let context, a canvas context mode, be the result of invoking the 2D context creation algorithm given canvas as the target. - if (!canvas.create_bitmap(paint_width, paint_height)) + if (!canvas.allocate_painting_surface(paint_width, paint_height)) return Error::from_code(ErrorCode::UnableToCaptureScreen, "Unable to create a screenshot bitmap"sv); // 6. Complete implementation specific steps equivalent to drawing the region of the framebuffer specified by the following coordinates onto context: @@ -87,7 +87,7 @@ Response capture_element_screenshot(Painter const& painter, Page& page, DOM::Ele // - Width: paint width // - Height: paint height Gfx::IntRect paint_rect { rect.x(), rect.y(), paint_width, paint_height }; - painter(paint_rect, *canvas.bitmap()); + painter(paint_rect, *canvas.surface()->create_snapshot()); // 7. Return success with canvas. return canvas; diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp index 36148faac896..cfe16146274c 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp @@ -39,14 +39,14 @@ JS::ThrowCompletionOr> WebGLRenderingContext::c // We should be coming here from getContext being called on a wrapped element. auto context_attributes = TRY(convert_value_to_context_attributes_dictionary(canvas_element.vm(), options)); - bool created_bitmap = canvas_element.create_bitmap(/* minimum_width= */ 1, /* minimum_height= */ 1); - if (!created_bitmap) { + bool created_surface = canvas_element.allocate_painting_surface(/* minimum_width= */ 1, /* minimum_height= */ 1); + if (!created_surface) { fire_webgl_context_creation_error(canvas_element); return JS::GCPtr { nullptr }; } - VERIFY(canvas_element.bitmap()); - auto context = OpenGLContext::create(*canvas_element.bitmap()); + VERIFY(canvas_element.surface()); + auto context = OpenGLContext::create(*canvas_element.surface()->create_snapshot()); if (!context) { fire_webgl_context_creation_error(canvas_element); diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp index a10ca8fa59ea..15e7d57744ea 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().bitmap()); + m_context->present(*canvas_element().surface()->create_snapshot()); // "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.