diff options
-rw-r--r-- | components/canvas/webgl_thread.rs | 27 | ||||
-rw-r--r-- | components/canvas_traits/webgl.rs | 4 | ||||
-rw-r--r-- | components/pixels/lib.rs | 20 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 24 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 4 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 63 |
6 files changed, 58 insertions, 84 deletions
diff --git a/components/canvas/webgl_thread.rs b/components/canvas/webgl_thread.rs index cd8dbde18d2..d00ae02871b 100644 --- a/components/canvas/webgl_thread.rs +++ b/components/canvas/webgl_thread.rs @@ -6,7 +6,6 @@ use canvas_traits::webgl::*; use euclid::Size2D; use fnv::FnvHashMap; use gleam::gl; -use ipc_channel::ipc::IpcBytesSender; use offscreen_gl_context::{GLContext, GLContextAttributes, GLLimits, NativeGLContextMethods}; use pixels; use std::thread; @@ -791,8 +790,16 @@ impl WebGLImpl { ctx.gl().pixel_store_i(name, val), WebGLCommand::PolygonOffset(factor, units) => ctx.gl().polygon_offset(factor, units), - WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, ref chan) => { - Self::read_pixels(ctx.gl(), x, y, width, height, format, pixel_type, chan) + WebGLCommand::ReadPixels(rect, format, pixel_type, ref sender) => { + let pixels = ctx.gl().read_pixels( + rect.origin.x as i32, + rect.origin.y as i32, + rect.size.width as i32, + rect.size.height as i32, + format, + pixel_type, + ); + sender.send(&pixels).unwrap(); } WebGLCommand::RenderbufferStorage(target, format, width, height) => ctx.gl().renderbuffer_storage(target, format, width, height), @@ -1335,20 +1342,6 @@ impl WebGLImpl { } } - fn read_pixels( - gl: &gl::Gl, - x: i32, - y: i32, - width: i32, - height: i32, - format: u32, - pixel_type: u32, - chan: &IpcBytesSender, - ) { - let result = gl.read_pixels(x, y, width, height, format, pixel_type); - chan.send(&result).unwrap() - } - fn finish(gl: &gl::Gl, chan: &WebGLSender<()>) { gl.finish(); chan.send(()).unwrap(); diff --git a/components/canvas_traits/webgl.rs b/components/canvas_traits/webgl.rs index 4c392972b8e..43a24771ae1 100644 --- a/components/canvas_traits/webgl.rs +++ b/components/canvas_traits/webgl.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use euclid::Size2D; +use euclid::{Rect, Size2D}; use gleam::gl; use ipc_channel::ipc::{IpcBytesReceiver, IpcBytesSender}; use offscreen_gl_context::{GLContextAttributes, GLLimits}; @@ -227,7 +227,7 @@ pub enum WebGLCommand { GetRenderbufferParameter(u32, u32, WebGLSender<i32>), PolygonOffset(f32, f32), RenderbufferStorage(u32, u32, i32, i32), - ReadPixels(i32, i32, i32, i32, u32, u32, IpcBytesSender), + ReadPixels(Rect<u32>, u32, u32, IpcBytesSender), SampleCoverage(f32, bool), Scissor(i32, i32, u32, u32), StencilFunc(u32, i32, u32), diff --git a/components/pixels/lib.rs b/components/pixels/lib.rs index dc6285ebaab..de29e5fa2ee 100644 --- a/components/pixels/lib.rs +++ b/components/pixels/lib.rs @@ -4,7 +4,7 @@ extern crate euclid; -use euclid::{Rect, Size2D}; +use euclid::{Point2D, Rect, Size2D}; use std::borrow::Cow; pub fn get_rect(pixels: &[u8], size: Size2D<u32>, rect: Rect<u32>) -> Cow<[u8]> { @@ -63,3 +63,21 @@ pub fn premultiply_inplace(pixels: &mut [u8]) -> bool { pub fn multiply_u8_color(a: u8, b: u8) -> u8 { return (a as u32 * b as u32 / 255) as u8; } + +pub fn clip( + mut origin: Point2D<i32>, + mut size: Size2D<u32>, + surface: Size2D<u32>, +) -> Option<Rect<u32>> { + if origin.x < 0 { + size.width = size.width.saturating_sub(-origin.x as u32); + origin.x = 0; + } + if origin.y < 0 { + size.height = size.height.saturating_sub(-origin.y as u32); + origin.y = 0; + } + Rect::new(origin.to_u32(), size) + .intersection(&Rect::from_size(surface)) + .filter(|rect| !rect.is_empty()) +} diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 2617f9e7ed5..dacabcccce5 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -1168,7 +1168,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { // FIXME(nox): This is probably wrong when this is a context for an // offscreen canvas. let canvas_size = self.canvas.as_ref().map_or(Size2D::zero(), |c| c.get_size()); - let read_rect = match clip(origin, size, canvas_size) { + let read_rect = match pixels::clip(origin, size, canvas_size) { Some(rect) => rect, None => { // All the pixels are outside the canvas surface. @@ -1220,7 +1220,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { Point2D::new(dirty_x, dirty_y), Size2D::new(dirty_width, dirty_height), ); - let src_rect = match clip(src_origin, src_size, imagedata_size) { + let src_rect = match pixels::clip(src_origin, src_size, imagedata_size) { Some(rect) => rect, None => return, }; @@ -1230,7 +1230,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { ); // By clipping to the canvas surface, we avoid sending any pixel // that would fall outside it. - let dst_rect = match clip(dst_origin, src_rect.size, canvas_size) { + let dst_rect = match pixels::clip(dst_origin, src_rect.size, canvas_size) { Some(rect) => rect, None => return, }; @@ -1537,21 +1537,3 @@ fn adjust_size_sign( } (origin, size.to_u32()) } - -fn clip( - mut origin: Point2D<i32>, - mut size: Size2D<u32>, - surface: Size2D<u32>, -) -> Option<Rect<u32>> { - if origin.x < 0 { - size.width = size.width.saturating_sub(-origin.x as u32); - origin.x = 0; - } - if origin.y < 0 { - size.height = size.height.saturating_sub(-origin.y as u32); - origin.y = 0; - } - Rect::new(origin.to_u32(), size) - .intersection(&Rect::from_size(surface)) - .filter(|rect| !rect.is_empty()) -} diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 5cc28fcf461..8f572336573 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -368,13 +368,13 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement { context.get_rect(Rect::from_size(self.get_size())) }, Some(CanvasContext::WebGL(ref context)) => { - match context.get_image_data(self.Width(), self.Height()) { + match context.get_image_data(self.get_size()) { Some(data) => data, None => return Ok(USVString("data:,".into())), } }, Some(CanvasContext::WebGL2(ref context)) => { - match context.base_context().get_image_data(self.Width(), self.Height()) { + match context.base_context().get_image_data(self.get_size()) { Some(data) => data, None => return Ok(USVString("data:,".into())), } diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 4e3658fa524..bfccd5e6f68 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -52,7 +52,7 @@ use dom::webgluniformlocation::WebGLUniformLocation; use dom::webglvertexarrayobjectoes::WebGLVertexArrayObjectOES; use dom::window::Window; use dom_struct::dom_struct; -use euclid::Size2D; +use euclid::{Point2D, Rect, Size2D}; use half::f16; use ipc_channel::ipc; use js::jsapi::{JSContext, JSObject, Type}; @@ -1070,7 +1070,7 @@ impl WebGLRenderingContext { // can fail and that it is UB what happens in that case. // // https://www.khronos.org/registry/webgl/specs/latest/1.0/#2.2 - pub fn get_image_data(&self, width: u32, height: u32) -> Option<Vec<u8>> { + pub fn get_image_data(&self, mut size: Size2D<u32>) -> Option<Vec<u8>> { handle_potential_webgl_error!(self, self.validate_framebuffer(), return None); let (fb_width, fb_height) = handle_potential_webgl_error!( @@ -1078,15 +1078,12 @@ impl WebGLRenderingContext { self.get_current_framebuffer_size().ok_or(InvalidOperation), return None ); - let width = cmp::min(width, fb_width as u32); - let height = cmp::min(height, fb_height as u32); + size.width = cmp::min(size.width, fb_width as u32); + size.height = cmp::min(size.height, fb_height as u32); let (sender, receiver) = ipc::bytes_channel().unwrap(); self.send_command(WebGLCommand::ReadPixels( - 0, - 0, - width as i32, - height as i32, + Rect::from_size(size), constants::RGBA, constants::UNSIGNED_BYTE, sender, @@ -2879,45 +2876,29 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { return self.webgl_error(InvalidOperation); } - let mut src_x = x; - let mut src_y = y; - let mut src_width = width; - let mut src_height = height; - let mut dest_offset = 0; - - if src_x < 0 { - if src_width <= -src_x { - return; - } - dest_offset += bytes_per_pixel * -src_x; - src_width += src_x; - src_x = 0; - } - if src_y < 0 { - if src_height <= -src_y { - return; - } - dest_offset += row_len * -src_y; - src_height += src_y; - src_y = 0; - } + let src_origin = Point2D::new(x, y); + let src_size = Size2D::new(width as u32, height as u32); + let fb_size = Size2D::new(fb_width as u32, fb_height as u32); + let src_rect = match pixels::clip(src_origin, src_size, fb_size) { + Some(rect) => rect, + None => return, + }; - if src_x + src_width > fb_width { - src_width = fb_width - src_x; + let mut dest_offset = 0; + if x < 0 { + dest_offset += -x * bytes_per_pixel; } - if src_y + src_height > fb_height { - src_height = fb_height - src_y; + if y < 0 { + dest_offset += -y * row_len; } let (sender, receiver) = ipc::bytes_channel().unwrap(); - self.send_command(WebGLCommand::ReadPixels( - src_x, src_y, src_width, src_height, format, pixel_type, sender, - )); - + self.send_command(WebGLCommand::ReadPixels(src_rect, format, pixel_type, sender)); let src = receiver.recv().unwrap(); - let src_row_len = (src_width * bytes_per_pixel) as usize; - for i in 0..src_height { - let dest_start = (dest_offset + i * dest_stride) as usize; + + let src_row_len = src_rect.size.width as usize * bytes_per_pixel as usize; + for i in 0..src_rect.size.height { + let dest_start = dest_offset as usize + i as usize * dest_stride as usize; let dest_end = dest_start + src_row_len; let src_start = i as usize * src_row_len; let src_end = src_start + src_row_len; |