mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-21 19:30:27 +00: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.
80 lines
2.9 KiB
C++
80 lines
2.9 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibGfx/Forward.h>
|
|
#include <LibGfx/PaintingSurface.h>
|
|
#include <LibWeb/HTML/HTMLElement.h>
|
|
#include <LibWeb/Painting/ExternalContentSource.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::ExternalContentSource& ensure_external_content_source();
|
|
|
|
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(GC::Ref<CSS::CascadedProperties>) 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();
|
|
|
|
Variant<GC::Ref<HTML::CanvasRenderingContext2D>, GC::Ref<WebGL::WebGLRenderingContext>, GC::Ref<WebGL::WebGL2RenderingContext>, Empty> m_context;
|
|
RefPtr<Painting::ExternalContentSource> m_external_content_source;
|
|
bool m_canvas_content_dirty { false };
|
|
};
|
|
|
|
}
|