imagebitmap: Resolve promise with ImageBitmap on bitmap task source (#37488)

Follow the ImageBitmap specification and use the global scope bitmap
task source
to fulfill resolved promise (asynchronously). 
https://html.spec.whatwg.org/multipage/#bitmap-task-source

Any promise rejection must be done synchronously.

Testing: Improvements in the following WPT test
-
html/canvas/element/manual/imagebitmap/createImageBitmap-resolves-in-task.any.js

Fixes (partially): #34112

Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
Andrei Volykhin 2025-06-17 11:19:32 +03:00 committed by GitHub
parent ef5e9b5f4d
commit 1bd8f38810
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 30 deletions

View file

@ -3009,6 +3009,22 @@ impl GlobalScope {
return p;
}
// The promise with image bitmap should be fulfilled on the the bitmap task source.
let fullfill_promise_on_bitmap_task_source =
|promise: &Rc<Promise>, image_bitmap: &ImageBitmap| {
let trusted_promise = TrustedPromise::new(promise.clone());
let trusted_image_bitmap = Trusted::new(image_bitmap);
self.task_manager()
.bitmap_task_source()
.queue(task!(resolve_promise: move || {
let promise = trusted_promise.root();
let image_bitmap = trusted_image_bitmap.root();
promise.resolve_native(&image_bitmap, CanGc::note());
}));
};
// Step 3. Check the usability of the image argument. If this throws an exception or returns bad,
// then return a promise rejected with an "InvalidStateError" DOMException.
// Step 6. Switch on image:
@ -3065,7 +3081,9 @@ impl GlobalScope {
// of imageBitmap's bitmap to false.
image_bitmap.set_origin_clean(image.same_origin(GlobalScope::entry().origin()));
p.resolve_native(&image_bitmap, can_gc);
// Step 6.5. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::HTMLVideoElement(ref video) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
@ -3103,7 +3121,9 @@ impl GlobalScope {
// of imageBitmap's bitmap to false.
image_bitmap.set_origin_clean(video.origin_is_clean());
p.resolve_native(&image_bitmap, can_gc);
// Step 6.4. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::HTMLCanvasElement(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
@ -3132,7 +3152,9 @@ impl GlobalScope {
// as the origin-clean flag of image's bitmap.
image_bitmap.set_origin_clean(canvas.origin_is_clean());
p.resolve_native(&image_bitmap, can_gc);
// Step 6.3. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::ImageBitmap(ref bitmap) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
@ -3161,7 +3183,9 @@ impl GlobalScope {
// as the origin-clean flag of image's bitmap.
image_bitmap.set_origin_clean(bitmap.origin_is_clean());
p.resolve_native(&image_bitmap, can_gc);
// Step 6.3. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::OffscreenCanvas(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
@ -3190,7 +3214,9 @@ impl GlobalScope {
// as the origin-clean flag of image's bitmap.
image_bitmap.set_origin_clean(canvas.origin_is_clean());
p.resolve_native(&image_bitmap, can_gc);
// Step 6.3. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::Blob(_) => {
// TODO: implement support of Blob object as ImageBitmapSource
@ -3227,7 +3253,9 @@ impl GlobalScope {
let image_bitmap = ImageBitmap::new(self, bitmap_data, can_gc);
p.resolve_native(&image_bitmap, can_gc);
// Step 6.4. Queue a global task, using the bitmap task source,
// to resolve promise with imageBitmap.
fullfill_promise_on_bitmap_task_source(&p, &image_bitmap);
},
ImageBitmapSource::CSSStyleValue(_) => {
// TODO: CSSStyleValue is not part of ImageBitmapSource

View file

@ -132,6 +132,7 @@ impl TaskManager {
.cancel_pending_tasks_for_source(task_source_name);
}
task_source_functions!(self, bitmap_task_source, Bitmap);
task_source_functions!(self, canvas_blob_task_source, Canvas);
task_source_functions!(self, clipboard_task_source, Clipboard);
task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);

View file

@ -22,6 +22,8 @@ use crate::task_manager::TaskManager;
/// doesn't implement TaskSource.
#[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, MallocSizeOf, PartialEq, VariantArray)]
pub(crate) enum TaskSourceName {
/// <https://html.spec.whatwg.org/multipage/#bitmap-task-source>
Bitmap,
Canvas,
Clipboard,
DOMManipulation,
@ -48,6 +50,7 @@ pub(crate) enum TaskSourceName {
impl From<TaskSourceName> for ScriptThreadEventCategory {
fn from(value: TaskSourceName) -> Self {
match value {
TaskSourceName::Bitmap => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::Canvas => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::Clipboard => ScriptThreadEventCategory::ScriptEvent,
TaskSourceName::DOMManipulation => ScriptThreadEventCategory::ScriptEvent,

View file

@ -1,16 +1,10 @@
[createImageBitmap-resolves-in-task.any.html]
[createImageBitmap with an HTMLCanvasElement source should resolve async]
expected: FAIL
[createImageBitmap with an HTMLVideoElement source should resolve async]
expected: FAIL
[createImageBitmap with an HTMLVideoElement from a data URL source should resolve async]
expected: FAIL
[createImageBitmap with a bitmap HTMLImageElement source should resolve async]
expected: FAIL
[createImageBitmap with a vector HTMLImageElement source should resolve async]
expected: FAIL
@ -32,28 +26,10 @@
[createImageBitmap with a vector SVGImageElement source should resolve async]
expected: FAIL
[createImageBitmap with an OffscreenCanvas source should resolve async]
expected: FAIL
[createImageBitmap with an ImageData source should resolve async]
expected: FAIL
[createImageBitmap with an ImageBitmap source should resolve async]
expected: FAIL
[createImageBitmap with a Blob source should resolve async]
expected: FAIL
[createImageBitmap-resolves-in-task.any.worker.html]
[createImageBitmap with an OffscreenCanvas source should resolve async]
expected: FAIL
[createImageBitmap with an ImageData source should resolve async]
expected: FAIL
[createImageBitmap with an ImageBitmap source should resolve async]
expected: FAIL
[createImageBitmap with a Blob source should resolve async]
expected: FAIL