diff options
author | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-09-17 15:59:16 -0700 |
---|---|---|
committer | Emilio Cobos Álvarez <ecoal95@gmail.com> | 2016-10-09 12:41:13 +0200 |
commit | f985a73caeef534c3eacf1cbc8c7337064b6f005 (patch) | |
tree | 9ec24c9fd9747f1e0b500012e63541373b650d35 /components/script/dom/webglrenderingcontext.rs | |
parent | 602246a14ccf3027232d642eaa30ed97dab48c2d (diff) | |
download | servo-f985a73caeef534c3eacf1cbc8c7337064b6f005.tar.gz servo-f985a73caeef534c3eacf1cbc8c7337064b6f005.zip |
webgl: Handle both sequences and typed arrays, managing the type error ourselves.
This is a step with multiple intentions:
* Be correct.
* Unlock tests that are blocking @anholt.
* Ease the transition to typed arrays once the changes by @Ms2ger start rolling
in, since I expect the amount of test expectations to update to be
non-trivial.
Diffstat (limited to 'components/script/dom/webglrenderingcontext.rs')
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 401 |
1 files changed, 232 insertions, 169 deletions
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 644066b6710..ae971503864 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -8,8 +8,10 @@ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGL use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods; use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement; -use dom::bindings::conversions::{ToJSValConvertible, array_buffer_view_data, array_buffer_view_data_checked}; -use dom::bindings::conversions::{array_buffer_view_to_vec, array_buffer_view_to_vec_checked}; +use dom::bindings::conversions::{ArrayBufferViewContents, ConversionResult, FromJSValConvertible, ToJSValConvertible}; +use dom::bindings::conversions::{array_buffer_view_data, array_buffer_view_data_checked, array_buffer_view_to_vec}; +use dom::bindings::conversions::array_buffer_view_to_vec_checked; +use dom::bindings::error::{Error, Fallible}; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; @@ -34,6 +36,7 @@ use dom::webgltexture::{TexParameterValue, WebGLTexture}; use dom::webgluniformlocation::WebGLUniformLocation; use euclid::size::Size2D; use ipc_channel::ipc::{self, IpcSender}; +use js::conversions::ConversionBehavior; use js::jsapi::{JSContext, JSObject, JS_GetArrayBufferViewType, Type}; use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue, UndefinedValue}; use net_traits::image::base::PixelFormat; @@ -288,7 +291,7 @@ impl WebGLRenderingContext { fn validate_uniform_parameters<T>(&self, uniform: Option<&WebGLUniformLocation>, uniform_type: UniformSetterType, - data: Option<&[T]>) -> bool { + data: &[T]) -> bool { let uniform = match uniform { Some(uniform) => uniform, None => return false, @@ -303,14 +306,6 @@ impl WebGLRenderingContext { }, }; - let data = match data { - Some(data) => data, - None => { - self.webgl_error(InvalidOperation); - return false; - }, - }; - // TODO(emilio): Get more complex uniform info from ANGLE, and use it to // properly validate that the uniform setter type is compatible with the // uniform type, and that the uniform size matches. @@ -391,12 +386,12 @@ impl WebGLRenderingContext { // TODO(emilio): Move this logic to a validator. #[allow(unsafe_code)] unsafe fn validate_tex_image_2d_data(&self, - width: u32, - height: u32, - format: TexFormat, - data_type: TexDataType, - data: *mut JSObject) - -> Result<u32, ()> { + width: u32, + height: u32, + format: TexFormat, + data_type: TexDataType, + data: *mut JSObject) + -> Result<u32, ()> { let element_size = data_type.element_size(); let components_per_element = data_type.components_per_element(); let components = format.components(); @@ -531,6 +526,45 @@ impl Drop for WebGLRenderingContext { } } +// FIXME: After [1] lands and the relevant Servo and codegen PR too, we should +// convert all our raw JSObject pointers to proper types. +// +// [1]: https://github.com/servo/rust-mozjs/pull/304 +#[allow(unsafe_code)] +unsafe fn typed_array_or_sequence_to_vec<T>(cx: *mut JSContext, + sequence_or_abv: *mut JSObject, + config: <T as FromJSValConvertible>::Config) -> Result<Vec<T>, Error> + where T: ArrayBufferViewContents + FromJSValConvertible, + <T as FromJSValConvertible>::Config: Clone, +{ + assert!(!sequence_or_abv.is_null()); + if let Some(v) = array_buffer_view_to_vec_checked::<T>(sequence_or_abv) { + return Ok(v); + } + + rooted!(in(cx) let mut val = UndefinedValue()); + sequence_or_abv.to_jsval(cx, val.handle_mut()); + + match Vec::<T>::from_jsval(cx, val.handle(), config) { + Ok(ConversionResult::Success(v)) => Ok(v), + Ok(ConversionResult::Failure(error)) => Err(Error::Type(error.into_owned())), + // FIXME: What to do here? Generated code only aborts the execution of + // the script. + Err(err) => panic!("unexpected conversion error: {:?}", err), + } +} + +#[allow(unsafe_code)] +unsafe fn fallible_array_buffer_view_to_vec<T>(abv: *mut JSObject) -> Result<Vec<T>, Error> + where T: ArrayBufferViewContents +{ + assert!(!abv.is_null()); + match array_buffer_view_to_vec::<T>(abv) { + Some(v) => Ok(v), + None => Err(Error::Type("Not an ArrayBufferView".to_owned())), + } +} + impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.1 fn Canvas(&self) -> Root<HTMLCanvasElement> { @@ -844,85 +878,92 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 - fn BufferData(&self, _cx: *mut JSContext, target: u32, data: *mut JSObject, usage: u32) { + fn BufferData(&self, _cx: *mut JSContext, target: u32, data: *mut JSObject, usage: u32) -> Fallible<()> { + if data.is_null() { + return Ok(self.webgl_error(InvalidValue)); + } + + let data_vec = try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(data) }); + let bound_buffer = match target { constants::ARRAY_BUFFER => self.bound_buffer_array.get(), constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(), - _ => return self.webgl_error(InvalidEnum), + _ => return Ok(self.webgl_error(InvalidEnum)), }; let bound_buffer = match bound_buffer { Some(bound_buffer) => bound_buffer, - None => return self.webgl_error(InvalidValue), + None => return Ok(self.webgl_error(InvalidValue)), }; match usage { constants::STREAM_DRAW | constants::STATIC_DRAW | constants::DYNAMIC_DRAW => (), - _ => return self.webgl_error(InvalidEnum), + _ => return Ok(self.webgl_error(InvalidEnum)), } - if let Some(data_vec) = unsafe { array_buffer_view_to_vec::<u8>(data) } { - handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data_vec, usage)); - } else { - // NB: array_buffer_view_to_vec should never fail when we have - // WebIDL support for Float32Array etc. - self.webgl_error(InvalidValue); - } + handle_potential_webgl_error!(self, bound_buffer.buffer_data(target, &data_vec, usage)); + + Ok(()) } #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.5 - fn BufferSubData(&self, _cx: *mut JSContext, target: u32, offset: i64, data: *mut JSObject) { + fn BufferSubData(&self, _cx: *mut JSContext, target: u32, offset: i64, data: *mut JSObject) -> Fallible<()> { + if data.is_null() { + return Ok(self.webgl_error(InvalidValue)); + } + + let data_vec = try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(data) }); + let bound_buffer = match target { constants::ARRAY_BUFFER => self.bound_buffer_array.get(), constants::ELEMENT_ARRAY_BUFFER => self.bound_buffer_element_array.get(), - _ => return self.webgl_error(InvalidEnum), + _ => return Ok(self.webgl_error(InvalidEnum)), }; let bound_buffer = match bound_buffer { Some(bound_buffer) => bound_buffer, - None => return self.webgl_error(InvalidOperation), + None => return Ok(self.webgl_error(InvalidOperation)), }; - if data.is_null() { - return self.webgl_error(InvalidValue); - } - if offset < 0 { - return self.webgl_error(InvalidValue); + return Ok(self.webgl_error(InvalidValue)); } - if let Some(data_vec) = unsafe { array_buffer_view_to_vec::<u8>(data) } { - if (offset as usize) + data_vec.len() > bound_buffer.capacity() { - return self.webgl_error(InvalidValue); - } - self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::BufferSubData(target, offset as isize, data_vec))) - .unwrap() - } else { - // NB: array_buffer_view_to_vec should never fail when we have - // WebIDL support for Float32Array etc. - self.webgl_error(InvalidValue); + if (offset as usize) + data_vec.len() > bound_buffer.capacity() { + return Ok(self.webgl_error(InvalidValue)); } + self.ipc_renderer + .send(CanvasMsg::WebGL(WebGLCommand::BufferSubData(target, offset as isize, data_vec))) + .unwrap(); + + Ok(()) } + #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CompressedTexImage2D(&self, _cx: *mut JSContext, _target: u32, _level: i32, _internal_format: u32, - _width: i32, _height: i32, _border: i32, _pixels: *mut JSObject) { + _width: i32, _height: i32, _border: i32, pixels: *mut JSObject) -> Fallible<()> { + let _data = try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(pixels) }); // FIXME: No compressed texture format is currently supported, so error out as per // https://www.khronos.org/registry/webgl/specs/latest/1.0/#COMPRESSED_TEXTURE_SUPPORT - self.webgl_error(InvalidEnum) + self.webgl_error(InvalidEnum); + Ok(()) } + #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 fn CompressedTexSubImage2D(&self, _cx: *mut JSContext, _target: u32, _level: i32, _xoffset: i32, _yoffset: i32, _width: i32, _height: i32, - _format: u32, _pixels: *mut JSObject) { + _format: u32, pixels: *mut JSObject) -> Fallible<()> { + let _data = try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(pixels) }); // FIXME: No compressed texture format is currently supported, so error out as per // https://www.khronos.org/registry/webgl/specs/latest/1.0/#COMPRESSED_TEXTURE_SUPPORT - self.webgl_error(InvalidEnum) + self.webgl_error(InvalidEnum); + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -1650,23 +1691,23 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { #[allow(unsafe_code)] // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.12 fn ReadPixels(&self, _cx: *mut JSContext, x: i32, y: i32, width: i32, height: i32, - format: u32, pixel_type: u32, pixels: *mut JSObject) { + format: u32, pixel_type: u32, pixels: *mut JSObject) -> Fallible<()> { if pixels.is_null() { - return self.webgl_error(InvalidValue); + return Ok(self.webgl_error(InvalidValue)); } let mut data = match unsafe { array_buffer_view_data::<u8>(pixels) } { Some(data) => data, - None => return self.webgl_error(InvalidValue), + None => return Err(Error::Type("Not an ArrayBufferView".to_owned())), }; if !self.validate_framebuffer_complete() { - return; + return Ok(()); } match unsafe { JS_GetArrayBufferViewType(pixels) } { Type::Uint8 => (), - _ => return self.webgl_error(InvalidOperation) + _ => return Ok(self.webgl_error(InvalidOperation)), } let (sender, receiver) = ipc::channel().unwrap(); @@ -1677,12 +1718,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { let result = receiver.recv().unwrap(); if result.len() > data.len() { - return self.webgl_error(InvalidOperation) + return Ok(self.webgl_error(InvalidOperation)); } for i in 0..result.len() { data[i] = result[i] } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 @@ -1802,7 +1845,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn Uniform1f(&self, uniform: Option<&WebGLUniformLocation>, val: f32) { - if self.validate_uniform_parameters(uniform, UniformSetterType::Float, Some(&[val])) { + if self.validate_uniform_parameters(uniform, UniformSetterType::Float, &[val]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform1f(uniform.unwrap().id(), val))) .unwrap() @@ -1813,7 +1856,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { fn Uniform1i(&self, uniform: Option<&WebGLUniformLocation>, val: i32) { - if self.validate_uniform_parameters(uniform, UniformSetterType::Int, Some(&[val])) { + if self.validate_uniform_parameters(uniform, UniformSetterType::Int, &[val]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform1i(uniform.unwrap().id(), val))) .unwrap() @@ -1823,40 +1866,44 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform1iv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<i32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<i32>(cx, data, ConversionBehavior::Default) }); - if self.validate_uniform_parameters(uniform, UniformSetterType::Int, data_vec.as_ref().map(Vec::as_slice)) { + if self.validate_uniform_parameters(uniform, UniformSetterType::Int, &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform1iv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform1fv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<f32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); - if self.validate_uniform_parameters(uniform, UniformSetterType::Float, data_vec.as_ref().map(Vec::as_slice)) { + if self.validate_uniform_parameters(uniform, UniformSetterType::Float, &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform1fv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 fn Uniform2f(&self, uniform: Option<&WebGLUniformLocation>, x: f32, y: f32) { - if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, Some(&[x, y])) { + if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, &[x, y]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform2f(uniform.unwrap().id(), x, y))) .unwrap() @@ -1866,18 +1913,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform2fv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<f32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); + if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec2, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform2fv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -1886,7 +1936,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: i32, y: i32) { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec2, - Some(&[x, y])) { + &[x, y]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform2i(uniform.unwrap().id(), x, y))) .unwrap() @@ -1896,19 +1946,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform2iv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<i32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<i32>(cx, data, ConversionBehavior::Default) }); if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec2, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform2iv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -1917,7 +1969,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: f32, y: f32, z: f32) { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec3, - Some(&[x, y, z])) { + &[x, y, z]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform3f(uniform.unwrap().id(), x, y, z))) .unwrap() @@ -1927,19 +1979,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform3fv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<f32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec3, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform3fv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -1948,7 +2002,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: i32, y: i32, z: i32) { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec3, - Some(&[x, y, z])) { + &[x, y, z]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform3i(uniform.unwrap().id(), x, y, z))) .unwrap() @@ -1958,19 +2012,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform3iv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<i32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<i32>(cx, data, ConversionBehavior::Default) }); if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec3, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform3iv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -1979,7 +2035,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: i32, y: i32, z: i32, w: i32) { if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec4, - Some(&[x, y, z, w])) { + &[x, y, z, w]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform4i(uniform.unwrap().id(), x, y, z, w))) .unwrap() @@ -1990,19 +2046,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform4iv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<i32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<i32>(cx, data, ConversionBehavior::Default) }); if self.validate_uniform_parameters(uniform, UniformSetterType::IntVec4, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform4iv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2011,7 +2069,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { x: f32, y: f32, z: f32, w: f32) { if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec4, - Some(&[x, y, z, w])) { + &[x, y, z, w]) { self.ipc_renderer .send(CanvasMsg::WebGL(WebGLCommand::Uniform4f(uniform.unwrap().id(), x, y, z, w))) .unwrap() @@ -2021,19 +2079,21 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] fn Uniform4fv(&self, - _cx: *mut JSContext, + cx: *mut JSContext, uniform: Option<&WebGLUniformLocation>, - data: *mut JSObject) { + data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - let data_vec = unsafe { array_buffer_view_to_vec::<f32>(data) }; + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); if self.validate_uniform_parameters(uniform, UniformSetterType::FloatVec4, - data_vec.as_ref().map(Vec::as_slice)) { + &data_vec) { self.ipc_renderer - .send(CanvasMsg::WebGL(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec.unwrap()))) + .send(CanvasMsg::WebGL(WebGLCommand::Uniform4fv(uniform.unwrap().id(), data_vec))) .unwrap() } + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.9 @@ -2062,16 +2122,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] - fn VertexAttrib1fv(&self, _cx: *mut JSContext, indx: u32, data: *mut JSObject) { + fn VertexAttrib1fv(&self, cx: *mut JSContext, indx: u32, data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - if let Some(data_vec) = unsafe { array_buffer_view_to_vec_checked::<f32>(data) } { - if data_vec.len() < 1 { - return self.webgl_error(InvalidOperation); - } - self.vertex_attrib(indx, data_vec[0], 0f32, 0f32, 1f32) - } else { - self.webgl_error(InvalidValue); + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); + if data_vec.len() < 1 { + return Ok(self.webgl_error(InvalidOperation)); } + self.vertex_attrib(indx, data_vec[0], 0f32, 0f32, 1f32); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2081,16 +2139,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] - fn VertexAttrib2fv(&self, _cx: *mut JSContext, indx: u32, data: *mut JSObject) { + fn VertexAttrib2fv(&self, cx: *mut JSContext, indx: u32, data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - if let Some(data_vec) = unsafe { array_buffer_view_to_vec_checked::<f32>(data) } { - if data_vec.len() < 2 { - return self.webgl_error(InvalidOperation); - } - self.vertex_attrib(indx, data_vec[0], data_vec[1], 0f32, 1f32) - } else { - self.webgl_error(InvalidValue); + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); + if data_vec.len() < 2 { + return Ok(self.webgl_error(InvalidOperation)); } + self.vertex_attrib(indx, data_vec[0], data_vec[1], 0f32, 1f32); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2100,16 +2156,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] - fn VertexAttrib3fv(&self, _cx: *mut JSContext, indx: u32, data: *mut JSObject) { + fn VertexAttrib3fv(&self, cx: *mut JSContext, indx: u32, data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - if let Some(data_vec) = unsafe { array_buffer_view_to_vec_checked::<f32>(data) } { - if data_vec.len() < 3 { - return self.webgl_error(InvalidOperation); - } - self.vertex_attrib(indx, data_vec[0], data_vec[1], data_vec[2], 1f32) - } else { - self.webgl_error(InvalidValue); + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); + if data_vec.len() < 3 { + return Ok(self.webgl_error(InvalidOperation)); } + self.vertex_attrib(indx, data_vec[0], data_vec[1], data_vec[2], 1f32); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2119,16 +2173,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 #[allow(unsafe_code)] - fn VertexAttrib4fv(&self, _cx: *mut JSContext, indx: u32, data: *mut JSObject) { + fn VertexAttrib4fv(&self, cx: *mut JSContext, indx: u32, data: *mut JSObject) -> Fallible<()> { assert!(!data.is_null()); - if let Some(data_vec) = unsafe { array_buffer_view_to_vec_checked::<f32>(data) } { - if data_vec.len() < 4 { - return self.webgl_error(InvalidOperation); - } - self.vertex_attrib(indx, data_vec[0], data_vec[1], data_vec[2], data_vec[3]) - } else { - self.webgl_error(InvalidValue); + let data_vec = try!(unsafe { typed_array_or_sequence_to_vec::<f32>(cx, data, ()) }); + if data_vec.len() < 4 { + return Ok(self.webgl_error(InvalidOperation)); } + + self.vertex_attrib(indx, data_vec[0], data_vec[1], data_vec[2], data_vec[3]); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.10 @@ -2195,7 +2248,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { border: i32, format: u32, data_type: u32, - data: *mut JSObject) { + data_ptr: *mut JSObject) -> Fallible<()> { + let data = if data_ptr.is_null() { + None + } else { + Some(try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(data_ptr) })) + }; + let validator = TexImage2DValidator::new(self, target, level, internal_format, width, height, border, format, data_type); @@ -2211,34 +2270,32 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, } = match validator.validate() { Ok(result) => result, - Err(_) => return, // NB: The validator sets the correct error for us. + Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; let expected_byte_length = match unsafe { self.validate_tex_image_2d_data(width, height, format, data_type, - data) } { + data_ptr) } { Ok(byte_length) => byte_length, - Err(_) => return, + Err(()) => return Ok(()), }; // If data is null, a buffer of sufficient size // initialized to 0 is passed. - let buff = if data.is_null() { - vec![0u8; expected_byte_length as usize] - } else { - unsafe { - array_buffer_view_to_vec::<u8>(data) - .expect("Can't reach here without being an ArrayBufferView!") - } + let buff = match data { + None => vec![0u8; expected_byte_length as usize], + Some(data) => data, }; if buff.len() != expected_byte_length as usize { - return self.webgl_error(InvalidOperation); + return Ok(self.webgl_error(InvalidOperation)); } self.tex_image_2d(texture, target, data_type, format, - level, width, height, border, buff) + level, width, height, border, buff); + + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -2248,14 +2305,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { internal_format: u32, format: u32, data_type: u32, - source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) { + source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) -> Fallible<()> { // Get pixels from image source let (pixels, size) = match self.get_image_pixels(source) { Ok((pixels, size)) => (pixels, size), - Err(_) => return, + Err(_) => return Ok(()), }; - let validator = TexImage2DValidator::new(self, target, level, internal_format, size.width, size.height, @@ -2272,11 +2328,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { data_type, } = match validator.validate() { Ok(result) => result, - Err(_) => return, // NB: The validator sets the correct error for us. + Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; self.tex_image_2d(texture, target, data_type, format, level, width, height, border, pixels); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -2291,7 +2348,14 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { height: i32, format: u32, data_type: u32, - data: *mut JSObject) { + data_ptr: *mut JSObject) -> Fallible<()> { + let data = if data_ptr.is_null() { + None + } else { + Some(try!(unsafe { fallible_array_buffer_view_to_vec::<u8>(data_ptr) })) + }; + + let validator = TexImage2DValidator::new(self, target, level, format, width, height, 0, format, data_type); @@ -2306,35 +2370,32 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .. } = match validator.validate() { Ok(result) => result, - Err(_) => return, // NB: The validator sets the correct error for us. + Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; let expected_byte_length = match unsafe { self.validate_tex_image_2d_data(width, height, format, data_type, - data) } { + data_ptr) } { Ok(byte_length) => byte_length, - Err(()) => return, + Err(()) => return Ok(()), }; // If data is null, a buffer of sufficient size // initialized to 0 is passed. - let buff = if data.is_null() { - vec![0u8; expected_byte_length as usize] - } else { - unsafe { - array_buffer_view_to_vec::<u8>(data) - .expect("Can't reach here without being an ArrayBufferView!") - } + let buff = match data { + None => vec![0u8; expected_byte_length as usize], + Some(data) => data, }; if expected_byte_length != 0 && buff.len() != expected_byte_length as usize { - return self.webgl_error(InvalidOperation); + return Ok(self.webgl_error(InvalidOperation)); } self.tex_sub_image_2d(texture, target, level, xoffset, yoffset, width, height, format, data_type, buff); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 @@ -2345,10 +2406,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { yoffset: i32, format: u32, data_type: u32, - source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) { + source: Option<ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement>) + -> Fallible<()> { let (pixels, size) = match self.get_image_pixels(source) { Ok((pixels, size)) => (pixels, size), - Err(_) => return, + Err(_) => return Ok(()), }; let validator = TexImage2DValidator::new(self, target, level, format, @@ -2365,11 +2427,12 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { .. } = match validator.validate() { Ok(result) => result, - Err(_) => return, // NB: The validator sets the correct error for us. + Err(_) => return Ok(()), // NB: The validator sets the correct error for us. }; self.tex_sub_image_2d(texture, target, level, xoffset, yoffset, width, height, format, data_type, pixels); + Ok(()) } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 |