imagebitmap: Add missing basic functionality (#37025)

Add missing basic functionality for ImageBitmap
https://html.spec.whatwg.org/multipage/#imagebitmap
including new variant of creation bitmap with source rectangle
https://html.spec.whatwg.org/multipage/#dom-createimagebitmap
but without support of cropping bitmap data with formatting.

Add ImageBitmap to CanvasImageSource union type
https://html.spec.whatwg.org/multipage/#canvasimagesource

Add ImageBitmap to TexImageSource for WebGL
https://registry.khronos.org/webgl/specs/latest/1.0/index.html

Testing: Improvements in the following WPT tests
 - html/canvas/element/manual/imagebitmap/*
 - html/canvas/element/manual/wide-gamut-canvas/*
 - html/semantics/embedded-content/the-canvas-element/*
 - webgl/tests/conformance/textures/image_bitmap_from*
 - webmessaging/postMessage_cross_domain_image_transfer_2d.sub.htm

Fixes: https://github.com/servo/servo/issues/34112

Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
Andrei Volykhin 2025-06-09 17:28:30 +03:00 committed by GitHub
parent a3c792e5aa
commit 7f536e8092
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
79 changed files with 653 additions and 1232 deletions

View file

@ -55,6 +55,7 @@ use crate::dom::element::{Element, cors_setting_for_element};
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmlvideoelement::HTMLVideoElement;
use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeTraits};
use crate::dom::offscreencanvas::OffscreenCanvas;
@ -319,6 +320,7 @@ impl CanvasState {
},
CanvasImageSource::HTMLVideoElement(video) => video.origin_is_clean(),
CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
CanvasImageSource::ImageBitmap(bitmap) => bitmap.origin_is_clean(),
CanvasImageSource::OffscreenCanvas(canvas) => canvas.origin_is_clean(),
CanvasImageSource::CSSStyleValue(_) => true,
}
@ -459,6 +461,15 @@ impl CanvasState {
self.draw_html_canvas_element(canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh)
},
CanvasImageSource::ImageBitmap(ref bitmap) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if bitmap.is_detached() {
return Err(Error::InvalidState);
}
self.draw_image_bitmap(bitmap, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh);
Ok(())
},
CanvasImageSource::OffscreenCanvas(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if canvas.get_size().is_empty() {
@ -728,6 +739,52 @@ impl CanvasState {
Ok(())
}
/// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
#[allow(clippy::too_many_arguments)]
fn draw_image_bitmap(
&self,
bitmap: &ImageBitmap,
canvas: Option<&HTMLCanvasElement>,
sx: f64,
sy: f64,
sw: Option<f64>,
sh: Option<f64>,
dx: f64,
dy: f64,
dw: Option<f64>,
dh: Option<f64>,
) {
let Some(snapshot) = bitmap.bitmap_data().clone() else {
return;
};
// Step 4. Establish the source and destination rectangles.
let bitmap_size = snapshot.size();
let dw = dw.unwrap_or(bitmap_size.width as f64);
let dh = dh.unwrap_or(bitmap_size.height as f64);
let sw = sw.unwrap_or(bitmap_size.width as f64);
let sh = sh.unwrap_or(bitmap_size.height as f64);
let (source_rect, dest_rect) =
self.adjust_source_dest_rects(bitmap_size, sx, sy, sw, sh, dx, dy, dw, dh);
// Step 5. If one of the sw or sh arguments is zero, then return. Nothing is painted.
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
return;
}
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
snapshot.as_ipc(),
dest_rect,
source_rect,
smoothing_enabled,
));
self.mark_as_dirty(canvas);
}
pub(crate) fn mark_as_dirty(&self, canvas: Option<&HTMLCanvasElement>) {
if let Some(canvas) = canvas {
canvas.mark_as_dirty();
@ -1063,6 +1120,14 @@ impl CanvasState {
canvas.get_image_data().ok_or(Error::InvalidState)?
},
CanvasImageSource::ImageBitmap(ref bitmap) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if bitmap.is_detached() {
return Err(Error::InvalidState);
}
bitmap.bitmap_data().clone().ok_or(Error::InvalidState)?
},
CanvasImageSource::OffscreenCanvas(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if canvas.get_size().is_empty() {