LibWeb: Add OffscreenCanvas to IDL types

Add OffscreenCanvas to TexImageSource and CanvasImageSource.
Implement all the necessary features to make it work in all cases where
these types are used.
This commit is contained in:
Totto16 2025-03-06 23:41:31 +01:00 committed by Andrew Kaster
commit f1a096d6e4
Notes: github-actions[bot] 2025-06-30 15:47:37 +00:00
8 changed files with 35 additions and 9 deletions

View file

@ -42,6 +42,12 @@ static void default_source_size(CanvasImageSource const& image, float& source_wi
source_height = source->video_height(); source_height = source->video_height();
} }
}, },
[&source_width, &source_height](GC::Root<OffscreenCanvas> const& source) {
auto const bitmap = source->bitmap();
source_width = bitmap->width();
source_height = bitmap->height();
},
[&source_width, &source_height](GC::Root<HTMLCanvasElement> const& source) { [&source_width, &source_height](GC::Root<HTMLCanvasElement> const& source) {
if (source->surface()) { if (source->surface()) {
source_width = source->surface()->size().width(); source_width = source->surface()->size().width();

View file

@ -10,13 +10,14 @@
#include <LibWeb/HTML/HTMLCanvasElement.h> #include <LibWeb/HTML/HTMLCanvasElement.h>
#include <LibWeb/HTML/HTMLImageElement.h> #include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLVideoElement.h> #include <LibWeb/HTML/HTMLVideoElement.h>
#include <LibWeb/HTML/OffscreenCanvas.h>
#include <LibWeb/WebIDL/ExceptionOr.h> #include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::HTML { namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/canvas.html#canvasimagesource // https://html.spec.whatwg.org/multipage/canvas.html#canvasimagesource
// NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly. // NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly.
using CanvasImageSource = Variant<GC::Root<HTMLImageElement>, GC::Root<SVG::SVGImageElement>, GC::Root<HTMLCanvasElement>, GC::Root<ImageBitmap>, GC::Root<HTMLVideoElement>>; using CanvasImageSource = Variant<GC::Root<HTMLImageElement>, GC::Root<SVG::SVGImageElement>, GC::Root<HTMLCanvasElement>, GC::Root<ImageBitmap>, GC::Root<OffscreenCanvas>, GC::Root<HTMLVideoElement>>;
// https://html.spec.whatwg.org/multipage/canvas.html#canvasdrawimage // https://html.spec.whatwg.org/multipage/canvas.html#canvasdrawimage
class CanvasDrawImage { class CanvasDrawImage {

View file

@ -1,6 +1,7 @@
#import <HTML/HTMLCanvasElement.idl> #import <HTML/HTMLCanvasElement.idl>
#import <HTML/HTMLImageElement.idl> #import <HTML/HTMLImageElement.idl>
#import <HTML/HTMLVideoElement.idl> #import <HTML/HTMLVideoElement.idl>
#import <HTML/Canvas/OffscreenCanvasBase.idl>
#import <HTML/ImageBitmap.idl> #import <HTML/ImageBitmap.idl>
#import <SVG/SVGImageElement.idl> #import <SVG/SVGImageElement.idl>
@ -9,8 +10,8 @@ typedef (HTMLImageElement or
// FIXME: We should use HTMLOrSVGImageElement instead of HTMLImageElement // FIXME: We should use HTMLOrSVGImageElement instead of HTMLImageElement
HTMLVideoElement or HTMLVideoElement or
HTMLCanvasElement or HTMLCanvasElement or
ImageBitmap ImageBitmap or
// FIXME: OffscreenCanvas OffscreenCanvas
// FIXME: VideoFrame // FIXME: VideoFrame
) CanvasImageSource; ) CanvasImageSource;

View file

@ -17,6 +17,7 @@ namespace Web::HTML {
GC_DEFINE_ALLOCATOR(CanvasPattern); GC_DEFINE_ALLOCATOR(CanvasPattern);
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvaspattern-settransform
void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFunction paint) const void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFunction paint) const
{ {
// 1. Create an infinite transparent black bitmap. // 1. Create an infinite transparent black bitmap.
@ -50,6 +51,7 @@ void CanvasPatternPaintStyle::paint(Gfx::IntRect physical_bounding_box, PaintFun
auto bitmap = m_image.visit( auto bitmap = m_image.visit(
[](GC::Root<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->immutable_bitmap(); }, [](GC::Root<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->immutable_bitmap(); },
[](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->current_image_bitmap(); }, [](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->current_image_bitmap(); },
[](GC::Root<OffscreenCanvas> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
[](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*source->surface()); }, [](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*source->surface()); },
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); }, [](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
[](GC::Root<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); }); [](GC::Root<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); });

View file

@ -135,6 +135,7 @@ WebIDL::ExceptionOr<void> CanvasRenderingContext2D::draw_image_internal(CanvasIm
[](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { [](GC::Root<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return source->current_image_bitmap(); return source->current_image_bitmap();
}, },
[](GC::Root<OffscreenCanvas> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
[](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { [](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
auto surface = source->surface(); auto surface = source->surface();
if (!surface) if (!surface)
@ -737,8 +738,14 @@ WebIDL::ExceptionOr<CanvasImageSourceUsability> check_usability_of_image(CanvasI
return Optional<CanvasImageSourceUsability> {}; return Optional<CanvasImageSourceUsability> {};
}, },
// OffscreenCanvas
[](GC::Root<OffscreenCanvas> const& offscreen_canvas) -> WebIDL::ExceptionOr<Optional<CanvasImageSourceUsability>> {
// If image has either a horizontal dimension or a vertical dimension equal to zero, then throw an "InvalidStateError" DOMException.
if (offscreen_canvas->width() == 0 || offscreen_canvas->height() == 0)
return WebIDL::InvalidStateError::create(offscreen_canvas->realm(), "OffscreenCanvas width or height is zero"_string);
return Optional<CanvasImageSourceUsability> {};
},
// HTMLCanvasElement // HTMLCanvasElement
// FIXME: OffscreenCanvas
[](GC::Root<HTMLCanvasElement> const& canvas_element) -> WebIDL::ExceptionOr<Optional<CanvasImageSourceUsability>> { [](GC::Root<HTMLCanvasElement> const& canvas_element) -> WebIDL::ExceptionOr<Optional<CanvasImageSourceUsability>> {
// If image has either a horizontal dimension or a vertical dimension equal to zero, then throw an "InvalidStateError" DOMException. // If image has either a horizontal dimension or a vertical dimension equal to zero, then throw an "InvalidStateError" DOMException.
if (canvas_element->width() == 0 || canvas_element->height() == 0) if (canvas_element->width() == 0 || canvas_element->height() == 0)
@ -778,8 +785,8 @@ bool image_is_not_origin_clean(CanvasImageSource const& image)
// FIXME: image's media data is CORS-cross-origin. // FIXME: image's media data is CORS-cross-origin.
return false; return false;
}, },
// HTMLCanvasElement // HTMLCanvasElement, ImageBitmap or OffscreenCanvas
[](OneOf<GC::Root<HTMLCanvasElement>, GC::Root<ImageBitmap>> auto const&) { [](OneOf<GC::Root<HTMLCanvasElement>, GC::Root<ImageBitmap>, GC::Root<OffscreenCanvas>> auto const&) {
// FIXME: image's bitmap's origin-clean flag is false. // FIXME: image's bitmap's origin-clean flag is false.
return false; return false;
}); });

View file

@ -6,8 +6,14 @@
#pragma once #pragma once
#include <LibWeb/Forward.h>
#include <LibWeb/WebIDL/Types.h>
namespace Web::WebGL { namespace Web::WebGL {
// NOTE: This is the Variant created by the IDL wrapper generator, and needs to be updated accordingly.
using TexImageSource = Variant<GC::Root<HTML::ImageBitmap>, GC::Root<HTML::ImageData>, GC::Root<HTML::HTMLImageElement>, GC::Root<HTML::HTMLCanvasElement>, GC::Root<HTML::OffscreenCanvas>, GC::Root<HTML::HTMLVideoElement>>;
// FIXME: This object should inherit from Bindings::PlatformObject and implement the WebGLRenderingContextBase IDL interface. // FIXME: This object should inherit from Bindings::PlatformObject and implement the WebGLRenderingContextBase IDL interface.
// We should make WebGL code generator to produce implementation for this interface. // We should make WebGL code generator to produce implementation for this interface.
class WebGLRenderingContextBase { class WebGLRenderingContextBase {

View file

@ -4,8 +4,8 @@ typedef (ImageBitmap or
ImageData or ImageData or
HTMLImageElement or HTMLImageElement or
HTMLCanvasElement or HTMLCanvasElement or
HTMLVideoElement HTMLVideoElement or
// FIXME: OffscreenCanvas or OffscreenCanvas
// FIXME: VideoFrame // FIXME: VideoFrame
) TexImageSource; ) TexImageSource;

View file

@ -730,7 +730,7 @@ struct ConvertedTexture {
int height { 0 }; int height { 0 };
}; };
static Optional<ConvertedTexture> read_and_pixel_convert_texture_image_source(Variant<GC::Root<ImageBitmap>, GC::Root<ImageData>, GC::Root<HTMLImageElement>, GC::Root<HTMLCanvasElement>, GC::Root<HTMLVideoElement>> const& source, WebIDL::UnsignedLong format, WebIDL::UnsignedLong type, Optional<int> destination_width = OptionalNone {}, Optional<int> destination_height = OptionalNone {}) static Optional<ConvertedTexture> read_and_pixel_convert_texture_image_source(TexImageSource const& source, WebIDL::UnsignedLong format, WebIDL::UnsignedLong type, Optional<int> destination_width = OptionalNone {}, Optional<int> destination_height = OptionalNone {})
{ {
// FIXME: If this function is called with an ImageData whose data attribute has been neutered, // FIXME: If this function is called with an ImageData whose data attribute has been neutered,
// an INVALID_VALUE error is generated. // an INVALID_VALUE error is generated.
@ -753,6 +753,9 @@ static Optional<ConvertedTexture> read_and_pixel_convert_texture_image_source(Va
surface->read_into_bitmap(*bitmap); surface->read_into_bitmap(*bitmap);
return Gfx::ImmutableBitmap::create(*bitmap); return Gfx::ImmutableBitmap::create(*bitmap);
}, },
[](GC::Root<OffscreenCanvas> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return Gfx::ImmutableBitmap::create(*source->bitmap());
},
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { [](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return Gfx::ImmutableBitmap::create(*source->bitmap()); return Gfx::ImmutableBitmap::create(*source->bitmap());
}, },