2020-03-19 19:07:56 +01:00
/*
2024-10-04 13:19:50 +02:00
* Copyright ( c ) 2018 - 2020 , Andreas Kling < andreas @ ladybird . org >
2020-03-19 19:07:56 +01:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-03-19 19:07:56 +01:00
*/
2021-04-19 23:47:29 +02:00
# include <AK/Base64.h>
2020-04-15 16:55:36 +02:00
# include <AK/Checked.h>
2023-08-03 10:26:13 +02:00
# include <AK/MemoryStream.h>
2020-03-19 19:07:56 +01:00
# include <LibGfx/Bitmap.h>
2023-08-03 10:26:13 +02:00
# include <LibGfx/ImageFormats/JPEGWriter.h>
2023-03-21 14:58:06 -04:00
# include <LibGfx/ImageFormats/PNGWriter.h>
2023-08-03 01:29:31 +02:00
# include <LibWeb/Bindings/ExceptionOrUtils.h>
2024-04-27 12:09:58 +12:00
# include <LibWeb/Bindings/HTMLCanvasElementPrototype.h>
2021-09-24 13:49:57 +02:00
# include <LibWeb/CSS/StyleComputer.h>
2024-08-14 11:46:56 +01:00
# include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
2024-11-08 20:14:37 +08:00
# include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
2023-08-31 19:22:17 +02:00
# include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
# include <LibWeb/CSS/StyleValues/StyleValueList.h>
2020-03-19 19:07:56 +01:00
# include <LibWeb/DOM/Document.h>
2020-07-26 15:08:16 +02:00
# include <LibWeb/HTML/CanvasRenderingContext2D.h>
# include <LibWeb/HTML/HTMLCanvasElement.h>
2023-08-31 22:12:14 +02:00
# include <LibWeb/HTML/Numbers.h>
2023-08-03 01:29:31 +02:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2024-09-25 15:44:58 +02:00
# include <LibWeb/HTML/TraversableNavigable.h>
2020-11-22 15:53:01 +01:00
# include <LibWeb/Layout/CanvasBox.h>
2023-08-03 01:29:31 +02:00
# include <LibWeb/Platform/EventLoopPlugin.h>
2024-11-29 20:17:25 +01:00
# include <LibWeb/WebGL/WebGLRenderingContext.h>
2023-08-03 01:29:31 +02:00
# include <LibWeb/WebIDL/AbstractOperations.h>
2020-03-19 19:07:56 +01:00
2020-07-28 18:20:36 +02:00
namespace Web : : HTML {
2020-03-19 19:07:56 +01:00
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( HTMLCanvasElement ) ;
2023-11-19 19:47:52 +01:00
2020-04-15 12:12:19 +02:00
static constexpr auto max_canvas_area = 16384 * 16384 ;
2022-02-18 21:00:52 +01:00
HTMLCanvasElement : : HTMLCanvasElement ( DOM : : Document & document , DOM : : QualifiedName qualified_name )
2021-02-07 11:20:15 +01:00
: HTMLElement ( document , move ( qualified_name ) )
2020-03-19 19:07:56 +01:00
{
}
2022-03-14 13:21:51 -06:00
HTMLCanvasElement : : ~ HTMLCanvasElement ( ) = default ;
2020-03-19 19:07:56 +01:00
2023-08-07 08:41:28 +02:00
void HTMLCanvasElement : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( HTMLCanvasElement ) ;
2023-01-10 06:28:20 -05:00
}
2022-09-02 15:53:02 +02:00
void HTMLCanvasElement : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
m_context . visit (
2024-11-15 04:01:23 +13:00
[ & ] ( GC : : Ref < CanvasRenderingContext2D > & context ) {
2023-11-19 16:18:00 +13:00
visitor . visit ( context ) ;
2022-09-02 15:53:02 +02:00
} ,
2024-11-15 04:01:23 +13:00
[ & ] ( GC : : Ref < WebGL : : WebGLRenderingContext > & context ) {
2023-11-19 16:18:00 +13:00
visitor . visit ( context ) ;
2022-09-02 15:53:02 +02:00
} ,
[ ] ( Empty ) {
} ) ;
}
2023-08-31 19:22:17 +02:00
void HTMLCanvasElement : : apply_presentational_hints ( CSS : : StyleProperties & style ) const
{
// https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images
// The width and height attributes map to the aspect-ratio property on canvas elements.
// FIXME: Multiple elements have aspect-ratio presentational hints, make this into a helper function
// https://html.spec.whatwg.org/multipage/rendering.html#map-to-the-aspect-ratio-property
// if element has both attributes w and h, and parsing those attributes' values using the rules for parsing non-negative integers doesn't generate an error for either
2024-01-16 19:04:45 +01:00
auto w = parse_non_negative_integer ( get_attribute_value ( HTML : : AttributeNames : : width ) ) ;
auto h = parse_non_negative_integer ( get_attribute_value ( HTML : : AttributeNames : : height ) ) ;
2023-08-31 19:22:17 +02:00
if ( w . has_value ( ) & & h . has_value ( ) )
// then the user agent is expected to use the parsed integers as a presentational hint for the 'aspect-ratio' property of the form auto w / h.
style . set_property ( CSS : : PropertyID : : AspectRatio ,
CSS : : StyleValueList : : create ( CSS : : StyleValueVector {
2024-08-14 14:06:03 +01:00
CSS : : CSSKeywordValue : : create ( CSS : : Keyword : : Auto ) ,
2023-08-31 19:22:17 +02:00
CSS : : RatioStyleValue : : create ( CSS : : Ratio { static_cast < double > ( w . value ( ) ) , static_cast < double > ( h . value ( ) ) } ) } ,
CSS : : StyleValueList : : Separator : : Space ) ) ;
}
2024-11-29 16:04:35 +00:00
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-width
WebIDL : : UnsignedLong HTMLCanvasElement : : width ( ) const
2020-03-19 19:07:56 +01:00
{
2024-11-29 16:04:35 +00:00
// The width and height IDL attributes must reflect the respective content attributes of the same name, with the same defaults.
2023-08-31 22:12:14 +02:00
// https://html.spec.whatwg.org/multipage/canvas.html#obtain-numeric-values
// The rules for parsing non-negative integers must be used to obtain their numeric values.
// If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead.
// The width attribute defaults to 300
2024-11-29 16:04:35 +00:00
if ( auto width_string = get_attribute ( HTML : : AttributeNames : : width ) ; width_string . has_value ( ) ) {
if ( auto width = parse_non_negative_integer ( * width_string ) ; width . has_value ( ) & & * width < = 2147483647 )
return * width ;
}
return 300 ;
2020-03-19 19:07:56 +01:00
}
2024-11-29 16:04:35 +00:00
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-height
WebIDL : : UnsignedLong HTMLCanvasElement : : height ( ) const
2020-03-19 19:07:56 +01:00
{
2024-11-29 16:04:35 +00:00
// The width and height IDL attributes must reflect the respective content attributes of the same name, with the same defaults.
2023-08-31 22:12:14 +02:00
// https://html.spec.whatwg.org/multipage/canvas.html#obtain-numeric-values
// The rules for parsing non-negative integers must be used to obtain their numeric values.
// If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead.
// the height attribute defaults to 150
2024-11-29 16:04:35 +00:00
if ( auto height_string = get_attribute ( HTML : : AttributeNames : : height ) ; height_string . has_value ( ) ) {
if ( auto height = parse_non_negative_integer ( * height_string ) ; height . has_value ( ) & & * height < = 2147483647 )
return * height ;
}
return 150 ;
2020-03-19 19:07:56 +01:00
}
2022-06-04 04:22:42 +01:00
void HTMLCanvasElement : : reset_context_to_default_state ( )
{
m_context . visit (
2024-11-15 04:01:23 +13:00
[ ] ( GC : : Ref < CanvasRenderingContext2D > & context ) {
2022-06-04 04:22:42 +01:00
context - > reset_to_default_state ( ) ;
} ,
2024-11-29 22:15:02 +01:00
[ ] ( GC : : Ref < WebGL : : WebGLRenderingContext > & context ) {
context - > reset_to_default_state ( ) ;
2022-06-04 04:22:42 +01:00
} ,
[ ] ( Empty ) {
// Do nothing.
} ) ;
}
2024-11-29 20:17:25 +01:00
void HTMLCanvasElement : : notify_context_about_canvas_size_change ( )
{
m_context . visit (
[ & ] ( GC : : Ref < CanvasRenderingContext2D > & context ) {
context - > set_size ( bitmap_size_for_canvas ( ) ) ;
} ,
2024-11-29 22:15:02 +01:00
[ & ] ( GC : : Ref < WebGL : : WebGLRenderingContext > & context ) {
context - > set_size ( bitmap_size_for_canvas ( ) ) ;
2024-11-29 20:17:25 +01:00
} ,
[ ] ( Empty ) {
// Do nothing.
} ) ;
}
WebIDL : : ExceptionOr < void > HTMLCanvasElement : : set_width ( unsigned value )
2021-11-13 00:54:21 +01:00
{
2024-11-29 16:04:35 +00:00
if ( value > 2147483647 )
value = 300 ;
2024-10-14 10:05:01 +02:00
TRY ( set_attribute ( HTML : : AttributeNames : : width , String : : number ( value ) ) ) ;
2024-11-29 20:17:25 +01:00
notify_context_about_canvas_size_change ( ) ;
2022-06-04 04:22:42 +01:00
reset_context_to_default_state ( ) ;
2023-05-25 20:37:57 +01:00
return { } ;
2021-11-13 00:54:21 +01:00
}
2024-11-29 16:04:35 +00:00
WebIDL : : ExceptionOr < void > HTMLCanvasElement : : set_height ( WebIDL : : UnsignedLong value )
2021-11-13 00:54:21 +01:00
{
2024-11-29 16:04:35 +00:00
if ( value > 2147483647 )
value = 150 ;
2024-10-14 10:05:01 +02:00
TRY ( set_attribute ( HTML : : AttributeNames : : height , String : : number ( value ) ) ) ;
2024-11-29 20:17:25 +01:00
notify_context_about_canvas_size_change ( ) ;
2022-06-04 04:22:42 +01:00
reset_context_to_default_state ( ) ;
2023-05-25 20:37:57 +01:00
return { } ;
2021-11-13 00:54:21 +01:00
}
2024-11-15 04:01:23 +13:00
GC : : Ptr < Layout : : Node > HTMLCanvasElement : : create_layout_node ( CSS : : StyleProperties style )
2020-03-19 19:07:56 +01:00
{
2024-11-14 06:13:46 +13:00
return heap ( ) . allocate < Layout : : CanvasBox > ( document ( ) , * this , move ( style ) ) ;
2020-03-19 19:07:56 +01:00
}
2024-11-08 20:14:37 +08:00
void HTMLCanvasElement : : adjust_computed_style ( CSS : : StyleProperties & style )
{
// https://drafts.csswg.org/css-display-3/#unbox
if ( style . display ( ) . is_contents ( ) )
style . set_property ( CSS : : PropertyID : : Display , CSS : : DisplayStyleValue : : create ( CSS : : Display : : from_short ( CSS : : Display : : Short : : None ) ) ) ;
}
2022-06-04 04:22:42 +01:00
HTMLCanvasElement : : HasOrCreatedContext HTMLCanvasElement : : create_2d_context ( )
{
if ( ! m_context . has < Empty > ( ) )
2024-11-15 04:01:23 +13:00
return m_context . has < GC : : Ref < CanvasRenderingContext2D > > ( ) ? HasOrCreatedContext : : Yes : HasOrCreatedContext : : No ;
2022-06-04 04:22:42 +01:00
2023-08-13 13:05:26 +02:00
m_context = CanvasRenderingContext2D : : create ( realm ( ) , * this ) ;
2022-06-04 04:22:42 +01:00
return HasOrCreatedContext : : Yes ;
}
JS : : ThrowCompletionOr < HTMLCanvasElement : : HasOrCreatedContext > HTMLCanvasElement : : create_webgl_context ( JS : : Value options )
2020-03-19 19:07:56 +01:00
{
2022-06-04 04:22:42 +01:00
if ( ! m_context . has < Empty > ( ) )
2024-11-15 04:01:23 +13:00
return m_context . has < GC : : Ref < WebGL : : WebGLRenderingContext > > ( ) ? HasOrCreatedContext : : Yes : HasOrCreatedContext : : No ;
2022-06-04 04:22:42 +01:00
2022-09-25 18:12:50 -06:00
auto maybe_context = TRY ( WebGL : : WebGLRenderingContext : : create ( realm ( ) , * this , options ) ) ;
2022-06-04 04:22:42 +01:00
if ( ! maybe_context )
return HasOrCreatedContext : : No ;
2024-11-15 04:01:23 +13:00
m_context = GC : : Ref < WebGL : : WebGLRenderingContext > ( * maybe_context ) ;
2022-06-04 04:22:42 +01:00
return HasOrCreatedContext : : Yes ;
2020-03-19 19:07:56 +01:00
}
2022-06-04 04:22:42 +01:00
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-getcontext
2023-09-03 15:58:55 +12:00
JS : : ThrowCompletionOr < HTMLCanvasElement : : RenderingContext > HTMLCanvasElement : : get_context ( String const & type , JS : : Value options )
2020-04-15 12:12:19 +02:00
{
2022-06-04 04:22:42 +01:00
// 1. If options is not an object, then set options to null.
if ( ! options . is_object ( ) )
options = JS : : js_null ( ) ;
// 2. Set options to the result of converting options to a JavaScript value.
// NOTE: No-op.
// 3. Run the steps in the cell of the following table whose column header matches this canvas element's canvas context mode and whose row header matches contextId:
// NOTE: See the spec for the full table.
if ( type = = " 2d " sv ) {
if ( create_2d_context ( ) = = HasOrCreatedContext : : Yes )
2024-11-15 04:01:23 +13:00
return GC : : make_root ( * m_context . get < GC : : Ref < HTML : : CanvasRenderingContext2D > > ( ) ) ;
2022-06-04 04:22:42 +01:00
return Empty { } ;
}
// NOTE: The WebGL spec says "experimental-webgl" is also acceptable and must be equivalent to "webgl". Other engines accept this, so we do too.
if ( type . is_one_of ( " webgl " sv , " experimental-webgl " sv ) ) {
if ( TRY ( create_webgl_context ( options ) ) = = HasOrCreatedContext : : Yes )
2024-11-15 04:01:23 +13:00
return GC : : make_root ( * m_context . get < GC : : Ref < WebGL : : WebGLRenderingContext > > ( ) ) ;
2022-06-04 04:22:42 +01:00
return Empty { } ;
}
return Empty { } ;
}
2024-11-29 20:17:25 +01:00
Gfx : : IntSize HTMLCanvasElement : : bitmap_size_for_canvas ( size_t minimum_width , size_t minimum_height ) const
2022-06-04 04:22:42 +01:00
{
2024-11-29 20:17:25 +01:00
auto width = max ( this - > width ( ) , minimum_width ) ;
auto height = max ( this - > height ( ) , minimum_height ) ;
2020-04-15 16:55:36 +02:00
Checked < size_t > area = width ;
area * = height ;
if ( area . has_overflow ( ) ) {
2021-01-09 14:02:45 +01:00
dbgln ( " Refusing to create {}x{} canvas (overflow) " , width , height ) ;
2020-04-15 12:12:19 +02:00
return { } ;
}
2020-04-15 16:55:36 +02:00
if ( area . value ( ) > max_canvas_area ) {
2021-01-09 14:02:45 +01:00
dbgln ( " Refusing to create {}x{} canvas (exceeds maximum size) " , width , height ) ;
2020-04-15 12:12:19 +02:00
return { } ;
}
2020-06-21 15:37:13 +02:00
return Gfx : : IntSize ( width , height ) ;
2020-04-15 12:12:19 +02:00
}
2023-08-03 10:12:11 +02:00
struct SerializeBitmapResult {
ByteBuffer buffer ;
StringView mime_type ;
} ;
// https://html.spec.whatwg.org/multipage/canvas.html#a-serialisation-of-the-bitmap-as-a-file
2024-11-08 09:13:54 +01:00
static ErrorOr < SerializeBitmapResult > serialize_bitmap ( Gfx : : Bitmap const & bitmap , StringView type , JS : : Value quality )
2023-08-03 10:12:11 +02:00
{
2023-08-03 10:26:13 +02:00
// If type is an image format that supports variable quality (such as "image/jpeg"), quality is given, and type is not "image/png", then,
2024-10-31 11:34:22 +00:00
// if quality is a Number in the range 0.0 to 1.0 inclusive, the user agent must treat quality as the desired quality level.
2023-08-03 10:26:13 +02:00
// Otherwise, the user agent must use its default quality value, as if the quality argument had not been given.
2024-11-08 09:13:54 +01:00
bool valid_quality = quality . is_number ( ) & & quality . as_double ( ) > = 0.0 & & quality . as_double ( ) < = 1.0 ;
2023-08-03 10:26:13 +02:00
if ( type . equals_ignoring_ascii_case ( " image/jpeg " sv ) ) {
AllocatingMemoryStream file ;
Gfx : : JPEGWriter : : Options jpeg_options ;
2024-11-08 09:13:54 +01:00
if ( valid_quality )
jpeg_options . quality = static_cast < int > ( quality . as_double ( ) * 100 ) ;
2023-08-03 10:26:13 +02:00
TRY ( Gfx : : JPEGWriter : : encode ( file , bitmap , jpeg_options ) ) ;
return SerializeBitmapResult { TRY ( file . read_until_eof ( ) ) , " image/jpeg " sv } ;
}
2023-08-03 10:12:11 +02:00
// User agents must support PNG ("image/png"). User agents may support other types.
// If the user agent does not support the requested type, then it must create the file using the PNG format. [PNG]
return SerializeBitmapResult { TRY ( Gfx : : PNGWriter : : encode ( bitmap ) ) , " image/png " sv } ;
}
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-todataurl
2024-11-08 09:13:54 +01:00
String HTMLCanvasElement : : to_data_url ( StringView type , JS : : Value quality )
2021-04-19 23:47:29 +02:00
{
2023-09-16 22:00:37 +02:00
// It is possible the the canvas doesn't have a associated bitmap so create one
2024-11-29 20:17:25 +01:00
allocate_painting_surface_if_needed ( ) ;
auto surface = this - > surface ( ) ;
auto size = bitmap_size_for_canvas ( ) ;
2024-12-04 15:35:16 +01:00
if ( ! surface ) {
2024-11-29 20:17:25 +01:00
// If the context is not initialized yet, we need to allocate transparent surface for serialization
auto skia_backend_context = navigable ( ) - > traversable_navigable ( ) - > skia_backend_context ( ) ;
surface = Gfx : : PaintingSurface : : create_with_size ( skia_backend_context , size , Gfx : : BitmapFormat : : BGRA8888 , Gfx : : AlphaType : : Premultiplied ) ;
2024-09-25 15:44:58 +02:00
}
2023-09-16 22:00:37 +02:00
2023-08-03 10:12:11 +02:00
// 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.)
2024-11-29 20:17:25 +01:00
if ( ! surface )
2023-09-03 15:58:55 +12:00
return " data:, " _string ;
2023-08-03 10:12:11 +02:00
// 3. Let file be a serialization of this canvas element's bitmap as a file, passing type and quality if given.
2024-11-29 20:17:25 +01:00
auto snapshot = Gfx : : ImmutableBitmap : : create_snapshot_from_painting_surface ( * surface ) ;
auto bitmap = MUST ( Gfx : : Bitmap : : create ( Gfx : : BitmapFormat : : BGRA8888 , Gfx : : AlphaType : : Premultiplied , surface - > size ( ) ) ) ;
surface - > read_into_bitmap ( * bitmap ) ;
2024-11-09 05:48:17 +01:00
auto file = serialize_bitmap ( bitmap , type , move ( quality ) ) ;
2023-08-03 10:12:11 +02:00
// 4. If file is null then return "data:,".
if ( file . is_error ( ) ) {
dbgln ( " HTMLCanvasElement: Failed to encode canvas bitmap to {}: {} " , type , file . error ( ) ) ;
2023-09-03 15:58:55 +12:00
return " data:, " _string ;
2022-12-05 20:34:27 +01:00
}
2023-08-03 10:12:11 +02:00
// 5. Return a data: URL representing file. [RFC2397]
auto base64_encoded_or_error = encode_base64 ( file . value ( ) . buffer ) ;
2022-12-19 00:23:47 +01:00
if ( base64_encoded_or_error . is_error ( ) ) {
2023-09-03 15:58:55 +12:00
return " data:, " _string ;
2022-12-19 00:23:47 +01:00
}
2024-02-11 20:15:39 +13:00
return MUST ( URL : : create_with_data ( file . value ( ) . mime_type , base64_encoded_or_error . release_value ( ) , true ) . to_string ( ) ) ;
2021-04-19 23:47:29 +02:00
}
2023-08-03 01:29:31 +02:00
// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-toblob
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < void > HTMLCanvasElement : : to_blob ( GC : : Ref < WebIDL : : CallbackType > callback , StringView type , JS : : Value quality )
2023-08-03 01:29:31 +02:00
{
2023-09-16 22:00:37 +02:00
// It is possible the the canvas doesn't have a associated bitmap so create one
2024-11-29 20:17:25 +01:00
allocate_painting_surface_if_needed ( ) ;
auto surface = this - > surface ( ) ;
auto size = bitmap_size_for_canvas ( ) ;
2024-12-04 15:35:16 +01:00
if ( ! surface ) {
2024-11-29 20:17:25 +01:00
// If the context is not initialized yet, we need to allocate transparent surface for serialization
auto skia_backend_context = navigable ( ) - > traversable_navigable ( ) - > skia_backend_context ( ) ;
surface = Gfx : : PaintingSurface : : create_with_size ( skia_backend_context , size , Gfx : : BitmapFormat : : BGRA8888 , Gfx : : AlphaType : : Premultiplied ) ;
2024-09-25 15:44:58 +02:00
}
2023-09-16 22:00:37 +02:00
2023-08-03 01:29:31 +02:00
// FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.
// 2. Let result be null.
RefPtr < Gfx : : Bitmap > bitmap_result ;
// 3. If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension nor its vertical dimension is zero),
// then set result to a copy of this canvas element's bitmap.
2024-11-29 20:17:25 +01:00
if ( surface ) {
bitmap_result = MUST ( Gfx : : Bitmap : : create ( Gfx : : BitmapFormat : : BGRA8888 , Gfx : : AlphaType : : Premultiplied , surface - > size ( ) ) ) ;
surface - > read_into_bitmap ( * bitmap_result ) ;
2024-09-25 15:44:58 +02:00
}
2023-08-03 01:29:31 +02:00
// 4. Run these steps in parallel:
2024-11-15 04:01:23 +13:00
Platform : : EventLoopPlugin : : the ( ) . deferred_invoke ( GC : : create_function ( heap ( ) , [ this , callback , bitmap_result , type , quality ] {
2023-08-03 01:29:31 +02:00
// 1. If result is non-null, then set result to a serialization of result as a file with type and quality if given.
Optional < SerializeBitmapResult > file_result ;
if ( bitmap_result ) {
if ( auto result = serialize_bitmap ( * bitmap_result , type , move ( quality ) ) ; ! result . is_error ( ) )
file_result = result . release_value ( ) ;
}
// 2. Queue an element task on the canvas blob serialization task source given the canvas element to run these steps:
queue_an_element_task ( Task : : Source : : CanvasBlobSerializationTask , [ this , callback , file_result = move ( file_result ) ] {
auto maybe_error = Bindings : : throw_dom_exception_if_needed ( vm ( ) , [ & ] ( ) - > WebIDL : : ExceptionOr < void > {
// 1. If result is non-null, then set result to a new Blob object, created in the relevant realm of this canvas element, representing result. [FILEAPI]
2024-11-15 04:01:23 +13:00
GC : : Ptr < FileAPI : : Blob > blob_result ;
2023-08-03 01:29:31 +02:00
if ( file_result . has_value ( ) )
2023-08-13 13:05:26 +02:00
blob_result = FileAPI : : Blob : : create ( realm ( ) , file_result - > buffer , TRY_OR_THROW_OOM ( vm ( ) , String : : from_utf8 ( file_result - > mime_type ) ) ) ;
2023-08-03 01:29:31 +02:00
// 2. Invoke callback with « result ».
TRY ( WebIDL : : invoke_callback ( * callback , { } , move ( blob_result ) ) ) ;
return { } ;
} ) ;
if ( maybe_error . is_throw_completion ( ) )
report_exception ( maybe_error . throw_completion ( ) , realm ( ) ) ;
} ) ;
2024-10-31 02:39:29 +13:00
} ) ) ;
2023-08-03 01:29:31 +02:00
return { } ;
}
2022-06-04 04:22:42 +01:00
void HTMLCanvasElement : : present ( )
{
2024-11-29 20:17:25 +01:00
if ( auto surface = this - > surface ( ) )
surface - > flush ( ) ;
2024-09-25 15:44:58 +02:00
2022-06-04 04:22:42 +01:00
m_context . visit (
2024-11-15 04:01:23 +13:00
[ ] ( GC : : Ref < CanvasRenderingContext2D > & ) {
2022-06-04 04:22:42 +01:00
// Do nothing, CRC2D writes directly to the canvas bitmap.
} ,
2024-11-15 04:01:23 +13:00
[ ] ( GC : : Ref < WebGL : : WebGLRenderingContext > & context ) {
2022-06-04 04:22:42 +01:00
context - > present ( ) ;
} ,
[ ] ( Empty ) {
// Do nothing.
} ) ;
}
2024-11-29 20:17:25 +01:00
RefPtr < Gfx : : PaintingSurface > HTMLCanvasElement : : surface ( ) const
{
return m_context . visit (
[ & ] ( GC : : Ref < CanvasRenderingContext2D > const & context ) {
return context - > surface ( ) ;
} ,
2024-11-29 22:15:02 +01:00
[ & ] ( GC : : Ref < WebGL : : WebGLRenderingContext > const & context ) - > RefPtr < Gfx : : PaintingSurface > {
return context - > surface ( ) ;
2024-11-29 20:17:25 +01:00
} ,
[ ] ( Empty ) - > RefPtr < Gfx : : PaintingSurface > {
return { } ;
} ) ;
}
void HTMLCanvasElement : : allocate_painting_surface_if_needed ( )
{
m_context . visit (
[ & ] ( GC : : Ref < CanvasRenderingContext2D > & context ) {
context - > allocate_painting_surface_if_needed ( ) ;
} ,
2024-11-29 22:15:02 +01:00
[ & ] ( GC : : Ref < WebGL : : WebGLRenderingContext > & context ) {
context - > allocate_painting_surface_if_needed ( ) ;
2024-11-29 20:17:25 +01:00
} ,
[ ] ( Empty ) {
// Do nothing.
} ) ;
}
2020-03-19 19:07:56 +01:00
}