diff --git a/components/pixels/lib.rs b/components/pixels/lib.rs index 5978a7ddde3..c1dbf35cbf3 100644 --- a/components/pixels/lib.rs +++ b/components/pixels/lib.rs @@ -31,6 +31,20 @@ pub enum PixelFormat { BGRA8, } +// Computes image byte length, returning None if overflow occurred or the total length exceeds +// the maximum image allocation size. +pub fn compute_rgba8_byte_length_if_within_limit(width: usize, height: usize) -> Option { + // Maximum allowed image allocation size (2^31-1 ~ 2GB). + const MAX_IMAGE_BYTE_LENGTH: usize = 2147483647; + + // The color components of each pixel must be stored in four sequential + // elements in the order of red, green, blue, and then alpha. + 4usize + .checked_mul(width) + .and_then(|v| v.checked_mul(height)) + .filter(|v| *v <= MAX_IMAGE_BYTE_LENGTH) +} + pub fn rgba8_get_rect(pixels: &[u8], size: Size2D, rect: Rect) -> Cow<[u8]> { assert!(!rect.is_empty()); assert!(Rect::from_size(size).contains_rect(&rect)); diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index a34b49f4a65..75abc67aef1 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -2982,10 +2982,13 @@ impl GlobalScope { return p; } - if let Some(snapshot) = canvas.get_image_data() { - let image_bitmap = ImageBitmap::new(self, snapshot, can_gc); - image_bitmap.set_origin_clean(canvas.origin_is_clean()); - p.resolve_native(&(image_bitmap), can_gc); + match canvas.get_image_data() { + Some(snapshot) => { + let image_bitmap = ImageBitmap::new(self, snapshot, can_gc); + image_bitmap.set_origin_clean(canvas.origin_is_clean()); + p.resolve_native(&(image_bitmap), can_gc); + }, + None => p.reject_error(Error::InvalidState, can_gc), } p }, @@ -2996,10 +2999,13 @@ impl GlobalScope { return p; } - if let Some(snapshot) = canvas.get_image_data() { - let image_bitmap = ImageBitmap::new(self, snapshot, can_gc); - image_bitmap.set_origin_clean(canvas.origin_is_clean()); - p.resolve_native(&(image_bitmap), can_gc); + match canvas.get_image_data() { + Some(snapshot) => { + let image_bitmap = ImageBitmap::new(self, snapshot, can_gc); + image_bitmap.set_origin_clean(canvas.origin_is_clean()); + p.resolve_native(&(image_bitmap), can_gc); + }, + None => p.reject_error(Error::InvalidState, can_gc), } p }, diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 499e91c127b..f287e6877e6 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -362,7 +362,13 @@ impl HTMLCanvasElement { Some(context) => context.get_image_data(), None => { let size = self.get_size(); - if size.width == 0 || size.height == 0 { + if size.is_empty() || + pixels::compute_rgba8_byte_length_if_within_limit( + size.width as usize, + size.height as usize, + ) + .is_none() + { None } else { Some(Snapshot::cleared(size.cast())) diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index a891064952a..fdb5fbb8942 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -41,14 +41,11 @@ impl ImageData { mut data: Option>, can_gc: CanGc, ) -> Fallible> { - // The color components of each pixel must be stored in four sequential - // elements in the order of red, green, blue, and then alpha. - let len = 4u32 - .checked_mul(width) - .and_then(|v| v.checked_mul(height)) - .ok_or(Error::Range( - "The requested image size exceeds the supported range".to_owned(), - ))?; + let len = + pixels::compute_rgba8_byte_length_if_within_limit(width as usize, height as usize) + .ok_or(Error::Range( + "The requested image size exceeds the supported range".to_owned(), + ))?; unsafe { let cx = GlobalScope::get_cx(); @@ -129,18 +126,16 @@ impl ImageData { return Err(Error::IndexSize); } - // The color components of each pixel must be stored in four sequential - // elements in the order of red, green, blue, and then alpha. - // Please note when a too-large ImageData is created using a constructor - // historically throwns an IndexSizeError, instead of RangeError. - let len = 4u32 - .checked_mul(width) - .and_then(|v| v.checked_mul(height)) - .ok_or(Error::IndexSize)?; + // When a constructor is called for an ImageData that is too large, other browsers throw + // IndexSizeError rather than RangeError here, so we do the same. + let len = + pixels::compute_rgba8_byte_length_if_within_limit(width as usize, height as usize) + .ok_or(Error::IndexSize)?; let cx = GlobalScope::get_cx(); - let heap_typed_array = create_heap_buffer_source_with_length::(cx, len, can_gc)?; + let heap_typed_array = + create_heap_buffer_source_with_length::(cx, len as u32, can_gc)?; let imagedata = Box::new(ImageData { reflector_: Reflector::new(), diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs index b4323ef6b54..e848ad862f8 100644 --- a/components/script/dom/offscreencanvas.rs +++ b/components/script/dom/offscreencanvas.rs @@ -92,7 +92,13 @@ impl OffscreenCanvas { Some(context) => context.get_image_data(), None => { let size = self.get_size(); - if size.width == 0 || size.height == 0 { + if size.is_empty() || + pixels::compute_rgba8_byte_length_if_within_limit( + size.width as usize, + size.height as usize, + ) + .is_none() + { None } else { Some(Snapshot::cleared(size)) diff --git a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini index aba246039a0..ee557e4bc27 100644 --- a/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini +++ b/tests/wpt/meta/html/canvas/element/manual/imagebitmap/createImageBitmap-invalid-args.html.ini @@ -1,5 +1,5 @@ [createImageBitmap-invalid-args.html] - expected: CRASH + expected: ERROR [createImageBitmap with a vector HTMLImageElement source and sw set to 0] expected: FAIL @@ -10,16 +10,13 @@ expected: FAIL [createImageBitmap with a broken image source.] - expected: NOTRUN - - [createImageBitmap with WebGLRenderingContext image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a Blob source and sw set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an available but zero height image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement source and sh set to 0] expected: FAIL @@ -28,25 +25,19 @@ expected: FAIL [createImageBitmap with a Blob source and sh set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and sw set to 0] expected: FAIL - [createImageBitmap with null image source.] - expected: NOTRUN - [createImageBitmap with an ImageData source and sh set to 0] - expected: NOTRUN - - [createImageBitmap with undefined image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with an undecodable blob source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with an available but undecodable image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and oversized (unallocatable) crop region] expected: FAIL @@ -55,13 +46,13 @@ expected: FAIL [createImageBitmap with a vector SVGImageElement source and oversized (unallocatable) crop region] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLCanvasElement source and oversized (unallocatable) crop region] expected: FAIL [createImageBitmap with an ImageBitmap source and oversized (unallocatable) crop region] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement source and oversized (unallocatable) crop region] expected: FAIL @@ -70,187 +61,112 @@ expected: FAIL [createImageBitmap with an ImageData source and sw set to 0] - expected: NOTRUN - - [createImageBitmap with an invalid OffscreenCanvas source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with an OffscreenCanvas source and sh set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an OffscreenCanvas source and sw set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and sh set to 0] expected: FAIL [createImageBitmap with an ImageData source and oversized (unallocatable) crop region] - expected: NOTRUN - - [createImageBitmap with ArrayBuffer image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap SVGImageElement source and oversized (unallocatable) crop region] - expected: NOTRUN - - [createImageBitmap with an oversized canvas source.] - expected: NOTRUN - - [createImageBitmap with Uint8Array image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a vector SVGImageElement source and sh set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLCanvasElement source and sh set to 0] expected: FAIL [createImageBitmap with a closed ImageBitmap.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap HTMLImageElement source and oversized (unallocatable) crop region] expected: FAIL [createImageBitmap with empty image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with empty video source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap SVGImageElement source and sw set to 0] - expected: TIMEOUT + expected: FAIL [createImageBitmap with an ImageBitmap source and sh set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an available but zero width image source.] - expected: NOTRUN + expected: FAIL [createImageBitmap with a vector SVGImageElement source and sw set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with a Blob source and oversized (unallocatable) crop region] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap SVGImageElement source and sh set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with an ImageBitmap source and sw set to 0] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap HTMLImageElement source and sw set to 0] expected: FAIL [createImageBitmap with an OffscreenCanvas source and oversized (unallocatable) crop region] - expected: NOTRUN - - [createImageBitmap with CanvasRenderingContext2D image source.] - expected: NOTRUN - - [createImageBitmap with a vector HTMLImageElement source and a value of 0 int resizeWidth] expected: FAIL - [createImageBitmap with a vector HTMLImageElement source and a value between 0 and 1 in resizeWidth] - expected: FAIL - - [createImageBitmap with an OffscreenCanvas source and a value of 0 in resizeHeight] - expected: NOTRUN - [createImageBitmap with a bitmap SVGImageElement source and a value of 0 in resizeHeight] - expected: NOTRUN - - [createImageBitmap with an ImageData source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN - - [createImageBitmap with a vector SVGImageElement source and a value of 0 int resizeWidth] - expected: NOTRUN - - [createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN - - [createImageBitmap with an ImageBitmap source and a value of 0 int resizeWidth] - expected: NOTRUN - - [createImageBitmap with an ImageData source and a value of 0 in resizeHeight] - expected: NOTRUN - - [createImageBitmap with an HTMLVideoElement source and a value between 0 and 1 in resizeWidth] expected: FAIL - [createImageBitmap with an OffscreenCanvas source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN + [createImageBitmap with a vector SVGImageElement source and a value of 0 int resizeWidth] + expected: FAIL + + [createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeWidth] + expected: FAIL + + [createImageBitmap with an ImageBitmap source and a value of 0 int resizeWidth] + expected: FAIL [createImageBitmap with a vector SVGImageElement source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN - - [createImageBitmap with a Blob source and a value of 0 int resizeWidth] - expected: NOTRUN - - [createImageBitmap with an HTMLVideoElement source and a value of 0 in resizeHeight] expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and a value between 0 and 1 in resizeWidth] expected: FAIL [createImageBitmap with a vector SVGImageElement source and a value of 0 in resizeHeight] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap SVGImageElement source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN - - [createImageBitmap with a Blob source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN - - [createImageBitmap with a Blob source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN - - [createImageBitmap with a vector HTMLImageElement source and a value between 0 and 1 in resizeHeight] expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and a value of 0 in resizeHeight] expected: FAIL [createImageBitmap with an ImageBitmap source and a value of 0 in resizeHeight] - expected: NOTRUN + expected: FAIL [createImageBitmap with an ImageBitmap source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN + expected: FAIL [createImageBitmap with a bitmap SVGImageElement source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN - - [createImageBitmap with an HTMLVideoElement source and a value between 0 and 1 in resizeHeight] expected: FAIL - [createImageBitmap with an HTMLVideoElement source and a value of 0 int resizeWidth] - expected: FAIL - - [createImageBitmap with an OffscreenCanvas source and a value of 0 int resizeWidth] - expected: NOTRUN - - [createImageBitmap with a vector HTMLImageElement source and a value of 0 in resizeHeight] - expected: FAIL - - [createImageBitmap with an OffscreenCanvas source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN - [createImageBitmap with a bitmap SVGImageElement source and a value of 0 int resizeWidth] - expected: NOTRUN + expected: FAIL [createImageBitmap with an HTMLVideoElement from a data URL source and a value of 0 int resizeWidth] expected: FAIL - [createImageBitmap with an ImageData source and a value between 0 and 1 in resizeHeight] - expected: NOTRUN - [createImageBitmap with an HTMLVideoElement from a data URL source and a value between 0 and 1 in resizeHeight] expected: FAIL - [createImageBitmap with an ImageData source and a value of 0 int resizeWidth] - expected: NOTRUN - [createImageBitmap with a vector SVGImageElement source and a value between 0 and 1 in resizeWidth] - expected: NOTRUN - - [createImageBitmap with a Blob source and a value of 0 in resizeHeight] - expected: NOTRUN + expected: FAIL