ladybird/Libraries/LibWeb/HTML/HTMLCanvasElement.h
Aliaksandr Kalenik 93bbdf1f55 LibWeb: Use compositor surface IDs for embedded content
Display lists kept canvas and nested navigable content alive through
ExternalContentSource objects. That made the resource graph depend on
process-local object identity instead of a stable surface handle, which
blocks compositor process isolation and made teardown-sensitive embedded
content harder to reason about.

Allocate CompositorSurfaceId values for canvases and child navigables,
publish their backing stores to the owning compositor, and paint them
with DrawCompositorSurface. Child navigables now publish to parent
compositors by CompositorContextId instead of raw object pointers, so
the in-process path uses the same stable addressing model required by a
remote compositor.

Clear and skip stale child surfaces during teardown, preserve Skia
canvas state while drawing compositor surfaces, and add display-list
coverage for canvas and iframe compositor surfaces. The nested navigable
async-scrolling baseline now expects DrawCompositorSurface.
2026-05-18 15:27:59 +02:00

84 lines
3 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Optional.h>
#include <LibGfx/Forward.h>
#include <LibGfx/PaintingSurface.h>
#include <LibWeb/HTML/HTMLElement.h>
#include <LibWeb/Painting/DisplayListResourceIds.h>
#include <LibWeb/WebIDL/Types.h>
namespace Web::HTML {
class HTMLCanvasElement final : public HTMLElement {
WEB_PLATFORM_OBJECT(HTMLCanvasElement, HTMLElement);
GC_DECLARE_ALLOCATOR(HTMLCanvasElement);
public:
static constexpr bool OVERRIDES_FINALIZE = true;
using RenderingContext = Variant<GC::Root<CanvasRenderingContext2D>, GC::Root<WebGL::WebGLRenderingContext>, GC::Root<WebGL::WebGL2RenderingContext>, Empty>;
virtual ~HTMLCanvasElement() override;
Gfx::IntSize bitmap_size_for_canvas(size_t minimum_width = 0, size_t minimum_height = 0) const;
JS::ThrowCompletionOr<RenderingContext> get_context(String const& type, JS::Value options);
enum class HasOrCreatedContext {
No,
Yes,
};
JS::ThrowCompletionOr<HasOrCreatedContext> create_2d_context(JS::Value options);
WebIDL::UnsignedLong width() const;
WebIDL::UnsignedLong height() const;
void set_width(WebIDL::UnsignedLong);
void set_height(WebIDL::UnsignedLong);
virtual void attribute_changed(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
String to_data_url(StringView type, JS::Value quality);
WebIDL::ExceptionOr<void> to_blob(GC::Ref<WebIDL::CallbackType> callback, StringView type, JS::Value quality);
RefPtr<Gfx::Bitmap> get_bitmap_from_surface();
void present();
void set_canvas_content_dirty();
RefPtr<Gfx::PaintingSurface> surface() const;
void allocate_painting_surface_if_needed();
Painting::CompositorSurfaceId ensure_compositor_surface_id();
CSS::ComputationContext canvas_font_computation_context();
private:
HTMLCanvasElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
virtual void finalize() override;
virtual void visit_edges(Cell::Visitor&) override;
virtual bool is_presentational_hint(FlyString const&) const override;
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) const override;
virtual GC::Ptr<Layout::Node> create_layout_node(GC::Ref<CSS::ComputedProperties>) override;
virtual void adjust_computed_style(CSS::ComputedProperties&) override;
template<typename ContextType>
JS::ThrowCompletionOr<HasOrCreatedContext> create_webgl_context(JS::Value options);
void reset_context_to_default_state();
void notify_context_about_canvas_size_change();
void clear_compositor_surface();
Variant<GC::Ref<HTML::CanvasRenderingContext2D>, GC::Ref<WebGL::WebGLRenderingContext>, GC::Ref<WebGL::WebGL2RenderingContext>, Empty> m_context;
Optional<Painting::CompositorSurfaceId> m_compositor_surface_id;
bool m_canvas_content_dirty { false };
};
}