WebIDL Fix ImageData constructor to take a Uint8ClampedArray instead of js_object (#31398)

<!-- Please describe your changes on the following line: -->

Fix ImageData constructor to take a Uint8ClampedArray instead of
js_object

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #31320

<!-- Either: -->
- [x] These changes do not require tests because there is not behavior
change.

<!-- Also, please make sure that "Allow edits from maintainers" checkbox
is checked, so that we can help you if you get stuck somewhere along the
way.-->

<!-- Pull requests that do not address these steps are welcome, but they
will require additional verification as part of the review process. -->

---------

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
This commit is contained in:
Taym Haddadi 2025-05-09 13:05:56 +02:00 committed by GitHub
parent 53be79a5b5
commit e5347eceac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 42 additions and 61 deletions

View file

@ -37,7 +37,7 @@ use js::rust::{
#[cfg(feature = "webgpu")] #[cfg(feature = "webgpu")]
use js::typedarray::{ArrayBuffer, HeapArrayBuffer}; use js::typedarray::{ArrayBuffer, HeapArrayBuffer};
use js::typedarray::{ use js::typedarray::{
ArrayBufferU8, ArrayBufferView, ArrayBufferViewU8, CreateWith, TypedArray, TypedArrayElement, ArrayBufferU8, ArrayBufferViewU8, CreateWith, TypedArray, TypedArrayElement,
TypedArrayElementCreator, TypedArrayElementCreator,
}; };
@ -63,36 +63,25 @@ pub(crate) enum BufferSource {
ArrayBuffer(Box<Heap<*mut JSObject>>), ArrayBuffer(Box<Heap<*mut JSObject>>),
} }
pub(crate) fn new_initialized_heap_buffer_source<T>( pub(crate) fn create_heap_buffer_source_with_length<T>(
init: HeapTypedArrayInit, cx: JSContext,
len: u32,
can_gc: CanGc, can_gc: CanGc,
) -> Result<HeapBufferSource<T>, ()> ) -> Fallible<HeapBufferSource<T>>
where where
T: TypedArrayElement + TypedArrayElementCreator, T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy, T::Element: Clone + Copy,
{ {
let heap_buffer_source = match init { rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
HeapTypedArrayInit::Buffer(buffer_source) => HeapBufferSource { let typed_array_result =
buffer_source, create_buffer_source_with_length::<T>(cx, len as usize, array.handle_mut(), can_gc);
phantom: PhantomData, if typed_array_result.is_err() {
}, return Err(Error::JSFailed);
HeapTypedArrayInit::Info { len, cx } => { }
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
let typed_array_result =
create_buffer_source_with_length::<T>(cx, len as usize, array.handle_mut(), can_gc);
if typed_array_result.is_err() {
return Err(());
}
HeapBufferSource::<T>::new(BufferSource::ArrayBufferView(Heap::boxed(*array.handle()))) Ok(HeapBufferSource::<T>::new(BufferSource::ArrayBufferView(
}, Heap::boxed(*array.handle()),
}; )))
Ok(heap_buffer_source)
}
pub(crate) enum HeapTypedArrayInit {
Buffer(BufferSource),
Info { len: u32, cx: JSContext },
} }
pub(crate) struct HeapBufferSource<T> { pub(crate) struct HeapBufferSource<T> {
@ -131,11 +120,11 @@ where
} }
pub(crate) fn from_view( pub(crate) fn from_view(
chunk: CustomAutoRooterGuard<ArrayBufferView>, chunk: CustomAutoRooterGuard<TypedArray<T, *mut JSObject>>,
) -> HeapBufferSource<ArrayBufferViewU8> { ) -> HeapBufferSource<T> {
HeapBufferSource::<ArrayBufferViewU8>::new(BufferSource::ArrayBufferView(Heap::boxed( HeapBufferSource::<T>::new(BufferSource::ArrayBufferView(Heap::boxed(unsafe {
unsafe { *chunk.underlying_object() }, *chunk.underlying_object()
))) })))
} }
pub(crate) fn default() -> Self { pub(crate) fn default() -> Self {

View file

@ -9,13 +9,13 @@ use std::vec::Vec;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use euclid::default::{Rect, Size2D}; use euclid::default::{Rect, Size2D};
use ipc_channel::ipc::IpcSharedMemory; use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::{Heap, JSObject}; use js::gc::CustomAutoRooterGuard;
use js::jsapi::JSObject;
use js::rust::HandleObject; use js::rust::HandleObject;
use js::typedarray::{ClampedU8, CreateWith, Uint8ClampedArray}; use js::typedarray::{ClampedU8, CreateWith, Uint8ClampedArray};
use super::bindings::buffer_source::{ use super::bindings::buffer_source::{HeapBufferSource, create_heap_buffer_source_with_length};
BufferSource, HeapBufferSource, HeapTypedArrayInit, new_initialized_heap_buffer_source, use crate::dom::bindings::buffer_source::create_buffer_source;
};
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::ImageDataMethods; use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::ImageDataMethods;
use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
@ -55,31 +55,31 @@ impl ImageData {
rooted!(in (*cx) let mut js_object = ptr::null_mut::<JSObject>()); rooted!(in (*cx) let mut js_object = ptr::null_mut::<JSObject>());
if let Some(ref mut d) = data { if let Some(ref mut d) = data {
d.resize(len as usize, 0); d.resize(len as usize, 0);
let typed_array =
create_buffer_source::<ClampedU8>(cx, &d[..], js_object.handle_mut(), can_gc)
.map_err(|_| Error::JSFailed)?;
let data = CreateWith::Slice(&d[..]); let data = CreateWith::Slice(&d[..]);
Uint8ClampedArray::create(*cx, data, js_object.handle_mut()).unwrap(); Uint8ClampedArray::create(*cx, data, js_object.handle_mut()).unwrap();
Self::new_with_jsobject(global, None, width, Some(height), js_object.get(), can_gc) auto_root!(in(*cx) let data = typed_array);
Self::new_with_data(global, None, width, Some(height), data, can_gc)
} else { } else {
Self::new_without_jsobject(global, None, width, height, can_gc) Self::new_without_data(global, None, width, height, can_gc)
} }
} }
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn new_with_jsobject( fn new_with_data(
global: &GlobalScope, global: &GlobalScope,
proto: Option<HandleObject>, proto: Option<HandleObject>,
width: u32, width: u32,
opt_height: Option<u32>, opt_height: Option<u32>,
jsobject: *mut JSObject, data: CustomAutoRooterGuard<Uint8ClampedArray>,
can_gc: CanGc, can_gc: CanGc,
) -> Fallible<DomRoot<ImageData>> { ) -> Fallible<DomRoot<ImageData>> {
let heap_typed_array = match new_initialized_heap_buffer_source::<ClampedU8>( let heap_typed_array = HeapBufferSource::<ClampedU8>::from_view(data);
HeapTypedArrayInit::Buffer(BufferSource::ArrayBufferView(Heap::boxed(jsobject))),
can_gc,
) {
Ok(heap_typed_array) => heap_typed_array,
Err(_) => return Err(Error::JSFailed),
};
let typed_array = match heap_typed_array.get_typed_array() { let typed_array = match heap_typed_array.get_typed_array() {
Ok(array) => array, Ok(array) => array,
@ -117,13 +117,14 @@ impl ImageData {
)) ))
} }
fn new_without_jsobject( fn new_without_data(
global: &GlobalScope, global: &GlobalScope,
proto: Option<HandleObject>, proto: Option<HandleObject>,
width: u32, width: u32,
height: u32, height: u32,
can_gc: CanGc, can_gc: CanGc,
) -> Fallible<DomRoot<ImageData>> { ) -> Fallible<DomRoot<ImageData>> {
// If one or both of sw and sh are zero, then throw an "IndexSizeError" DOMException.
if width == 0 || height == 0 { if width == 0 || height == 0 {
return Err(Error::IndexSize); return Err(Error::IndexSize);
} }
@ -139,13 +140,8 @@ impl ImageData {
let cx = GlobalScope::get_cx(); let cx = GlobalScope::get_cx();
let heap_typed_array = match new_initialized_heap_buffer_source::<ClampedU8>( let heap_typed_array = create_heap_buffer_source_with_length::<ClampedU8>(cx, len, can_gc)?;
HeapTypedArrayInit::Info { len, cx },
can_gc,
) {
Ok(heap_typed_array) => heap_typed_array,
Err(_) => return Err(Error::JSFailed),
};
let imagedata = Box::new(ImageData { let imagedata = Box::new(ImageData {
reflector_: Reflector::new(), reflector_: Reflector::new(),
width, width,
@ -198,20 +194,19 @@ impl ImageDataMethods<crate::DomTypeHolder> for ImageData {
width: u32, width: u32,
height: u32, height: u32,
) -> Fallible<DomRoot<Self>> { ) -> Fallible<DomRoot<Self>> {
Self::new_without_jsobject(global, proto, width, height, can_gc) Self::new_without_data(global, proto, width, height, can_gc)
} }
/// <https://html.spec.whatwg.org/multipage/#dom-imagedata-with-data> /// <https://html.spec.whatwg.org/multipage/#dom-imagedata-with-data>
fn Constructor_( fn Constructor_(
_cx: JSContext,
global: &GlobalScope, global: &GlobalScope,
proto: Option<HandleObject>, proto: Option<HandleObject>,
can_gc: CanGc, can_gc: CanGc,
jsobject: *mut JSObject, data: CustomAutoRooterGuard<Uint8ClampedArray>,
width: u32, width: u32,
opt_height: Option<u32>, opt_height: Option<u32>,
) -> Fallible<DomRoot<Self>> { ) -> Fallible<DomRoot<Self>> {
Self::new_with_jsobject(global, proto, width, opt_height, jsobject, can_gc) Self::new_with_data(global, proto, width, opt_height, data, can_gc)
} }
/// <https://html.spec.whatwg.org/multipage/#dom-imagedata-width> /// <https://html.spec.whatwg.org/multipage/#dom-imagedata-width>

View file

@ -254,7 +254,7 @@ interface CanvasPattern {
Serializable] Serializable]
interface ImageData { interface ImageData {
[Throws] constructor(unsigned long sw, unsigned long sh/*, optional ImageDataSettings settings = {}*/); [Throws] constructor(unsigned long sw, unsigned long sh/*, optional ImageDataSettings settings = {}*/);
[Throws] constructor(/* Uint8ClampedArray */ object data, unsigned long sw, optional unsigned long sh [Throws] constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh
/*, optional ImageDataSettings settings = {}*/); /*, optional ImageDataSettings settings = {}*/);
readonly attribute unsigned long width; readonly attribute unsigned long width;

View file

@ -1,3 +0,0 @@
[2d.imageData.object.ctor.basics.html]
[Testing different type of ImageData constructor]
expected: FAIL