mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-26 17:55:07 +02:00
present() now snapshots the PaintingSurface into an ImmutableBitmap and publishes it to the ExternalContentSource, so the rendering thread never touches the live GPU surface — eliminating the data race described in the ExternalContentSource commit (problem 1). Canvas elements are registered with Page and presented once per frame from the event loop, rather than on every individual draw call in CRC2D::did_draw(). A dirty flag on HTMLCanvasElement ensures the snapshot is only taken when content has actually changed, and makes the present() call in CanvasPaintable::paint() a no-op when the surface has already been snapshotted for the current frame.
51 lines
1.7 KiB
C++
51 lines
1.7 KiB
C++
/*
|
|
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibWeb/Painting/CanvasPaintable.h>
|
|
#include <LibWeb/Painting/DisplayListRecorder.h>
|
|
|
|
namespace Web::Painting {
|
|
|
|
GC_DEFINE_ALLOCATOR(CanvasPaintable);
|
|
|
|
GC::Ref<CanvasPaintable> CanvasPaintable::create(Layout::CanvasBox const& layout_box)
|
|
{
|
|
return layout_box.heap().allocate<CanvasPaintable>(layout_box);
|
|
}
|
|
|
|
CanvasPaintable::CanvasPaintable(Layout::CanvasBox const& layout_box)
|
|
: PaintableBox(layout_box)
|
|
{
|
|
}
|
|
|
|
void CanvasPaintable::paint(DisplayListRecordingContext& context, PaintPhase phase) const
|
|
{
|
|
if (!is_visible())
|
|
return;
|
|
|
|
PaintableBox::paint(context, phase);
|
|
|
|
if (phase == PaintPhase::Foreground) {
|
|
auto canvas_rect = context.rounded_device_rect(absolute_rect());
|
|
ScopedCornerRadiusClip corner_clip { context, canvas_rect, normalized_border_radii_data(ShrinkRadiiForBorders::Yes) };
|
|
|
|
auto& canvas_element = as<HTML::HTMLCanvasElement>(*dom_node());
|
|
if (canvas_element.surface()) {
|
|
// present() snapshots the surface and publishes to ExternalContentSource.
|
|
// FIXME: Remove this const_cast.
|
|
auto& mutable_canvas_element = const_cast<HTML::HTMLCanvasElement&>(canvas_element);
|
|
mutable_canvas_element.present();
|
|
auto canvas_int_rect = canvas_rect.to_type<int>();
|
|
auto scaling_mode = to_gfx_scaling_mode(computed_values().image_rendering(),
|
|
canvas_element.surface()->size(), canvas_int_rect.size());
|
|
context.display_list_recorder().draw_external_content(canvas_int_rect,
|
|
mutable_canvas_element.ensure_external_content_source(), scaling_mode);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|