WedIDL: bring dom/bindings/typedarray further in line with spec (#31375)

* WedIDL: bring dom/bindings/typedarray further in line with spec

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* Rename HeapBufferSourceTypes to HeapBufferSource

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

* fmt code

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>

---------

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
This commit is contained in:
Taym Haddadi 2024-02-25 13:13:17 +01:00 committed by GitHub
parent 32f1d07323
commit d0b663800f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 505 additions and 317 deletions

View file

@ -9,7 +9,7 @@ use js::rust::{CustomAutoRooterGuard, HandleObject};
use js::typedarray::{Float32, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::audionode::MAX_CHANNEL_COUNT;
use crate::dom::bindings::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::AudioBufferBinding::{
@ -42,7 +42,7 @@ pub struct AudioBuffer {
reflector_: Reflector,
/// Float32Arrays returned by calls to GetChannelData.
#[ignore_malloc_size_of = "mozjs"]
js_channels: DomRefCell<Vec<HeapTypedArray<Float32>>>,
js_channels: DomRefCell<Vec<HeapBufferSource<Float32>>>,
/// Aggregates the data from js_channels.
/// This is Some<T> iff the buffers in js_channels are detached.
#[ignore_malloc_size_of = "servo_media"]
@ -60,10 +60,9 @@ pub struct AudioBuffer {
impl AudioBuffer {
#[allow(crown::unrooted_must_root)]
#[allow(unsafe_code)]
pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
let vec = (0..number_of_channels)
.map(|_| HeapTypedArray::default())
.map(|_| HeapBufferSource::default())
.collect();
AudioBuffer {
reflector_: Reflector::new(),
@ -238,7 +237,7 @@ impl AudioBufferMethods for AudioBuffer {
}
self.js_channels.borrow()[channel as usize]
.get_internal()
.get_buffer()
.map_err(|_| Error::JSFailed)
}

View file

@ -0,0 +1,441 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
use std::borrow::BorrowMut;
use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr;
use std::sync::{Arc, Mutex};
use js::jsapi::{
Heap, JSObject, JS_GetArrayBufferViewBuffer, JS_IsArrayBufferViewObject, NewExternalArrayBuffer,
};
use js::rust::wrappers::DetachArrayBuffer;
use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject};
use js::typedarray::{CreateWith, TypedArray, TypedArrayElement, TypedArrayElementCreator};
use crate::script_runtime::JSContext;
/// <https://webidl.spec.whatwg.org/#BufferSource>
#[allow(dead_code)]
pub enum BufferSource {
Int8Array(Box<Heap<*mut JSObject>>),
Int16Array(Box<Heap<*mut JSObject>>),
Int32Array(Box<Heap<*mut JSObject>>),
Uint8Array(Box<Heap<*mut JSObject>>),
Uint16Array(Box<Heap<*mut JSObject>>),
Uint32Array(Box<Heap<*mut JSObject>>),
Uint8ClampedArray(Box<Heap<*mut JSObject>>),
BigInt64Array(Box<Heap<*mut JSObject>>),
BigUint64Array(Box<Heap<*mut JSObject>>),
Float32Array(Box<Heap<*mut JSObject>>),
Float64Array(Box<Heap<*mut JSObject>>),
DataView(Box<Heap<*mut JSObject>>),
ArrayBuffer(Box<Heap<*mut JSObject>>),
Default(Box<Heap<*mut JSObject>>),
}
pub struct HeapBufferSource<T> {
buffer_source: BufferSource,
phantom: PhantomData<T>,
}
unsafe impl<T> crate::dom::bindings::trace::JSTraceable for HeapBufferSource<T> {
#[inline]
unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) {
match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.trace(tracer);
},
}
}
}
pub fn new_initialized_heap_buffer_source_types<T>(
init: HeapTypedArrayInit,
) -> Result<HeapBufferSource<T>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
let heap_buffer_source_types = match init {
HeapTypedArrayInit::Buffer(buffer_source) => HeapBufferSource {
buffer_source: buffer_source,
phantom: PhantomData::default(),
},
HeapTypedArrayInit::Info { len, cx } => {
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
let typed_array_result =
create_buffer_source_types_with_length::<T>(cx, len as usize, array.handle_mut());
if typed_array_result.is_err() {
return Err(());
}
let heap_buffer_source_types = HeapBufferSource::<T>::default();
match &heap_buffer_source_types.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.set(*array);
},
}
heap_buffer_source_types
},
};
Ok(heap_buffer_source_types)
}
pub enum HeapTypedArrayInit {
Buffer(BufferSource),
Info { len: u32, cx: JSContext },
}
impl<T> HeapBufferSource<T>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
pub fn default() -> HeapBufferSource<T> {
HeapBufferSource {
buffer_source: BufferSource::Default(Box::new(Heap::default())),
phantom: PhantomData::default(),
}
}
pub fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> {
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
let _: TypedArray<T, *mut JSObject> =
create_buffer_source_types(cx, data, array.handle_mut())?;
match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.set(*array);
},
}
Ok(())
}
pub fn acquire_data(&self, cx: JSContext) -> Result<Vec<T::Element>, ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.get()
},
});
let data = if let Ok(array) =
array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()>
{
let data = array.to_vec();
let _ = self.detach_buffer(cx);
Ok(data)
} else {
Err(())
};
match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.set(ptr::null_mut());
},
}
data
}
/// <https://tc39.es/ecma262/#sec-detacharraybuffer>
pub fn detach_buffer(&self, cx: JSContext) -> bool {
match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
assert!(self.is_initialized());
let mut is_shared = false;
unsafe {
if JS_IsArrayBufferViewObject(*buffer.handle()) {
// If it is an ArrayBuffer view, get the buffer using JS_GetArrayBufferViewBuffer
rooted!(in (*cx) let view_buffer =
JS_GetArrayBufferViewBuffer(*cx, buffer.handle(), &mut is_shared));
// This buffer is always created unshared
debug_assert!(!is_shared);
// Detach the ArrayBuffer
DetachArrayBuffer(*cx, view_buffer.handle())
} else {
// If it's not an ArrayBuffer view, Detach the buffer directly
DetachArrayBuffer(*cx, Handle::from_raw(buffer.handle()))
}
}
},
}
}
pub fn copy_data_to(
&self,
cx: JSContext,
dest: &mut [T::Element],
source_start: usize,
length: usize,
) -> Result<(), ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let array: TypedArray = match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.get()
},
});
let Ok(array) = array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()> else{
return Err(())
};
unsafe {
let slice = (*array).as_slice();
dest.copy_from_slice(&slice[source_start..length]);
}
Ok(())
}
pub fn copy_data_from(
&self,
cx: JSContext,
source: CustomAutoRooterGuard<TypedArray<T, *mut JSObject>>,
dest_start: usize,
length: usize,
) -> Result<(), ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let mut array: TypedArray = match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => {
buffer.get()
},
});
let Ok(mut array) = array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()> else
{
return Err(())
};
unsafe {
let slice = (*array).as_mut_slice();
let (_, dest) = slice.split_at_mut(dest_start);
dest[0..length].copy_from_slice(&source.as_slice()[0..length])
}
Ok(())
}
pub fn is_initialized(&self) -> bool {
match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => !buffer.get().is_null(),
}
}
pub fn get_buffer(&self) -> Result<TypedArray<T, *mut JSObject>, ()> {
TypedArray::from(match &self.buffer_source {
BufferSource::Int8Array(buffer) |
BufferSource::Int16Array(buffer) |
BufferSource::Int32Array(buffer) |
BufferSource::Uint8Array(buffer) |
BufferSource::Uint16Array(buffer) |
BufferSource::Uint32Array(buffer) |
BufferSource::Uint8ClampedArray(buffer) |
BufferSource::BigInt64Array(buffer) |
BufferSource::BigUint64Array(buffer) |
BufferSource::Float32Array(buffer) |
BufferSource::Float64Array(buffer) |
BufferSource::DataView(buffer) |
BufferSource::ArrayBuffer(buffer) |
BufferSource::Default(buffer) => buffer.get(),
})
}
pub fn buffer_to_option(&self) -> Option<TypedArray<T, *mut JSObject>> {
if self.is_initialized() {
Some(self.get_buffer().expect("Failed to get buffer."))
} else {
warn!("Buffer not initialized.");
None
}
}
}
/// <https://webidl.spec.whatwg.org/#arraybufferview-create>
pub fn create_buffer_source_types<T>(
cx: JSContext,
data: &[T::Element],
dest: MutableHandleObject,
) -> Result<TypedArray<T, *mut JSObject>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
{
let res = unsafe { TypedArray::<T, *mut JSObject>::create(*cx, CreateWith::Slice(data), dest) };
if res.is_err() {
Err(())
} else {
TypedArray::from(dest.get())
}
}
fn create_buffer_source_types_with_length<T>(
cx: JSContext,
len: usize,
dest: MutableHandleObject,
) -> Result<TypedArray<T, *mut JSObject>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
{
let res = unsafe { TypedArray::<T, *mut JSObject>::create(*cx, CreateWith::Length(len), dest) };
if res.is_err() {
Err(())
} else {
TypedArray::from(dest.get())
}
}
pub fn create_new_external_array_buffer<T>(
cx: JSContext,
mapping: Arc<Mutex<Vec<T::Element>>>,
offset: usize,
range_size: usize,
m_end: usize,
) -> HeapBufferSource<T>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
/// `freeFunc()` must be threadsafe, should be safely callable from any thread
/// without causing conflicts , unexpected behavior.
/// <https://github.com/servo/mozjs/blob/main/mozjs-sys/mozjs/js/public/ArrayBuffer.h#L89>
unsafe extern "C" fn free_func(_contents: *mut c_void, free_user_data: *mut c_void) {
let _ = Arc::from_raw(free_user_data as _);
}
unsafe {
let mapping_slice_ptr =
mapping.lock().unwrap().borrow_mut()[offset as usize..m_end as usize].as_mut_ptr();
// rooted! is needed to ensure memory safety and prevent potential garbage collection issues.
// https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr78/docs/GC%20Rooting%20Guide.md#performance-tweaking
rooted!(in(*cx) let array_buffer = NewExternalArrayBuffer(
*cx,
range_size as usize,
mapping_slice_ptr as _,
Some(free_func),
Arc::into_raw(mapping) as _,
));
HeapBufferSource {
buffer_source: BufferSource::ArrayBuffer(Heap::boxed(*array_buffer)),
phantom: PhantomData::default(),
}
}
}

View file

@ -134,6 +134,7 @@
#![deny(missing_docs)]
#![deny(non_snake_case)]
pub mod buffer_source;
pub mod callback;
pub mod cell;
pub mod constant;
@ -159,7 +160,6 @@ pub mod str;
pub mod structuredclone;
pub mod trace;
pub mod transferable;
pub mod typedarrays;
pub mod utils;
pub mod weakref;
pub mod xmlname;

View file

@ -1,250 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
use std::borrow::BorrowMut;
use std::ffi::c_void;
use std::marker::PhantomData;
use std::ptr;
use std::sync::{Arc, Mutex};
use js::jsapi::{
Heap, JSObject, JS_GetArrayBufferViewBuffer, JS_IsArrayBufferViewObject, NewExternalArrayBuffer,
};
use js::rust::wrappers::DetachArrayBuffer;
use js::rust::{CustomAutoRooterGuard, Handle, MutableHandleObject};
use js::typedarray::{CreateWith, TypedArray, TypedArrayElement, TypedArrayElementCreator};
use crate::script_runtime::JSContext;
pub struct HeapTypedArray<T> {
internal: Box<Heap<*mut JSObject>>,
phantom: PhantomData<T>,
}
unsafe impl<T> crate::dom::bindings::trace::JSTraceable for HeapTypedArray<T> {
#[inline]
unsafe fn trace(&self, tracer: *mut js::jsapi::JSTracer) {
self.internal.trace(tracer);
}
}
pub fn new_initialized_heap_typed_array<T>(
init: HeapTypedArrayInit,
) -> Result<HeapTypedArray<T>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
let heap_typed_array = match init {
HeapTypedArrayInit::Object(js_object) => HeapTypedArray {
internal: Heap::boxed(js_object),
phantom: PhantomData::default(),
},
HeapTypedArrayInit::Info { len, cx } => {
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
let typed_array_result =
create_typed_array_with_length::<T>(cx, len as usize, array.handle_mut());
if typed_array_result.is_err() {
return Err(());
}
let heap_typed_array = HeapTypedArray::<T>::default();
heap_typed_array.internal.set(*array);
heap_typed_array
},
};
Ok(heap_typed_array)
}
pub enum HeapTypedArrayInit {
Object(*mut JSObject),
Info { len: u32, cx: JSContext },
}
impl<T> HeapTypedArray<T>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
pub fn default() -> HeapTypedArray<T> {
HeapTypedArray {
internal: Box::new(Heap::default()),
phantom: PhantomData::default(),
}
}
pub fn set_data(&self, cx: JSContext, data: &[T::Element]) -> Result<(), ()> {
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
let _: TypedArray<T, *mut JSObject> = create_typed_array(cx, data, array.handle_mut())?;
self.internal.set(*array);
Ok(())
}
pub fn acquire_data(&self, cx: JSContext) -> Result<Vec<T::Element>, ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let array: TypedArray = self.internal.get());
let data = if let Ok(array) =
array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()>
{
let data = array.to_vec();
let _ = self.detach_internal(cx);
Ok(data)
} else {
Err(())
};
self.internal.set(ptr::null_mut());
data
}
/// <https://tc39.es/ecma262/#sec-detacharraybuffer>
pub fn detach_internal(&self, cx: JSContext) -> bool {
assert!(self.is_initialized());
let mut is_shared = false;
unsafe {
if JS_IsArrayBufferViewObject(*self.internal.handle()) {
// If it is an ArrayBuffer view, get the buffer using JS_GetArrayBufferViewBuffer
rooted!(in (*cx) let view_buffer =
JS_GetArrayBufferViewBuffer(*cx, self.internal.handle(), &mut is_shared));
// This buffer is always created unshared
debug_assert!(!is_shared);
// Detach the ArrayBuffer
DetachArrayBuffer(*cx, view_buffer.handle())
} else {
// If it's not an ArrayBuffer view, Detach the internal buffer directly
DetachArrayBuffer(*cx, Handle::from_raw(self.internal.handle()))
}
}
}
pub fn copy_data_to(
&self,
cx: JSContext,
dest: &mut [T::Element],
source_start: usize,
length: usize,
) -> Result<(), ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let array: TypedArray = self.internal.get());
let Ok(array) = array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()> else{
return Err(())
};
unsafe {
let slice = (*array).as_slice();
dest.copy_from_slice(&slice[source_start..length]);
}
Ok(())
}
pub fn copy_data_from(
&self,
cx: JSContext,
source: CustomAutoRooterGuard<TypedArray<T, *mut JSObject>>,
dest_start: usize,
length: usize,
) -> Result<(), ()> {
assert!(self.is_initialized());
typedarray!(in(*cx) let mut array: TypedArray = self.internal.get());
let Ok(mut array) = array as Result<CustomAutoRooterGuard<'_, TypedArray<T, *mut JSObject>>, &mut ()> else
{
return Err(())
};
unsafe {
let slice = (*array).as_mut_slice();
let (_, dest) = slice.split_at_mut(dest_start);
dest[0..length].copy_from_slice(&source.as_slice()[0..length])
}
Ok(())
}
pub fn is_initialized(&self) -> bool {
!self.internal.get().is_null()
}
pub fn get_internal(&self) -> Result<TypedArray<T, *mut JSObject>, ()> {
TypedArray::from(self.internal.get())
}
pub fn internal_to_option(&self) -> Option<TypedArray<T, *mut JSObject>> {
if self.is_initialized() {
Some(self.get_internal().expect("Failed to get internal."))
} else {
warn!("Internal not initialized.");
None
}
}
}
pub fn create_typed_array<T>(
cx: JSContext,
data: &[T::Element],
dest: MutableHandleObject,
) -> Result<TypedArray<T, *mut JSObject>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
{
let res = unsafe { TypedArray::<T, *mut JSObject>::create(*cx, CreateWith::Slice(data), dest) };
if res.is_err() {
Err(())
} else {
TypedArray::from(dest.get())
}
}
fn create_typed_array_with_length<T>(
cx: JSContext,
len: usize,
dest: MutableHandleObject,
) -> Result<TypedArray<T, *mut JSObject>, ()>
where
T: TypedArrayElement + TypedArrayElementCreator,
{
let res = unsafe { TypedArray::<T, *mut JSObject>::create(*cx, CreateWith::Length(len), dest) };
if res.is_err() {
Err(())
} else {
TypedArray::from(dest.get())
}
}
pub fn create_new_external_array_buffer<T>(
cx: JSContext,
mapping: Arc<Mutex<Vec<T::Element>>>,
offset: usize,
range_size: usize,
m_end: usize,
) -> HeapTypedArray<T>
where
T: TypedArrayElement + TypedArrayElementCreator,
T::Element: Clone + Copy,
{
/// `freeFunc()` must be threadsafe, should be safely callable from any thread
/// without causing conflicts or unexpected behavior.
/// <https://github.com/servo/mozjs/blob/main/mozjs-sys/mozjs/js/public/ArrayBuffer.h#L89>
unsafe extern "C" fn free_func(_contents: *mut c_void, free_user_data: *mut c_void) {
let _ = Arc::from_raw(free_user_data as _);
}
unsafe {
let mapping_slice_ptr =
mapping.lock().unwrap().borrow_mut()[offset as usize..m_end as usize].as_mut_ptr();
// rooted! is needed to ensure memory safety and prevent potential garbage collection issues.
// https://github.com/mozilla-spidermonkey/spidermonkey-embedding-examples/blob/esr78/docs/GC%20Rooting%20Guide.md#performance-tweaking
rooted!(in(*cx) let array_buffer = NewExternalArrayBuffer(
*cx,
range_size as usize,
mapping_slice_ptr as _,
Some(free_func),
Arc::into_raw(mapping) as _,
));
HeapTypedArray {
internal: Heap::boxed(*array_buffer),
phantom: PhantomData::default(),
}
}
}

View file

@ -15,6 +15,7 @@ use js::typedarray::{Float32Array, Float64Array};
use style::parser::ParserContext;
use url::Url;
use crate::dom::bindings::buffer_source::create_buffer_source_types;
use crate::dom::bindings::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::DOMMatrixBinding::{DOMMatrixInit, DOMMatrixMethods};
use crate::dom::bindings::codegen::Bindings::DOMMatrixReadOnlyBinding::DOMMatrixReadOnlyMethods;
@ -25,7 +26,6 @@ use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::typedarrays::create_typed_array;
use crate::dom::dommatrix::DOMMatrix;
use crate::dom::dompoint::DOMPoint;
use crate::dom::globalscope::GlobalScope;
@ -686,14 +686,14 @@ impl DOMMatrixReadOnlyMethods for DOMMatrixReadOnly {
.map(|&x| x as f32)
.collect();
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
create_typed_array(cx, &vec, array.handle_mut())
create_buffer_source_types(cx, &vec, array.handle_mut())
.expect("Converting matrix to float32 array should never fail")
}
// https://drafts.fxtf.org/geometry-1/#dom-dommatrixreadonly-tofloat64array
fn ToFloat64Array(&self, cx: JSContext) -> Float64Array {
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
create_typed_array(cx, &self.matrix.borrow().to_array(), array.handle_mut())
create_buffer_source_types(cx, &self.matrix.borrow().to_array(), array.handle_mut())
.expect("Converting matrix to float64 array should never fail")
}
}

View file

@ -9,13 +9,13 @@ use js::jsapi::JSObject;
use js::rust::HandleObject;
use js::typedarray::{ArrayBuffer, ArrayBufferU8};
use crate::dom::bindings::buffer_source::create_buffer_source_types;
use crate::dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use crate::dom::bindings::codegen::Bindings::FileReaderSyncBinding::FileReaderSyncMethods;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::typedarrays::create_typed_array;
use crate::dom::blob::Blob;
use crate::dom::filereader::FileReaderSharedFunctionality;
use crate::dom::globalscope::GlobalScope;
@ -95,7 +95,7 @@ impl FileReaderSyncMethods for FileReaderSync {
// step 2
rooted!(in(*cx) let mut array_buffer = ptr::null_mut::<JSObject>());
create_typed_array::<ArrayBufferU8>(cx, &blob_contents, array_buffer.handle_mut())
create_buffer_source_types::<ArrayBufferU8>(cx, &blob_contents, array_buffer.handle_mut())
.map_err(|_| Error::JSFailed)
}
}

View file

@ -7,7 +7,7 @@ use std::cell::Cell;
use dom_struct::dom_struct;
use js::typedarray::{Float64, Float64Array};
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::bindings::codegen::Bindings::GamepadBinding::{GamepadHand, GamepadMethods};
use crate::dom::bindings::codegen::Bindings::GamepadButtonListBinding::GamepadButtonListMethods;
use crate::dom::bindings::inheritance::Castable;
@ -37,7 +37,7 @@ pub struct Gamepad {
timestamp: Cell<f64>,
mapping_type: String,
#[ignore_malloc_size_of = "mozjs"]
axes: HeapTypedArray<Float64>,
axes: HeapBufferSource<Float64>,
buttons: Dom<GamepadButtonList>,
pose: Option<Dom<GamepadPose>>,
#[ignore_malloc_size_of = "Defined in rust-webvr"]
@ -68,7 +68,7 @@ impl Gamepad {
connected: Cell::new(connected),
timestamp: Cell::new(timestamp),
mapping_type: mapping_type,
axes: HeapTypedArray::default(),
axes: HeapBufferSource::default(),
buttons: Dom::from_ref(buttons),
pose: pose.map(Dom::from_ref),
hand: hand,
@ -150,9 +150,7 @@ impl GamepadMethods for Gamepad {
// https://w3c.github.io/gamepad/#dom-gamepad-axes
fn Axes(&self, _cx: JSContext) -> Float64Array {
self.axes
.get_internal()
.expect("Failed to get gamepad axes.")
self.axes.get_buffer().expect("Failed to get gamepad axes.")
}
// https://w3c.github.io/gamepad/#dom-gamepad-buttons
@ -232,7 +230,7 @@ impl Gamepad {
if normalized_value.is_finite() {
let mut axis_vec = self
.axes
.internal_to_option()
.buffer_to_option()
.expect("Axes have not been initialized!");
unsafe {
axis_vec.as_mut_slice()[axis_index] = normalized_value;

View file

@ -5,7 +5,7 @@
use dom_struct::dom_struct;
use js::typedarray::{Float32, Float32Array};
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::bindings::codegen::Bindings::GamepadPoseBinding::GamepadPoseMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
@ -16,17 +16,17 @@ use crate::script_runtime::JSContext;
pub struct GamepadPose {
reflector_: Reflector,
#[ignore_malloc_size_of = "mozjs"]
position: HeapTypedArray<Float32>,
position: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "mozjs"]
orientation: HeapTypedArray<Float32>,
orientation: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "mozjs"]
linear_vel: HeapTypedArray<Float32>,
linear_vel: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "mozjs"]
angular_vel: HeapTypedArray<Float32>,
angular_vel: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "mozjs"]
linear_acc: HeapTypedArray<Float32>,
linear_acc: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "mozjs"]
angular_acc: HeapTypedArray<Float32>,
angular_acc: HeapBufferSource<Float32>,
}
// TODO: support gamepad discovery
@ -35,12 +35,12 @@ impl GamepadPose {
fn new_inherited() -> GamepadPose {
GamepadPose {
reflector_: Reflector::new(),
position: HeapTypedArray::default(),
orientation: HeapTypedArray::default(),
linear_vel: HeapTypedArray::default(),
angular_vel: HeapTypedArray::default(),
linear_acc: HeapTypedArray::default(),
angular_acc: HeapTypedArray::default(),
position: HeapBufferSource::default(),
orientation: HeapBufferSource::default(),
linear_vel: HeapBufferSource::default(),
angular_vel: HeapBufferSource::default(),
linear_acc: HeapBufferSource::default(),
angular_acc: HeapBufferSource::default(),
}
}
@ -52,7 +52,7 @@ impl GamepadPose {
impl GamepadPoseMethods for GamepadPose {
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-position
fn GetPosition(&self, _cx: JSContext) -> Option<Float32Array> {
self.position.internal_to_option()
self.position.buffer_to_option()
}
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-hasposition
@ -62,17 +62,17 @@ impl GamepadPoseMethods for GamepadPose {
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearvelocity
fn GetLinearVelocity(&self, _cx: JSContext) -> Option<Float32Array> {
self.linear_vel.internal_to_option()
self.linear_vel.buffer_to_option()
}
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-linearacceleration
fn GetLinearAcceleration(&self, _cx: JSContext) -> Option<Float32Array> {
self.linear_acc.internal_to_option()
self.linear_acc.buffer_to_option()
}
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation
fn GetOrientation(&self, _cx: JSContext) -> Option<Float32Array> {
self.orientation.internal_to_option()
self.orientation.buffer_to_option()
}
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-orientation
@ -82,11 +82,11 @@ impl GamepadPoseMethods for GamepadPose {
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularvelocity
fn GetAngularVelocity(&self, _cx: JSContext) -> Option<Float32Array> {
self.angular_vel.internal_to_option()
self.angular_vel.buffer_to_option()
}
// https://w3c.github.io/gamepad/extensions.html#dom-gamepadpose-angularacceleration
fn GetAngularAcceleration(&self, _cx: JSContext) -> Option<Float32Array> {
self.angular_acc.internal_to_option()
self.angular_acc.buffer_to_option()
}
}

View file

@ -15,7 +15,7 @@ use webgpu::identity::WebGPUOpResult;
use webgpu::wgpu::device::HostMap;
use webgpu::{WebGPU, WebGPUBuffer, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
use super::bindings::typedarrays::{create_new_external_array_buffer, HeapTypedArray};
use super::bindings::buffer_source::{create_new_external_array_buffer, HeapBufferSource};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
GPUBufferMethods, GPUMapModeConstants, GPUSize64,
@ -54,7 +54,7 @@ pub struct GPUBufferMapInfo {
pub mapping_range: Range<u64>,
pub mapped_ranges: Vec<Range<u64>>,
#[ignore_malloc_size_of = "defined in mozjs"]
pub js_buffers: Vec<HeapTypedArray<ArrayBufferU8>>,
pub js_buffers: Vec<HeapBufferSource<ArrayBufferU8>>,
pub map_mode: Option<u32>,
}
@ -169,7 +169,7 @@ impl GPUBufferMethods for GPUBuffer {
}
// Step 3.3
m_info.js_buffers.drain(..).for_each(|obj| {
obj.detach_internal(cx);
obj.detach_buffer(cx);
});
},
// Step 2
@ -325,7 +325,7 @@ impl GPUBufferMethods for GPUBuffer {
m_end as usize,
);
let result = heap_typed_array.get_internal().map_err(|_| Error::JSFailed);
let result = heap_typed_array.get_buffer().map_err(|_| Error::JSFailed);
m_info.mapped_ranges.push(offset..m_end);
m_info.js_buffers.push(heap_typed_array);

View file

@ -9,12 +9,12 @@ use std::vec::Vec;
use dom_struct::dom_struct;
use euclid::default::{Rect, Size2D};
use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::JSObject;
use js::jsapi::{Heap, JSObject};
use js::rust::HandleObject;
use js::typedarray::{ClampedU8, CreateWith, Uint8ClampedArray};
use super::bindings::typedarrays::{
new_initialized_heap_typed_array, HeapTypedArray, HeapTypedArrayInit,
use super::bindings::buffer_source::{
new_initialized_heap_buffer_source_types, BufferSource, HeapBufferSource, HeapTypedArrayInit,
};
use crate::dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::ImageDataMethods;
use crate::dom::bindings::error::{Error, Fallible};
@ -29,7 +29,7 @@ pub struct ImageData {
width: u32,
height: u32,
#[ignore_malloc_size_of = "mozjs"]
data: HeapTypedArray<ClampedU8>,
data: HeapBufferSource<ClampedU8>,
}
impl ImageData {
@ -63,14 +63,14 @@ impl ImageData {
opt_height: Option<u32>,
jsobject: *mut JSObject,
) -> Fallible<DomRoot<ImageData>> {
let heap_typed_array = match new_initialized_heap_typed_array::<ClampedU8>(
HeapTypedArrayInit::Object(jsobject),
let heap_typed_array = match new_initialized_heap_buffer_source_types::<ClampedU8>(
HeapTypedArrayInit::Buffer(BufferSource::Uint8ClampedArray(Heap::boxed(jsobject))),
) {
Ok(heap_typed_array) => heap_typed_array,
Err(_) => return Err(Error::JSFailed),
};
let typed_array = match heap_typed_array.get_internal() {
let typed_array = match heap_typed_array.get_buffer() {
Ok(array) => array,
Err(_) => {
return Err(Error::Type(
@ -117,7 +117,7 @@ impl ImageData {
let len = width * height * 4;
let heap_typed_array =
match new_initialized_heap_typed_array::<ClampedU8>(HeapTypedArrayInit::Info {
match new_initialized_heap_buffer_source_types::<ClampedU8>(HeapTypedArrayInit::Info {
len,
cx,
}) {
@ -163,7 +163,7 @@ impl ImageData {
assert!(self.data.is_initialized());
let internal_data = self
.data
.get_internal()
.get_buffer()
.expect("Failed to get Data from ImageData.");
// NOTE(nox): This is just as unsafe as `as_slice` itself even though we
// are extending the lifetime of the slice, because the data in
@ -202,6 +202,6 @@ impl ImageDataMethods for ImageData {
/// <https://html.spec.whatwg.org/multipage/#dom-imagedata-data>
fn GetData(&self, _: JSContext) -> Fallible<Uint8ClampedArray> {
self.data.get_internal().map_err(|_| Error::JSFailed)
self.data.get_buffer().map_err(|_| Error::JSFailed)
}
}

View file

@ -17,6 +17,7 @@ use script_traits::serializable::BlobImpl;
use script_traits::MsDuration;
use servo_config::prefs;
use crate::dom::bindings::buffer_source::create_buffer_source_types;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
@ -41,7 +42,6 @@ use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, DomObject,
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{ByteString, DOMString, USVString};
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::bindings::typedarrays::create_typed_array;
use crate::dom::bindings::weakref::MutableWeakRef;
use crate::dom::blob::Blob;
use crate::dom::globalscope::GlobalScope;
@ -214,7 +214,7 @@ impl TestBindingMethods for TestBinding {
let data: [u8; 16] = [0; 16];
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
create_typed_array(cx, &data, array.handle_mut())
create_buffer_source_types(cx, &data, array.handle_mut())
.expect("Creating ClampedU8 array should never fail")
}
fn AnyAttribute(&self, _: SafeJSContext) -> JSVal {

View file

@ -9,12 +9,12 @@ use js::jsapi::JSObject;
use js::rust::HandleObject;
use js::typedarray::Uint8Array;
use crate::dom::bindings::buffer_source::create_buffer_source_types;
use crate::dom::bindings::codegen::Bindings::TextEncoderBinding::TextEncoderMethods;
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::reflector::{reflect_dom_object_with_proto, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::typedarrays::create_typed_array;
use crate::dom::globalscope::GlobalScope;
use crate::script_runtime::JSContext;
@ -55,7 +55,7 @@ impl TextEncoderMethods for TextEncoder {
let encoded = input.0.as_bytes();
rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
create_typed_array(cx, &encoded, js_object.handle_mut())
create_buffer_source_types(cx, &encoded, js_object.handle_mut())
.expect("Converting input to uint8 array should never fail")
}
}

View file

@ -8,7 +8,7 @@ use js::rust::HandleObject;
use js::typedarray::{Float32, Float32Array};
use webxr_api::{ApiSpace, Ray};
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::Bindings::XRRayBinding::{XRRayDirectionInit, XRRayMethods};
use crate::dom::bindings::error::{Error, Fallible};
@ -27,7 +27,7 @@ pub struct XRRay {
#[no_trace]
ray: Ray<ApiSpace>,
#[ignore_malloc_size_of = "defined in mozjs"]
matrix: HeapTypedArray<Float32>,
matrix: HeapBufferSource<Float32>,
}
impl XRRay {
@ -35,7 +35,7 @@ impl XRRay {
XRRay {
reflector_: Reflector::new(),
ray,
matrix: HeapTypedArray::default(),
matrix: HeapBufferSource::default(),
}
}
@ -163,7 +163,7 @@ impl XRRayMethods for XRRay {
}
self.matrix
.get_internal()
.get_buffer()
.expect("Failed to get matrix from XRRay.")
}
}

View file

@ -7,7 +7,7 @@ use euclid::{RigidTransform3D, Rotation3D, Vector3D};
use js::rust::HandleObject;
use js::typedarray::{Float32, Float32Array};
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding::XRRigidTransformMethods;
use crate::dom::bindings::error::{Error, Fallible};
@ -29,7 +29,7 @@ pub struct XRRigidTransform {
transform: ApiRigidTransform,
inverse: MutNullableDom<XRRigidTransform>,
#[ignore_malloc_size_of = "defined in mozjs"]
matrix: HeapTypedArray<Float32>,
matrix: HeapBufferSource<Float32>,
}
impl XRRigidTransform {
@ -40,7 +40,7 @@ impl XRRigidTransform {
orientation: MutNullableDom::default(),
transform,
inverse: MutNullableDom::default(),
matrix: HeapTypedArray::default(),
matrix: HeapBufferSource::default(),
}
}
@ -140,7 +140,7 @@ impl XRRigidTransformMethods for XRRigidTransform {
}
self.matrix
.get_internal()
.get_buffer()
.expect("Failed to get transform's internal matrix.")
}
}

View file

@ -7,7 +7,7 @@ use euclid::RigidTransform3D;
use js::typedarray::{Float32, Float32Array};
use webxr_api::{ApiSpace, View};
use super::bindings::typedarrays::HeapTypedArray;
use super::bindings::buffer_source::HeapBufferSource;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
@ -23,7 +23,7 @@ pub struct XRView {
eye: XREye,
viewport_index: usize,
#[ignore_malloc_size_of = "mozjs"]
proj: HeapTypedArray<Float32>,
proj: HeapBufferSource<Float32>,
#[ignore_malloc_size_of = "defined in rust-webxr"]
#[no_trace]
view: View<ApiSpace>,
@ -43,7 +43,7 @@ impl XRView {
session: Dom::from_ref(session),
eye,
viewport_index,
proj: HeapTypedArray::default(),
proj: HeapBufferSource::default(),
view,
transform: Dom::from_ref(transform),
}
@ -98,7 +98,7 @@ impl XRViewMethods for XRView {
.expect("Failed to set projection matrix.")
}
self.proj
.get_internal()
.get_buffer()
.expect("Failed to get projection matrix.")
}