diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/document.rs | 2 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 327 | ||||
-rw-r--r-- | components/script/dom/webgltexture.rs | 16 | ||||
-rw-r--r-- | components/script/dom/webidls/WebGLRenderingContext.webidl | 14 |
4 files changed, 255 insertions, 104 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 2aebe049d21..1962e462282 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1055,7 +1055,7 @@ impl Document { key: Key, state: KeyState, modifiers: KeyModifiers, - compositor: &mut IpcSender<ScriptToCompositorMsg>) { + compositor: &IpcSender<ScriptToCompositorMsg>) { let focused = self.get_focused_element(); let body = self.GetBody(); diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 241aa0aa60e..29669c9ff15 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -234,70 +234,32 @@ impl WebGLRenderingContext { true } - fn validate_tex_image_parameters(&self, - target: u32, - level: i32, - internal_format: u32, - width: i32, - height: i32, - border: i32, - format: u32, - data_type: u32) -> bool { - // GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D, - // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - // GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - // GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z. - let texture = match target { - constants::TEXTURE_2D - => self.bound_texture_2d.get(), - constants::TEXTURE_CUBE_MAP_POSITIVE_X | - constants::TEXTURE_CUBE_MAP_NEGATIVE_X | - constants::TEXTURE_CUBE_MAP_POSITIVE_Y | - constants::TEXTURE_CUBE_MAP_NEGATIVE_Y | - constants::TEXTURE_CUBE_MAP_POSITIVE_Z | - constants::TEXTURE_CUBE_MAP_NEGATIVE_Z - => self.bound_texture_cube_map.get(), - _ => { - self.webgl_error(InvalidEnum); - return false; + fn texture_for_target(&self, target: u32) -> Option<Root<WebGLTexture>> { + match target { + constants::TEXTURE_2D => self.bound_texture_2d.get(), + constants::TEXTURE_CUBE_MAP_POSITIVE_X | constants::TEXTURE_CUBE_MAP_NEGATIVE_X | + constants::TEXTURE_CUBE_MAP_POSITIVE_Y | constants::TEXTURE_CUBE_MAP_NEGATIVE_Y | + constants::TEXTURE_CUBE_MAP_POSITIVE_Z | constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => { + self.bound_texture_cube_map.get() }, - }; - - // If an attempt is made to call this function with no - // WebGLTexture bound, an INVALID_OPERATION error is generated. - if texture.is_none() { - self.webgl_error(InvalidOperation); - return false; + _ => None, } + } - // GL_INVALID_ENUM is generated if data_type is not an accepted value. - match data_type { - constants::UNSIGNED_BYTE | - constants::UNSIGNED_SHORT_4_4_4_4 | - constants::UNSIGNED_SHORT_5_5_5_1 | - constants::UNSIGNED_SHORT_5_6_5 => {}, - _ => { - self.webgl_error(InvalidEnum); - return false; - }, - } - - - // TODO(emilio): GL_INVALID_VALUE may be generated if - // level is greater than log_2(max), where max is - // the returned value of GL_MAX_TEXTURE_SIZE when - // target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE - // when target is not GL_TEXTURE_2D. - let is_cubic = target != constants::TEXTURE_2D; - - // GL_INVALID_VALUE is generated if target is one of the - // six cube map 2D image targets and the width and height - // parameters are not equal. - if is_cubic && width != height { - self.webgl_error(InvalidValue); - return false; + fn face_index_for_target(&self, target: u32) -> Option<u8> { + match target { + constants::TEXTURE_2D => Some(0), + constants::TEXTURE_CUBE_MAP_POSITIVE_X => Some(0), + constants::TEXTURE_CUBE_MAP_NEGATIVE_X => Some(1), + constants::TEXTURE_CUBE_MAP_POSITIVE_Y => Some(2), + constants::TEXTURE_CUBE_MAP_NEGATIVE_Y => Some(3), + constants::TEXTURE_CUBE_MAP_POSITIVE_Z => Some(4), + constants::TEXTURE_CUBE_MAP_NEGATIVE_Z => Some(5), + _ => None } + } + fn validate_tex_internal_format(&self, internal_format: u32) -> bool { // GL_INVALID_VALUE is generated if internal_format is not an // accepted format. match internal_format { @@ -306,39 +268,51 @@ impl WebGLRenderingContext { constants::RGB | constants::RGBA | constants::LUMINANCE | - constants::LUMINANCE_ALPHA => {}, + constants::LUMINANCE_ALPHA => true, _ => { self.webgl_error(InvalidValue); - return false; + false }, } + } - // GL_INVALID_OPERATION is generated if format does not - // match internal_format. - if format != internal_format { - self.webgl_error(InvalidOperation); + + fn validate_tex_image_2d_parameters(&self, + target: u32, + level: i32, + internal_format: u32, + width: i32, + height: i32, + border: i32, + format: u32, + data_type: u32) -> bool { + // Validate common tex image parameters + if !self.validate_common_tex_image_parameters(target, level, width, height) { return false; } - // GL_INVALID_VALUE is generated if level is less than 0. - // - // GL_INVALID_VALUE is generated if width or height is less than 0 - // or greater than GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or - // GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D. - // - // TODO(emilio): Check limits - if width < 0 || height < 0 || level < 0 { - self.webgl_error(InvalidValue); + // GL_INVALID_ENUM is generated if data_type is not an accepted value. + match data_type { + constants::UNSIGNED_BYTE | + constants::UNSIGNED_SHORT_4_4_4_4 | + constants::UNSIGNED_SHORT_5_5_5_1 | + constants::UNSIGNED_SHORT_5_6_5 => {}, + _ => { + self.webgl_error(InvalidEnum); + return false; + }, + } + + // Validate internal_format + if !self.validate_tex_internal_format(internal_format) { return false; } - // GL_INVALID_VALUE is generated if level is greater than zero and the - // texture is not power of two. - if level > 0 && - (!(width as u32).is_power_of_two() || - !(height as u32).is_power_of_two()) { - self.webgl_error(InvalidValue); + // GL_INVALID_OPERATION is generated if format does not + // match internal_format. + if format != internal_format { + self.webgl_error(InvalidOperation); return false; } @@ -369,6 +343,82 @@ impl WebGLRenderingContext { true } + fn validate_common_tex_image_parameters(&self, + target: u32, + level: i32, + width: i32, + height: i32) -> bool { + // GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D, + // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + // GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + // GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z. + // + // max_size is GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or + // GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D. + let (texture, max) = match target { + constants::TEXTURE_2D + => (self.bound_texture_2d.get(), self.limits.max_tex_size), + constants::TEXTURE_CUBE_MAP_POSITIVE_X | + constants::TEXTURE_CUBE_MAP_NEGATIVE_X | + constants::TEXTURE_CUBE_MAP_POSITIVE_Y | + constants::TEXTURE_CUBE_MAP_NEGATIVE_Y | + constants::TEXTURE_CUBE_MAP_POSITIVE_Z | + constants::TEXTURE_CUBE_MAP_NEGATIVE_Z + => (self.bound_texture_cube_map.get(), self.limits.max_cube_map_tex_size), + _ => { + self.webgl_error(InvalidEnum); + return false; + }, + }; + + // If an attempt is made to call this function with no + // WebGLTexture bound, an INVALID_OPERATION error is generated. + if texture.is_none() { + self.webgl_error(InvalidOperation); + return false; + } + + let is_cubic = target != constants::TEXTURE_2D; + + // GL_INVALID_VALUE is generated if target is one of the + // six cube map 2D image targets and the width and height + // parameters are not equal. + if is_cubic && width != height { + self.webgl_error(InvalidValue); + return false; + } + + // GL_INVALID_VALUE is generated if level is less than 0. + // + // GL_INVALID_VALUE is generated if width or height is less than 0 + if width < 0 || height < 0 || level < 0 || + width as u32 > max || height as u32 > max { + self.webgl_error(InvalidValue); + return false; + } + + // GL_INVALID_VALUE may be generated if + // level is greater than log_2(max), where max is + // the returned value of GL_MAX_TEXTURE_SIZE when + // target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE + // when target is not GL_TEXTURE_2D. + if level > (max as f32).log2() as i32 { + self.webgl_error(InvalidValue); + return false; + } + + // GL_INVALID_VALUE is generated if level is greater than zero and the + // texture is not power of two. + if level > 0 && + (!(width as u32).is_power_of_two() || + !(height as u32).is_power_of_two()) { + self.webgl_error(InvalidValue); + return false; + } + + true + } + fn tex_image_2d(&self, target: u32, level: i32, @@ -380,11 +430,11 @@ impl WebGLRenderingContext { data_type: u32, pixels: Vec<u8>) { // NB: pixels should NOT be premultipied // This should be validated before reaching this function - debug_assert!(self.validate_tex_image_parameters(target, level, - internal_format, - width, height, - border, format, - data_type)); + debug_assert!(self.validate_tex_image_2d_parameters(target, level, + internal_format, + width, height, + border, format, + data_type)); let slot = match target { constants::TEXTURE_2D @@ -791,6 +841,88 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { self.webgl_error(InvalidEnum) } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + fn CopyTexImage2D(&self, target: u32, level: i32, internal_format: u32, + x: i32, y: i32, width: i32, height: i32, border: i32) { + // Validate common tex image parameters + if !self.validate_common_tex_image_parameters(target, level, width, height) || + !self.validate_tex_internal_format(internal_format) { + return; + } + + // GL_INVALID_VALUE is generated if the border is not 0 + if border != 0 { + self.webgl_error(InvalidValue); + return; + } + + let texture = self.texture_for_target(target).unwrap(); + let face_index = self.face_index_for_target(target).unwrap(); + + // We have already validated level + let image_info = texture.image_info_at_face(face_index, level as u32); + + // The color buffer components can be dropped during the conversion to the + // internal_format, but new components cannot be added + let invalid_format = match image_info.internal_format() { + Some(src_format) => match (src_format, internal_format) { + (constants::ALPHA, constants::ALPHA) | (constants::RGB, constants::RGB) | + (constants::RGB, constants::LUMINANCE) | (constants::RGBA, _) => false, + _ => true, + }, + None => false, + }; + + // GL_INVALID_OPERATION is generated if the color buffer cannot be + // converted to the internal_format + if invalid_format { + self.webgl_error(InvalidOperation); + return; + } + + // TexImage2D depth is always equal to 1 + handle_potential_webgl_error!(self, texture.initialize(target, + width as u32, + height as u32, 1, + internal_format, + level as u32)); + + let msg = WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y, + width, height, border); + + self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap() + } + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + fn CopyTexSubImage2D(&self, target: u32, level: i32, xoffset: i32, yoffset: i32, + x: i32, y: i32, width: i32, height: i32) { + // Validate common tex image parameters + if !self.validate_common_tex_image_parameters(target, level, width, height) { + return; + } + + let texture = self.texture_for_target(target).unwrap(); + let face_index = self.face_index_for_target(target).unwrap(); + + // We have already validated level + let image_info = texture.image_info_at_face(face_index, level as u32); + + // GL_INVALID_VALUE is generated if: + // - xoffset or yoffset is less than 0 + // - x offset plus the width is greater than the texture width + // - y offset plus the height is greater than the texture height + if xoffset < 0 || ((xoffset + width) as u32) > image_info.width() || + yoffset < 0 || ((yoffset + height) as u32) > image_info.height() { + self.webgl_error(InvalidValue); + return; + } + + let msg = WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset, + x, y, width, height); + + self.ipc_renderer.send(CanvasMsg::WebGL(msg)).unwrap(); + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.11 fn Clear(&self, mask: u32) { self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::Clear(mask))).unwrap(); @@ -1306,6 +1438,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.3 + fn SampleCoverage(&self, value: f32, invert: bool) { + self.ipc_renderer.send(CanvasMsg::WebGL(WebGLCommand::SampleCoverage(value, invert))).unwrap(); + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.4 fn Scissor(&self, x: i32, y: i32, width: i32, height: i32) { self.ipc_renderer @@ -1738,13 +1875,13 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { format: u32, data_type: u32, data: Option<*mut JSObject>) { - if !self.validate_tex_image_parameters(target, - level, - internal_format, - width, height, - border, - format, - data_type) { + if !self.validate_tex_image_2d_parameters(target, + level, + internal_format, + width, height, + border, + format, + data_type) { return; // Error handled in validate() } @@ -1883,9 +2020,9 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { }; // NB: Border must be zero - if !self.validate_tex_image_parameters(target, level, internal_format, - size.width, size.height, 0, - format, data_type) { + if !self.validate_tex_image_2d_parameters(target, level, internal_format, + size.width, size.height, 0, + format, data_type) { return; // Error handled in validate() } diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index df636a1db59..ccd05182968 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -309,7 +309,7 @@ impl WebGLTexture { true } - fn image_info_at_face(&self, face: u8, level: u32) -> ImageInfo { + pub fn image_info_at_face(&self, face: u8, level: u32) -> ImageInfo { let pos = (level * self.face_count.get() as u32) + face as u32; self.image_info_array.borrow()[pos as usize] } @@ -340,7 +340,7 @@ impl Drop for WebGLTexture { } #[derive(Clone, Copy, PartialEq, Debug, JSTraceable, HeapSizeOf)] -struct ImageInfo { +pub struct ImageInfo { width: u32, height: u32, depth: u32, @@ -359,6 +359,18 @@ impl ImageInfo { } } + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } + + pub fn internal_format(&self) -> Option<u32> { + self.internal_format + } + fn is_power_of_two(&self) -> bool { self.width.is_power_of_two() && self.height.is_power_of_two() && self.depth.is_power_of_two() } diff --git a/components/script/dom/webidls/WebGLRenderingContext.webidl b/components/script/dom/webidls/WebGLRenderingContext.webidl index 76ff64a1261..b534c2aeb61 100644 --- a/components/script/dom/webidls/WebGLRenderingContext.webidl +++ b/components/script/dom/webidls/WebGLRenderingContext.webidl @@ -523,11 +523,13 @@ interface WebGLRenderingContextBase GLsizei width, GLsizei height, GLenum format, object data); - //void copyTexImage2D(GLenum target, GLint level, GLenum internalformat, - // GLint x, GLint y, GLsizei width, GLsizei height, - // GLint border); - //void copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, - // GLint x, GLint y, GLsizei width, GLsizei height); + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + void copyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border); + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + void copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height); WebGLBuffer? createBuffer(); WebGLFramebuffer? createFramebuffer(); @@ -619,7 +621,7 @@ interface WebGLRenderingContextBase //void renderbufferStorage(GLenum target, GLenum internalformat, // GLsizei width, GLsizei height); - //void sampleCoverage(GLclampf value, GLboolean invert); + void sampleCoverage(GLclampf value, GLboolean invert); void scissor(GLint x, GLint y, GLsizei width, GLsizei height); void shaderSource(WebGLShader? shader, DOMString source); |