diff options
Diffstat (limited to 'components')
19 files changed, 746 insertions, 48 deletions
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index 175a061cbf4..cec8cc929d6 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -1168,6 +1168,43 @@ impl WebGLImpl { &pixels, ); }, + WebGLCommand::CompressedTexImage2D { + target, + level, + internal_format, + size, + ref data, + } => { + ctx.gl().compressed_tex_image_2d( + target, + level as i32, + internal_format, + size.width as i32, + size.height as i32, + 0, + &*data, + ); + }, + WebGLCommand::CompressedTexSubImage2D { + target, + level, + xoffset, + yoffset, + size, + format, + ref data, + } => { + ctx.gl().compressed_tex_sub_image_2d( + target, + level as i32, + xoffset as i32, + yoffset as i32, + size.width as i32, + size.height as i32, + format, + &*data, + ); + }, WebGLCommand::DrawingBufferWidth(ref sender) => sender .send(ctx.borrow_draw_buffer().unwrap().size().width) .unwrap(), diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index af88ca905aa..a36e8d0e659 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -331,6 +331,22 @@ pub enum WebGLCommand { pixel_format: Option<PixelFormat>, data: TruncatedDebug<IpcSharedMemory>, }, + CompressedTexImage2D { + target: u32, + level: u32, + internal_format: u32, + size: Size2D<u32>, + data: TruncatedDebug<IpcSharedMemory>, + }, + CompressedTexSubImage2D { + target: u32, + level: i32, + xoffset: i32, + yoffset: i32, + size: Size2D<u32>, + format: u32, + data: TruncatedDebug<IpcSharedMemory>, + }, DrawingBufferWidth(WebGLSender<i32>), DrawingBufferHeight(WebGLSender<i32>), Finish(WebGLSender<()>), @@ -740,6 +756,25 @@ macro_rules! gl_enums { } } +// FIXME: These should come from gleam +mod gl_ext_constants { + use gleam::gl::types::GLenum; + + pub const COMPRESSED_RGB_S3TC_DXT1_EXT: GLenum = 0x83F0; + pub const COMPRESSED_RGBA_S3TC_DXT1_EXT: GLenum = 0x83F1; + pub const COMPRESSED_RGBA_S3TC_DXT3_EXT: GLenum = 0x83F2; + pub const COMPRESSED_RGBA_S3TC_DXT5_EXT: GLenum = 0x83F3; + pub const COMPRESSED_RGB_ETC1_WEBGL: GLenum = 0x8D64; + + pub static COMPRESSIONS: &'static [GLenum] = &[ + COMPRESSED_RGB_S3TC_DXT1_EXT, + COMPRESSED_RGBA_S3TC_DXT1_EXT, + COMPRESSED_RGBA_S3TC_DXT3_EXT, + COMPRESSED_RGBA_S3TC_DXT5_EXT, + COMPRESSED_RGB_ETC1_WEBGL, + ]; +} + gl_enums! { pub enum TexFormat { DepthComponent = gl::DEPTH_COMPONENT, @@ -748,6 +783,11 @@ gl_enums! { RGBA = gl::RGBA, Luminance = gl::LUMINANCE, LuminanceAlpha = gl::LUMINANCE_ALPHA, + CompressedRgbS3tcDxt1 = gl_ext_constants::COMPRESSED_RGB_S3TC_DXT1_EXT, + CompressedRgbaS3tcDxt1 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT1_EXT, + CompressedRgbaS3tcDxt3 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT3_EXT, + CompressedRgbaS3tcDxt5 = gl_ext_constants::COMPRESSED_RGBA_S3TC_DXT5_EXT, + CompressedRgbEtc1 = gl_ext_constants::COMPRESSED_RGB_ETC1_WEBGL, } pub enum TexDataType { @@ -771,8 +811,14 @@ impl TexFormat { TexFormat::LuminanceAlpha => 2, TexFormat::RGB => 3, TexFormat::RGBA => 4, + _ => 1, } } + + /// Returns whether this format is a known texture compression format. + pub fn is_compressed(&self) -> bool { + gl_ext_constants::COMPRESSIONS.contains(&self.as_gl_constant()) + } } impl TexDataType { diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml index b57c70ac0c9..085349f3f23 100644 --- a/components/gfx/Cargo.toml +++ b/components/gfx/Cargo.toml @@ -60,7 +60,7 @@ servo_allocator = {path = "../allocator"} servo-fontconfig = "0.2.1" [target.'cfg(target_os = "android")'.dependencies] -xml5ever = {version = "0.12"} +xml5ever = {version = "0.14"} [target.'cfg(target_os = "windows")'.dependencies] dwrote = "0.8" diff --git a/components/layout/Cargo.toml b/components/layout/Cargo.toml index 247a4623a43..abbd43b3e64 100644 --- a/components/layout/Cargo.toml +++ b/components/layout/Cargo.toml @@ -24,7 +24,7 @@ fnv = "1.0" fxhash = "0.2" gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} -html5ever = "0.22" +html5ever = "0.23" ipc-channel = "0.11" libc = "0.2" log = "0.4" diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml index 4c1f53ec48c..b042ed7b62c 100644 --- a/components/layout_thread/Cargo.toml +++ b/components/layout_thread/Cargo.toml @@ -24,7 +24,7 @@ fxhash = "0.2" gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} histogram = "0.6.8" -html5ever = "0.22" +html5ever = "0.23" ipc-channel = "0.11" layout = {path = "../layout"} layout_traits = {path = "../layout_traits"} diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml index 609a977b1dd..bd351649b5b 100644 --- a/components/malloc_size_of/Cargo.toml +++ b/components/malloc_size_of/Cargo.toml @@ -43,5 +43,5 @@ thin-slice = "0.1.0" time = { version = "0.1.17", optional = true } url = { version = "1.2", optional = true } webrender_api = { git = "https://github.com/servo/webrender", features = ["ipc"], optional = true } -xml5ever = { version = "0.12", optional = true } +xml5ever = { version = "0.14", optional = true } void = "1.0.2" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index a9ef147da99..8dcf5bf0e14 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -56,7 +56,7 @@ fnv = "1.0" gleam = "0.6" headers-core = "0.0.1" headers-ext = "0.0.3" -html5ever = "0.22" +html5ever = "0.23" http = "0.1" hyper = "0.12" hyper_serde = "0.9" @@ -110,7 +110,7 @@ unicode-segmentation = "1.1.0" url = "1.6" utf-8 = "0.7" uuid = {version = "0.7", features = ["v4"]} -xml5ever = {version = "0.12"} +xml5ever = {version = "0.14"} webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs index 2d9c8ac51ec..8f30e54174d 100644 --- a/components/script/dom/servoparser/xml.rs +++ b/components/script/dom/servoparser/xml.rs @@ -40,18 +40,9 @@ impl Tokenizer { } pub fn feed(&mut self, input: &mut BufferQueue) -> Result<(), DomRoot<HTMLScriptElement>> { - if !input.is_empty() { - while let Some(chunk) = input.pop_front() { - self.inner.feed(chunk); - if let Some(script) = self.inner.sink.sink.script.take() { - return Err(script); - } - } - } else { - self.inner.run(); - if let Some(script) = self.inner.sink.sink.script.take() { - return Err(script); - } + self.inner.run(input); + if let Some(script) = self.inner.sink.sink.script.take() { + return Err(script); } Ok(()) } diff --git a/components/script/dom/webgl_extensions/ext/mod.rs b/components/script/dom/webgl_extensions/ext/mod.rs index 888e977c68e..ccb768cc04f 100644 --- a/components/script/dom/webgl_extensions/ext/mod.rs +++ b/components/script/dom/webgl_extensions/ext/mod.rs @@ -18,3 +18,5 @@ pub mod oestexturehalffloat; pub mod oestexturehalffloatlinear; pub mod oesvertexarrayobject; pub mod webglcolorbufferfloat; +pub mod webglcompressedtextureetc1; +pub mod webglcompressedtextures3tc; diff --git a/components/script/dom/webgl_extensions/ext/webglcompressedtextureetc1.rs b/components/script/dom/webgl_extensions/ext/webglcompressedtextureetc1.rs new file mode 100644 index 00000000000..29805fd4bdd --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/webglcompressedtextureetc1.rs @@ -0,0 +1,58 @@ +/* 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/. */ + +use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions}; +use crate::dom::bindings::codegen::Bindings::WEBGLCompressedTextureETC1Binding; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::webgltexture::{TexCompression, TexCompressionValidation}; +use canvas_traits::webgl::{TexFormat, WebGLVersion}; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct WEBGLCompressedTextureETC1 { + reflector_: Reflector, +} + +impl WEBGLCompressedTextureETC1 { + fn new_inherited() -> WEBGLCompressedTextureETC1 { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for WEBGLCompressedTextureETC1 { + type Extension = WEBGLCompressedTextureETC1; + fn new(ctx: &WebGLRenderingContext) -> DomRoot<WEBGLCompressedTextureETC1> { + reflect_dom_object( + Box::new(WEBGLCompressedTextureETC1::new_inherited()), + &*ctx.global(), + WEBGLCompressedTextureETC1Binding::Wrap, + ) + } + + fn spec() -> WebGLExtensionSpec { + WebGLExtensionSpec::Specific(WebGLVersion::WebGL1) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_gl_extension("GL_OES_compressed_ETC1_RGB8_texture") + } + + fn enable(ext: &WebGLExtensions) { + ext.add_tex_compression_formats(&[TexCompression { + format: TexFormat::CompressedRgbEtc1, + bytes_per_block: 8, + block_width: 4, + block_height: 4, + validation: TexCompressionValidation::None, + }]); + } + + fn name() -> &'static str { + "WEBGL_compressed_texture_etc1" + } +} diff --git a/components/script/dom/webgl_extensions/ext/webglcompressedtextures3tc.rs b/components/script/dom/webgl_extensions/ext/webglcompressedtextures3tc.rs new file mode 100644 index 00000000000..0e4385abd6b --- /dev/null +++ b/components/script/dom/webgl_extensions/ext/webglcompressedtextures3tc.rs @@ -0,0 +1,86 @@ +/* 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/. */ + +use super::{WebGLExtension, WebGLExtensionSpec, WebGLExtensions}; +use crate::dom::bindings::codegen::Bindings::WEBGLCompressedTextureS3TCBinding; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::webgltexture::{TexCompression, TexCompressionValidation}; +use canvas_traits::webgl::{TexFormat, WebGLVersion}; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct WEBGLCompressedTextureS3TC { + reflector_: Reflector, +} + +impl WEBGLCompressedTextureS3TC { + fn new_inherited() -> WEBGLCompressedTextureS3TC { + Self { + reflector_: Reflector::new(), + } + } +} + +impl WebGLExtension for WEBGLCompressedTextureS3TC { + type Extension = WEBGLCompressedTextureS3TC; + fn new(ctx: &WebGLRenderingContext) -> DomRoot<WEBGLCompressedTextureS3TC> { + reflect_dom_object( + Box::new(WEBGLCompressedTextureS3TC::new_inherited()), + &*ctx.global(), + WEBGLCompressedTextureS3TCBinding::Wrap, + ) + } + + fn spec() -> WebGLExtensionSpec { + WebGLExtensionSpec::Specific(WebGLVersion::WebGL1) + } + + fn is_supported(ext: &WebGLExtensions) -> bool { + ext.supports_gl_extension("GL_EXT_texture_compression_s3tc") || + ext.supports_all_gl_extension(&[ + "GL_EXT_texture_compression_dxt1", + "GL_ANGLE_texture_compression_dxt3", + "GL_ANGLE_texture_compression_dxt5", + ]) + } + + fn enable(ext: &WebGLExtensions) { + ext.add_tex_compression_formats(&[ + TexCompression { + format: TexFormat::CompressedRgbS3tcDxt1, + bytes_per_block: 8, + block_width: 4, + block_height: 4, + validation: TexCompressionValidation::S3TC, + }, + TexCompression { + format: TexFormat::CompressedRgbaS3tcDxt1, + bytes_per_block: 8, + block_width: 4, + block_height: 4, + validation: TexCompressionValidation::S3TC, + }, + TexCompression { + format: TexFormat::CompressedRgbaS3tcDxt3, + bytes_per_block: 16, + block_width: 4, + block_height: 4, + validation: TexCompressionValidation::S3TC, + }, + TexCompression { + format: TexFormat::CompressedRgbaS3tcDxt5, + bytes_per_block: 16, + block_width: 4, + block_height: 4, + validation: TexCompressionValidation::S3TC, + }, + ]); + } + + fn name() -> &'static str { + "WEBGL_compressed_texture_s3tc" + } +} diff --git a/components/script/dom/webgl_extensions/extensions.rs b/components/script/dom/webgl_extensions/extensions.rs index aa6d128ae89..e71fcf7dac5 100644 --- a/components/script/dom/webgl_extensions/extensions.rs +++ b/components/script/dom/webgl_extensions/extensions.rs @@ -17,6 +17,7 @@ use crate::dom::oestexturefloat::OESTextureFloat; use crate::dom::oestexturehalffloat::OESTextureHalfFloat; use crate::dom::webglcolorbufferfloat::WEBGLColorBufferFloat; use crate::dom::webglrenderingcontext::WebGLRenderingContext; +use crate::dom::webgltexture::TexCompression; use canvas_traits::webgl::WebGLVersion; use fnv::{FnvHashMap, FnvHashSet}; use gleam::gl::{self, GLenum}; @@ -82,6 +83,8 @@ struct WebGLExtensionFeatures { element_index_uint_enabled: bool, /// WebGL EXT_blend_minmax extension. blend_minmax_enabled: bool, + /// WebGL supported texture compression formats enabled by extensions. + tex_compression_formats: FnvHashMap<GLenum, TexCompression>, } impl WebGLExtensionFeatures { @@ -131,6 +134,7 @@ impl WebGLExtensionFeatures { disabled_get_vertex_attrib_names, element_index_uint_enabled, blend_minmax_enabled, + tex_compression_formats: Default::default(), } } } @@ -225,6 +229,13 @@ impl WebGLExtensions { .any(|name| features.gl_extensions.contains(*name)) } + pub fn supports_all_gl_extension(&self, names: &[&str]) -> bool { + let features = self.features.borrow(); + names + .iter() + .all(|name| features.gl_extensions.contains(*name)) + } + pub fn enable_tex_type(&self, data_type: GLenum) { self.features .borrow_mut() @@ -335,6 +346,35 @@ impl WebGLExtensions { .contains(&name) } + pub fn add_tex_compression_formats(&self, formats: &[TexCompression]) { + let formats: FnvHashMap<GLenum, TexCompression> = formats + .iter() + .map(|&compression| (compression.format.as_gl_constant(), compression)) + .collect(); + + self.features + .borrow_mut() + .tex_compression_formats + .extend(formats.iter()); + } + + pub fn get_tex_compression_format(&self, format_id: GLenum) -> Option<TexCompression> { + self.features + .borrow() + .tex_compression_formats + .get(&format_id) + .cloned() + } + + pub fn get_tex_compression_ids(&self) -> Vec<GLenum> { + self.features + .borrow() + .tex_compression_formats + .keys() + .map(|&k| k) + .collect() + } + fn register_all_extensions(&self) { self.register::<ext::angleinstancedarrays::ANGLEInstancedArrays>(); self.register::<ext::extblendminmax::EXTBlendMinmax>(); @@ -349,6 +389,8 @@ impl WebGLExtensions { self.register::<ext::oestexturehalffloatlinear::OESTextureHalfFloatLinear>(); self.register::<ext::oesvertexarrayobject::OESVertexArrayObject>(); self.register::<ext::webglcolorbufferfloat::WEBGLColorBufferFloat>(); + self.register::<ext::webglcompressedtextureetc1::WEBGLCompressedTextureETC1>(); + self.register::<ext::webglcompressedtextures3tc::WEBGLCompressedTextureS3TC>(); } pub fn enable_element_index_uint(&self) { diff --git a/components/script/dom/webgl_validations/tex_image_2d.rs b/components/script/dom/webgl_validations/tex_image_2d.rs index d9bce435234..329ffd10349 100644 --- a/components/script/dom/webgl_validations/tex_image_2d.rs +++ b/components/script/dom/webgl_validations/tex_image_2d.rs @@ -6,7 +6,8 @@ use super::types::TexImageTarget; use super::WebGLValidator; use crate::dom::bindings::root::DomRoot; use crate::dom::webglrenderingcontext::WebGLRenderingContext; -use crate::dom::webgltexture::WebGLTexture; +use crate::dom::webgltexture::{ImageInfo, WebGLTexture}; +use crate::dom::webgltexture::{TexCompression, TexCompressionValidation}; use canvas_traits::webgl::{TexDataType, TexFormat, WebGLError::*}; use std::{self, fmt}; @@ -40,6 +41,10 @@ pub enum TexImageValidationError { InvalidBorder, /// Expected a power of two texture. NonPotTexture, + /// Unrecognized texture compression format. + InvalidCompressionFormat, + /// Invalid X/Y texture offset parameters. + InvalidOffsets, } impl std::error::Error for TexImageValidationError { @@ -61,6 +66,8 @@ impl std::error::Error for TexImageValidationError { InvalidTypeForFormat => "Invalid type for the given format", InvalidBorder => "Invalid border", NonPotTexture => "Expected a power of two texture", + InvalidCompressionFormat => "Unrecognized texture compression format", + InvalidOffsets => "Invalid X/Y texture offset parameters", } } } @@ -357,3 +364,303 @@ impl<'a> WebGLValidator for TexImage2DValidator<'a> { }) } } + +pub struct CommonCompressedTexImage2DValidator<'a> { + common_validator: CommonTexImage2DValidator<'a>, + data_len: usize, +} + +impl<'a> CommonCompressedTexImage2DValidator<'a> { + pub fn new( + context: &'a WebGLRenderingContext, + target: u32, + level: i32, + width: i32, + height: i32, + border: i32, + compression_format: u32, + data_len: usize, + ) -> Self { + CommonCompressedTexImage2DValidator { + common_validator: CommonTexImage2DValidator::new( + context, + target, + level, + compression_format, + width, + height, + border, + ), + data_len, + } + } +} + +pub struct CommonCompressedTexImage2DValidatorResult { + pub texture: DomRoot<WebGLTexture>, + pub target: TexImageTarget, + pub level: u32, + pub width: u32, + pub height: u32, + pub compression: TexCompression, +} + +fn valid_s3tc_dimension(level: u32, side_length: u32, block_size: u32) -> bool { + (side_length % block_size == 0) || (level > 0 && [0, 1, 2].contains(&side_length)) +} + +fn valid_compressed_data_len( + data_len: usize, + width: u32, + height: u32, + compression: &TexCompression, +) -> bool { + let block_width = compression.block_width as u32; + let block_height = compression.block_height as u32; + + let required_blocks_hor = (width + block_width - 1) / block_width; + let required_blocks_ver = (height + block_height - 1) / block_height; + let required_blocks = required_blocks_hor * required_blocks_ver; + + let required_bytes = required_blocks * compression.bytes_per_block as u32; + data_len == required_bytes as usize +} + +fn is_subimage_blockaligned( + xoffset: u32, + yoffset: u32, + width: u32, + height: u32, + compression: &TexCompression, + tex_info: &ImageInfo, +) -> bool { + let block_width = compression.block_width as u32; + let block_height = compression.block_height as u32; + + (xoffset % block_width == 0 && yoffset % block_height == 0) && + (width % block_width == 0 || xoffset + width == tex_info.width()) && + (height % block_height == 0 || yoffset + height == tex_info.height()) +} + +impl<'a> WebGLValidator for CommonCompressedTexImage2DValidator<'a> { + type Error = TexImageValidationError; + type ValidatedOutput = CommonCompressedTexImage2DValidatorResult; + + fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> { + let context = self.common_validator.context; + let CommonTexImage2DValidatorResult { + texture, + target, + level, + internal_format, + width, + height, + border: _, + } = self.common_validator.validate()?; + + // GL_INVALID_ENUM is generated if internalformat is not a supported + // format returned in GL_COMPRESSED_TEXTURE_FORMATS. + let compression = context + .extension_manager() + .get_tex_compression_format(internal_format.as_gl_constant()); + let compression = match compression { + Some(compression) => compression, + None => { + context.webgl_error(InvalidEnum); + return Err(TexImageValidationError::InvalidCompressionFormat); + }, + }; + + // GL_INVALID_VALUE is generated if imageSize is not consistent with the + // format, dimensions, and contents of the specified compressed image data. + if !valid_compressed_data_len(self.data_len, width, height, &compression) { + context.webgl_error(InvalidValue); + return Err(TexImageValidationError::TextureFormatMismatch); + } + + Ok(CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + }) + } +} + +pub struct CompressedTexImage2DValidator<'a> { + compression_validator: CommonCompressedTexImage2DValidator<'a>, +} + +impl<'a> CompressedTexImage2DValidator<'a> { + pub fn new( + context: &'a WebGLRenderingContext, + target: u32, + level: i32, + width: i32, + height: i32, + border: i32, + compression_format: u32, + data_len: usize, + ) -> Self { + CompressedTexImage2DValidator { + compression_validator: CommonCompressedTexImage2DValidator::new( + context, + target, + level, + width, + height, + border, + compression_format, + data_len, + ), + } + } +} + +impl<'a> WebGLValidator for CompressedTexImage2DValidator<'a> { + type Error = TexImageValidationError; + type ValidatedOutput = CommonCompressedTexImage2DValidatorResult; + + fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> { + let context = self.compression_validator.common_validator.context; + let CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + } = self.compression_validator.validate()?; + + // GL_INVALID_OPERATION is generated if parameter combinations are not + // supported by the specific compressed internal format as specified + // in the specific texture compression extension. + let compression_valid = match compression.validation { + TexCompressionValidation::S3TC => { + let valid_width = + valid_s3tc_dimension(level, width, compression.block_width as u32); + let valid_height = + valid_s3tc_dimension(level, height, compression.block_height as u32); + valid_width && valid_height + }, + TexCompressionValidation::None => true, + }; + if !compression_valid { + context.webgl_error(InvalidOperation); + return Err(TexImageValidationError::TextureFormatMismatch); + } + + Ok(CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + }) + } +} + +pub struct CompressedTexSubImage2DValidator<'a> { + compression_validator: CommonCompressedTexImage2DValidator<'a>, + xoffset: i32, + yoffset: i32, +} + +impl<'a> CompressedTexSubImage2DValidator<'a> { + pub fn new( + context: &'a WebGLRenderingContext, + target: u32, + level: i32, + xoffset: i32, + yoffset: i32, + width: i32, + height: i32, + compression_format: u32, + data_len: usize, + ) -> Self { + CompressedTexSubImage2DValidator { + compression_validator: CommonCompressedTexImage2DValidator::new( + context, + target, + level, + width, + height, + 0, + compression_format, + data_len, + ), + xoffset, + yoffset, + } + } +} + +impl<'a> WebGLValidator for CompressedTexSubImage2DValidator<'a> { + type Error = TexImageValidationError; + type ValidatedOutput = CommonCompressedTexImage2DValidatorResult; + + fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> { + let context = self.compression_validator.common_validator.context; + let CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + } = self.compression_validator.validate()?; + + let tex_info = texture.image_info_for_target(&target, level); + + // 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 self.xoffset < 0 || + (self.xoffset as u32 + width) > tex_info.width() || + self.yoffset < 0 || + (self.yoffset as u32 + height) > tex_info.height() + { + context.webgl_error(InvalidValue); + return Err(TexImageValidationError::InvalidOffsets); + } + + // GL_INVALID_OPERATION is generated if format does not match + // internal_format. + if compression.format != tex_info.internal_format().unwrap() { + context.webgl_error(InvalidOperation); + return Err(TexImageValidationError::TextureFormatMismatch); + } + + // GL_INVALID_OPERATION is generated if parameter combinations are not + // supported by the specific compressed internal format as specified + // in the specific texture compression extension. + let compression_valid = match compression.validation { + TexCompressionValidation::S3TC => is_subimage_blockaligned( + self.xoffset as u32, + self.yoffset as u32, + width, + height, + &compression, + &tex_info, + ), + TexCompressionValidation::None => true, + }; + if !compression_valid { + context.webgl_error(InvalidOperation); + return Err(TexImageValidationError::TextureFormatMismatch); + } + + Ok(CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + }) + } +} diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 3100fbf942d..0ccc2a53825 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -26,9 +26,10 @@ use crate::dom::htmliframeelement::HTMLIFrameElement; use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage}; use crate::dom::webgl_extensions::WebGLExtensions; use crate::dom::webgl_validations::tex_image_2d::{ - CommonTexImage2DValidator, CommonTexImage2DValidatorResult, + CommonCompressedTexImage2DValidatorResult, CommonTexImage2DValidator, + CommonTexImage2DValidatorResult, CompressedTexImage2DValidator, + CompressedTexSubImage2DValidator, TexImage2DValidator, TexImage2DValidatorResult, }; -use crate::dom::webgl_validations::tex_image_2d::{TexImage2DValidator, TexImage2DValidatorResult}; use crate::dom::webgl_validations::types::TexImageTarget; use crate::dom::webgl_validations::WebGLValidator; use crate::dom::webglactiveinfo::WebGLActiveInfo; @@ -1227,9 +1228,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return Int32Value(constants::UNSIGNED_BYTE as i32); }, constants::COMPRESSED_TEXTURE_FORMATS => { - // FIXME(nox): https://github.com/servo/servo/issues/20594 + let format_ids = self.extension_manager.get_tex_compression_ids(); + rooted!(in(cx) let mut rval = ptr::null_mut::<JSObject>()); - let _ = Uint32Array::create(cx, CreateWith::Slice(&[]), rval.handle_mut()).unwrap(); + let _ = Uint32Array::create(cx, CreateWith::Slice(&format_ids), rval.handle_mut()) + .unwrap(); return ObjectValue(rval.get()); }, constants::VERSION => { @@ -1756,36 +1759,116 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + #[allow(unsafe_code)] fn CompressedTexImage2D( &self, - _target: u32, - _level: i32, - _internal_format: u32, - _width: i32, - _height: i32, - _border: i32, - _data: CustomAutoRooterGuard<ArrayBufferView>, + target: u32, + level: i32, + internal_format: u32, + width: i32, + height: i32, + border: i32, + data: CustomAutoRooterGuard<ArrayBufferView>, ) { - // 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); + let validator = CompressedTexImage2DValidator::new( + self, + target, + level, + width, + height, + border, + internal_format, + data.len(), + ); + let CommonCompressedTexImage2DValidatorResult { + texture, + target, + level, + width, + height, + compression, + } = match validator.validate() { + Ok(result) => result, + Err(_) => return, + }; + + let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() }); + let pixels = TexPixels::from_array(buff, Size2D::new(width, height)); + + handle_potential_webgl_error!( + self, + texture.initialize( + target, + pixels.size.width, + pixels.size.height, + 1, + compression.format, + level, + Some(TexDataType::UnsignedByte) + ) + ); + + self.send_command(WebGLCommand::CompressedTexImage2D { + target: target.as_gl_constant(), + level, + internal_format, + size: Size2D::new(width, height), + data: pixels.data.into(), + }); + + if let Some(fb) = self.bound_framebuffer.get() { + fb.invalidate_texture(&*texture); + } } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 + #[allow(unsafe_code)] fn CompressedTexSubImage2D( &self, - _target: u32, - _level: i32, - _xoffset: i32, - _yoffset: i32, - _width: i32, - _height: i32, - _format: u32, - _data: CustomAutoRooterGuard<ArrayBufferView>, + target: u32, + level: i32, + xoffset: i32, + yoffset: i32, + width: i32, + height: i32, + format: u32, + data: CustomAutoRooterGuard<ArrayBufferView>, ) { - // 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); + let validator = CompressedTexSubImage2DValidator::new( + self, + target, + level, + xoffset, + yoffset, + width, + height, + format, + data.len(), + ); + let CommonCompressedTexImage2DValidatorResult { + texture: _, + target, + level, + width, + height, + .. + } = match validator.validate() { + Ok(result) => result, + Err(_) => return, + }; + + let buff = IpcSharedMemory::from_bytes(unsafe { data.as_slice() }); + let pixels = TexPixels::from_array(buff, Size2D::new(width, height)); + + self.send_command(WebGLCommand::CompressedTexSubImage2D { + target: target.as_gl_constant(), + level: level as i32, + xoffset, + yoffset, + size: Size2D::new(width, height), + format, + data: pixels.data.into(), + }); } // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.8 diff --git a/components/script/dom/webgltexture.rs b/components/script/dom/webgltexture.rs index 261edbe67be..8982e4bca0c 100644 --- a/components/script/dom/webgltexture.rs +++ b/components/script/dom/webgltexture.rs @@ -470,7 +470,24 @@ impl ImageInfo { } fn is_compressed_format(&self) -> bool { - // TODO: Once Servo supports compressed formats, check for them here - false + match self.internal_format { + Some(format) => format.is_compressed(), + None => false, + } } } + +#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)] +pub enum TexCompressionValidation { + None, + S3TC, +} + +#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf)] +pub struct TexCompression { + pub format: TexFormat, + pub bytes_per_block: u8, + pub block_width: u8, + pub block_height: u8, + pub validation: TexCompressionValidation, +} diff --git a/components/script/dom/webidls/WEBGLCompressedTextureETC1.webidl b/components/script/dom/webidls/WEBGLCompressedTextureETC1.webidl new file mode 100644 index 00000000000..c8ba921764d --- /dev/null +++ b/components/script/dom/webidls/WEBGLCompressedTextureETC1.webidl @@ -0,0 +1,13 @@ +/* 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/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_etc1/ + */ + +[NoInterfaceObject] +interface WEBGLCompressedTextureETC1 { + /* Compressed Texture Format */ + const GLenum COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; +}; // interface WEBGLCompressedTextureETC1 diff --git a/components/script/dom/webidls/WEBGLCompressedTextureS3TC.webidl b/components/script/dom/webidls/WEBGLCompressedTextureS3TC.webidl new file mode 100644 index 00000000000..0da53b81c17 --- /dev/null +++ b/components/script/dom/webidls/WEBGLCompressedTextureS3TC.webidl @@ -0,0 +1,16 @@ +/* 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/. */ +/* + * WebGL IDL definitions from the Khronos specification: + * https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ + */ + +[NoInterfaceObject] +interface WEBGLCompressedTextureS3TC { + /* Compressed Texture Formats */ + const GLenum COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; + const GLenum COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; + const GLenum COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; + const GLenum COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; +}; // interface WEBGLCompressedTextureS3TC diff --git a/components/script_layout_interface/Cargo.toml b/components/script_layout_interface/Cargo.toml index 1edde2cb613..91ef929ec28 100644 --- a/components/script_layout_interface/Cargo.toml +++ b/components/script_layout_interface/Cargo.toml @@ -18,7 +18,7 @@ cssparser = "0.25" crossbeam-channel = "0.3" euclid = "0.19" gfx_traits = {path = "../gfx_traits"} -html5ever = "0.22" +html5ever = "0.23" ipc-channel = "0.11" libc = "0.2" time = "0.1.17" diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index e675bb89f31..3947a5d3aa3 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -38,7 +38,7 @@ euclid = "0.19" fallible = { path = "../fallible" } fxhash = "0.2" hashglobe = { path = "../hashglobe" } -html5ever = {version = "0.22", optional = true} +html5ever = {version = "0.23", optional = true} indexmap = "1.0" itertools = "0.8" itoa = "0.4" |