mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
canvas: Add OffscreenCanvas 'transferToImageBitmap' method (#37880)
Follow the HTML speficication and add missing 'transferToImageBitmap' method to OffscreenCanvas interface. https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-transfertoimagebitmap Testing: Improvements in the following tests - html/canvas/offscreen/compositing/2d.composite.grid* - html/canvas/offscreen/fill-and-stroke-styles/2d.gradient* - html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas* - html/canvas/offscreen/reset/2d.reset* - html/canvas/offscreen/text/2d.text* Fixes (partially): #34111 Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
70b0fb840e
commit
9bd8d4f026
46 changed files with 110 additions and 84 deletions
|
@ -39,6 +39,11 @@ pub(crate) trait CanvasContext {
|
|||
|
||||
fn resize(&self);
|
||||
|
||||
// Resets the backing bitmap (to transparent or opaque black) without the
|
||||
// context state reset.
|
||||
// Used by OffscreenCanvas.transferToImageBitmap.
|
||||
fn reset_bitmap(&self);
|
||||
|
||||
/// Returns none if area of canvas is zero.
|
||||
///
|
||||
/// In case of other errors it returns cleared snapshot
|
||||
|
@ -145,6 +150,21 @@ impl CanvasContext for RenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
match self {
|
||||
RenderingContext::Placeholder(offscreen_canvas) => {
|
||||
if let Some(context) = offscreen_canvas.context() {
|
||||
context.reset_bitmap()
|
||||
}
|
||||
},
|
||||
RenderingContext::Context2d(context) => context.reset_bitmap(),
|
||||
RenderingContext::WebGL(context) => context.reset_bitmap(),
|
||||
RenderingContext::WebGL2(context) => context.reset_bitmap(),
|
||||
#[cfg(feature = "webgpu")]
|
||||
RenderingContext::WebGPU(context) => context.reset_bitmap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
match self {
|
||||
RenderingContext::Placeholder(offscreen_canvas) => {
|
||||
|
@ -257,6 +277,12 @@ impl CanvasContext for OffscreenRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
match self {
|
||||
OffscreenRenderingContext::Context2d(context) => context.reset_bitmap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
match self {
|
||||
OffscreenRenderingContext::Context2d(context) => context.get_image_data(),
|
||||
|
|
|
@ -292,6 +292,14 @@ impl CanvasState {
|
|||
*self.state.borrow_mut() = CanvasContextState::new();
|
||||
}
|
||||
|
||||
pub(crate) fn reset_bitmap(&self) {
|
||||
if !self.is_paintable() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.send_canvas_2d_msg(Canvas2dMsg::ClearRect(self.size.get().to_f32().into()));
|
||||
}
|
||||
|
||||
fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option<Rect<f32>> {
|
||||
if !([x, y, w, h].iter().all(|val| val.is_finite())) {
|
||||
return None;
|
||||
|
|
|
@ -153,6 +153,10 @@ impl CanvasContext for CanvasRenderingContext2D {
|
|||
self.set_canvas_bitmap_dimensions(self.size().cast())
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
self.canvas_state.reset_bitmap()
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
if !self.canvas_state.is_paintable() {
|
||||
return None;
|
||||
|
|
|
@ -27,6 +27,7 @@ use crate::dom::blob::Blob;
|
|||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
|
||||
use crate::dom::imagebitmap::ImageBitmap;
|
||||
use crate::dom::offscreencanvasrenderingcontext2d::OffscreenCanvasRenderingContext2D;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::realms::{AlreadyInRealm, InRealm};
|
||||
|
@ -214,6 +215,40 @@ impl OffscreenCanvasMethods<crate::DomTypeHolder> for OffscreenCanvas {
|
|||
}
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-transfertoimagebitmap>
|
||||
fn TransferToImageBitmap(&self, can_gc: CanGc) -> Fallible<DomRoot<ImageBitmap>> {
|
||||
// TODO Step 1. If the value of this OffscreenCanvas object's
|
||||
// [[Detached]] internal slot is set to true, then throw an
|
||||
// "InvalidStateError" DOMException.
|
||||
|
||||
// Step 2. If this OffscreenCanvas object's context mode is set to none,
|
||||
// then throw an "InvalidStateError" DOMException.
|
||||
if self.context.borrow().is_none() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
// Step 3. Let image be a newly created ImageBitmap object that
|
||||
// references the same underlying bitmap data as this OffscreenCanvas
|
||||
// object's bitmap.
|
||||
let Some(snapshot) = self.get_image_data() else {
|
||||
return Err(Error::InvalidState);
|
||||
};
|
||||
|
||||
let image_bitmap = ImageBitmap::new(&self.global(), snapshot, can_gc);
|
||||
image_bitmap.set_origin_clean(self.origin_is_clean());
|
||||
|
||||
// Step 4. Set this OffscreenCanvas object's bitmap to reference a newly
|
||||
// created bitmap of the same dimensions and color space as the previous
|
||||
// bitmap, and with its pixels initialized to transparent black, or
|
||||
// opaque black if the rendering context's alpha is false.
|
||||
if let Some(canvas_context) = self.context() {
|
||||
canvas_context.reset_bitmap();
|
||||
}
|
||||
|
||||
// Step 5. Return image.
|
||||
Ok(image_bitmap)
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-offscreencanvas-converttoblob>
|
||||
fn ConvertToBlob(&self, options: &ImageEncodeOptions, can_gc: CanGc) -> Rc<Promise> {
|
||||
// Step 5. Let result be a new promise object.
|
||||
|
|
|
@ -84,6 +84,10 @@ impl CanvasContext for OffscreenCanvasRenderingContext2D {
|
|||
self.context.resize()
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
self.context.reset_bitmap()
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
self.context.get_image_data()
|
||||
}
|
||||
|
|
|
@ -916,6 +916,10 @@ impl CanvasContext for WebGL2RenderingContext {
|
|||
self.base.resize();
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
self.base.reset_bitmap();
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
self.base.get_image_data()
|
||||
}
|
||||
|
|
|
@ -1974,6 +1974,10 @@ impl CanvasContext for WebGLRenderingContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
warn!("The WebGLRenderingContext 'reset_bitmap' is not implemented yet");
|
||||
}
|
||||
|
||||
// Used by HTMLCanvasElement.toDataURL
|
||||
//
|
||||
// This emits errors quite liberally, but the spec says that this operation
|
||||
|
|
|
@ -276,6 +276,10 @@ impl CanvasContext for GPUCanvasContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn reset_bitmap(&self) {
|
||||
warn!("The GPUCanvasContext 'reset_bitmap' is not implemented yet");
|
||||
}
|
||||
|
||||
/// <https://gpuweb.github.io/gpuweb/#ref-for-abstract-opdef-get-a-copy-of-the-image-contents-of-a-context%E2%91%A5>
|
||||
fn get_image_data(&self) -> Option<Snapshot> {
|
||||
// 1. Return a copy of the image contents of context.
|
||||
|
|
|
@ -519,7 +519,7 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'OffscreenCanvas': {
|
||||
'canGc': ['ConvertToBlob', 'GetContext', 'SetHeight', 'SetWidth'],
|
||||
'canGc': ['ConvertToBlob', 'GetContext', 'SetHeight', 'SetWidth', 'TransferToImageBitmap'],
|
||||
},
|
||||
|
||||
'OffscreenCanvasRenderingContext2D': {
|
||||
|
|
|
@ -20,6 +20,6 @@ interface OffscreenCanvas : EventTarget {
|
|||
attribute [EnforceRange] unsigned long long height;
|
||||
|
||||
[Throws] OffscreenRenderingContext? getContext(DOMString contextId, optional any options = null);
|
||||
//ImageBitmap transferToImageBitmap();
|
||||
[Throws] ImageBitmap transferToImageBitmap();
|
||||
Promise<Blob> convertToBlob(optional ImageEncodeOptions options = {});
|
||||
};
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.no_shadow.drawImage.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.no_shadow.fillRect.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.no_shadow.pattern.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.shadow.drawImage.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.shadow.fillRect.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.filter.shadow.pattern.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.no_shadow.drawImage.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.no_shadow.fillRect.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.no_shadow.pattern.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.shadow.drawImage.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.shadow.fillRect.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.composite.grid.no_filter.shadow.pattern.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.gradient.colorInterpolationMethod.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.gradient.hueInterpolationMethod.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.filter.drop-shadow-globalAlpha.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[offscreencanvas.filter.w.html]
|
||||
expected: ERROR
|
||||
[offscreencanvas]
|
||||
expected: TIMEOUT
|
|
@ -1,7 +1,4 @@
|
|||
[offscreencanvas.resize.html]
|
||||
[Verify that writing to the width and height attributes of an OffscreenCanvas works when there is a 2d context attached.]
|
||||
expected: FAIL
|
||||
|
||||
[Verify that resizing an OffscreenCanvas with a webgl context propagates the new size to its placeholder canvas asynchronously.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,18 +2,8 @@
|
|||
[Test that transferToImageBitmap returns an ImageBitmap with correct color]
|
||||
expected: FAIL
|
||||
|
||||
[Test that call transferToImageBitmap on a detached OffscreenCanvas throws an exception]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap returns an ImageBitmap with correct width and height]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap without a context throws an exception]
|
||||
[Test that call transferToImageBitmap on a detached OffscreenCanvas throws an exception]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap preserves transform]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap won't change context's property]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,26 +1,10 @@
|
|||
[offscreencanvas.transfer.to.imagebitmap.w.html]
|
||||
expected: ERROR
|
||||
[Test that call transferToImageBitmap twice returns an ImageBitmap with correct color in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap returns an ImageBitmap with correct width and height in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap returns an ImageBitmap with correct color in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that call transferToImageBitmap on a detached OffscreenCanvas throws an exception in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that call transferToImageBitmap without a context throws an exception in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that call transferToImageBitmap preserves transform in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that transferToImageBitmap won't change context's property in a worker]
|
||||
expected: FAIL
|
||||
|
||||
[Test that call transferToImageBitmap twice on a alpha-disabled context returns an ImageBitmap with correct color in a worker]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.after-rasterization.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.render.drop_shadow.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.render.global_composite_operation.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.render.line.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.render.misc.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.render.miter_limit.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +1,2 @@
|
|||
[2d.reset.render.text.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[2d.reset.state.clip.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +1,2 @@
|
|||
[2d.text.drawing.style.reset.fontKerning.none2.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[2d.text.fontVariantCaps.after.reset.font.w.html]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[2d.text.fontVariantCaps1.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.text.fontVariantCaps3.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.text.fontVariantCaps4.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.text.fontVariantCaps5.w.html]
|
||||
expected: TIMEOUT
|
|
@ -1,2 +0,0 @@
|
|||
[2d.text.fontVariantCaps6.w.html]
|
||||
expected: TIMEOUT
|
|
@ -26,9 +26,6 @@
|
|||
[ImageBitmapRenderingContext interface: operation transferFromImageBitmap(ImageBitmap?)]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvas interface: operation transferToImageBitmap()]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvas interface: attribute oncontextlost]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -4370,9 +4370,6 @@
|
|||
[ImageBitmapRenderingContext interface: operation transferFromImageBitmap(ImageBitmap?)]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvas interface: operation transferToImageBitmap()]
|
||||
expected: FAIL
|
||||
|
||||
[OffscreenCanvas interface: attribute oncontextlost]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue