aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs231
-rw-r--r--components/script/dom/htmlcanvaselement.rs28
-rw-r--r--components/script/dom/imagedata.rs37
-rw-r--r--components/script/dom/webglrenderingcontext.rs85
-rw-r--r--components/script/dom/webidls/CanvasRenderingContext2D.webidl4
5 files changed, 169 insertions, 216 deletions
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 9adbaa3a734..dacabcccce5 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -5,7 +5,7 @@
use canvas_traits::canvas::{Canvas2dMsg, CanvasMsg, CanvasId};
use canvas_traits::canvas::{CompositionOrBlending, FillOrStrokeStyle, FillRule};
use canvas_traits::canvas::{LineCapStyle, LineJoinStyle, LinearGradientStyle};
-use canvas_traits::canvas::{RadialGradientStyle, RepetitionStyle, byte_swap_and_premultiply};
+use canvas_traits::canvas::{RadialGradientStyle, RepetitionStyle};
use cssparser::{Parser, ParserInput, RGBA};
use cssparser::Color as CSSColor;
use dom::bindings::cell::DomRefCell;
@@ -40,11 +40,11 @@ use net_traits::image_cache::ImageOrMetadataAvailable;
use net_traits::image_cache::ImageResponse;
use net_traits::image_cache::ImageState;
use net_traits::image_cache::UsePlaceholder;
-use num_traits::ToPrimitive;
+use pixels;
use profile_traits::ipc as profiled_ipc;
use script_traits::ScriptMsg;
use servo_url::ServoUrl;
-use std::{cmp, fmt, mem};
+use std::{fmt, mem};
use std::cell::Cell;
use std::str::FromStr;
use std::sync::Arc;
@@ -410,7 +410,7 @@ impl CanvasRenderingContext2D {
Some((mut data, size)) => {
// Pixels come from cache in BGRA order and drawImage expects RGBA so we
// have to swap the color values
- byte_swap_and_premultiply(&mut data);
+ pixels::byte_swap_and_premultiply_inplace(&mut data);
let size = Size2D::new(size.width as f64, size.height as f64);
(data, size)
},
@@ -575,6 +575,28 @@ impl CanvasRenderingContext2D {
fn set_origin_unclean(&self) {
self.origin_clean.set(false)
}
+
+ pub fn get_rect(&self, rect: Rect<u32>) -> Vec<u8> {
+ assert!(self.origin_is_clean());
+
+ // 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());
+ assert!(Rect::from_size(canvas_size).contains_rect(&rect));
+
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(rect, canvas_size, sender));
+ let mut pixels = receiver.recv().unwrap().to_vec();
+
+ for chunk in pixels.chunks_mut(4) {
+ let b = chunk[0];
+ chunk[0] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[2] as usize];
+ chunk[1] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + chunk[1] as usize];
+ chunk[2] = UNPREMULTIPLY_TABLE[256 * (chunk[3] as usize) + b as usize];
+ }
+
+ pixels
+ }
}
pub trait LayoutCanvasRenderingContext2DHelpers {
@@ -1117,14 +1139,11 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
- fn CreateImageData(&self, sw: Finite<f64>, sh: Finite<f64>) -> Fallible<DomRoot<ImageData>> {
- if *sw == 0.0 || *sh == 0.0 {
+ fn CreateImageData(&self, sw: i32, sh: i32) -> Fallible<DomRoot<ImageData>> {
+ if sw == 0 || sh == 0 {
return Err(Error::IndexSize);
}
-
- let sw = cmp::max(1, sw.abs().to_u32().unwrap());
- let sh = cmp::max(1, sh.abs().to_u32().unwrap());
- ImageData::new(&self.global(), sw, sh, None)
+ ImageData::new(&self.global(), sw.abs() as u32, sh.abs() as u32, None)
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata
@@ -1133,61 +1152,31 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-getimagedata
- fn GetImageData(
- &self,
- sx: Finite<f64>,
- sy: Finite<f64>,
- sw: Finite<f64>,
- sh: Finite<f64>,
- ) -> Fallible<DomRoot<ImageData>> {
- if !self.origin_is_clean() {
- return Err(Error::Security);
- }
-
- let mut sx = *sx;
- let mut sy = *sy;
- let mut sw = *sw;
- let mut sh = *sh;
+ fn GetImageData(&self, sx: i32, sy: i32, sw: i32, sh: i32) -> Fallible<DomRoot<ImageData>> {
+ // FIXME(nox): There are many arithmetic operations here that can
+ // overflow or underflow, this should probably be audited.
- if sw == 0.0 || sh == 0.0 {
+ if sw == 0 || sh == 0 {
return Err(Error::IndexSize);
}
- if sw < 0.0 {
- sw = -sw;
- sx -= sw;
- }
- if sh < 0.0 {
- sh = -sh;
- sy -= sh;
+ if !self.origin_is_clean() {
+ return Err(Error::Security);
}
- let sh = cmp::max(1, sh.to_u32().unwrap());
- let sw = cmp::max(1, sw.to_u32().unwrap());
-
- let (sender, receiver) = ipc::bytes_channel().unwrap();
- let dest_rect = Rect::new(
- Point2D::new(sx.to_i32().unwrap(), sy.to_i32().unwrap()),
- Size2D::new(sw as i32, sh as i32),
- );
- let canvas_size = self
- .canvas
- .as_ref()
- .map(|c| c.get_size())
- .unwrap_or(Size2D::zero());
- let canvas_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
- self.send_canvas_2d_msg(Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender));
- let mut data = receiver.recv().unwrap();
-
- // Byte swap and unmultiply alpha.
- for chunk in data.chunks_mut(4) {
- let (b, g, r, a) = (chunk[0], chunk[1], chunk[2], chunk[3]);
- chunk[0] = UNPREMULTIPLY_TABLE[256 * (a as usize) + r as usize];
- chunk[1] = UNPREMULTIPLY_TABLE[256 * (a as usize) + g as usize];
- chunk[2] = UNPREMULTIPLY_TABLE[256 * (a as usize) + b as usize];
- }
+ let (origin, size) = adjust_size_sign(Point2D::new(sx, sy), Size2D::new(sw, sh));
+ // 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 pixels::clip(origin, size, canvas_size) {
+ Some(rect) => rect,
+ None => {
+ // All the pixels are outside the canvas surface.
+ return ImageData::new(&self.global(), size.width, size.height, None);
+ },
+ };
- ImageData::new(&self.global(), sw, sh, Some(data.to_vec()))
+ ImageData::new(&self.global(), size.width, size.height, Some(self.get_rect(read_rect)))
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
@@ -1196,21 +1185,23 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
}
// https://html.spec.whatwg.org/multipage/#dom-context-2d-putimagedata
+ #[allow(unsafe_code)]
fn PutImageData_(
&self,
imagedata: &ImageData,
dx: i32,
dy: i32,
- mut dirty_x: i32,
- mut dirty_y: i32,
- mut dirty_width: i32,
- mut dirty_height: i32,
+ dirty_x: i32,
+ dirty_y: i32,
+ dirty_width: i32,
+ dirty_height: i32,
) {
// FIXME(nox): There are many arithmetic operations here that can
// overflow or underflow, this should probably be audited.
- let imagedata_size = Size2D::new(imagedata.Width() as i32, imagedata.Height() as i32);
- if imagedata_size.width <= 0 || imagedata_size.height <= 0 {
+
+ let imagedata_size = Size2D::new(imagedata.Width(), imagedata.Height());
+ if imagedata_size.area() == 0 {
return;
}
@@ -1220,76 +1211,37 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
// Step 2.
// TODO: throw InvalidState if buffer is detached.
- // Step 3.
- if dirty_width < 0 {
- dirty_x += dirty_width;
- dirty_width = -dirty_width;
- }
- if dirty_height < 0 {
- dirty_y += dirty_height;
- dirty_height = -dirty_height;
- }
-
- // Ignore any pixel that would be drawn before the beginning of the
- // canvas surface.
- let mut dest_x = dx + dirty_x;
- let mut dest_y = dy + dirty_y;
- if dest_x < 0 {
- dirty_x -= dest_x;
- dirty_width += dest_x;
- dest_x = 0;
- }
- if dest_y < 0 {
- dirty_y -= dest_y;
- dirty_height += dest_y;
- dest_y = 0;
- }
-
- // Step 4.
- if dirty_x < 0 {
- dirty_width += dirty_x;
- dirty_x = 0;
- }
- if dirty_y < 0 {
- dirty_height += dirty_y;
- dirty_y = 0;
- }
-
- // Step 5.
- if dirty_x + dirty_width > imagedata_size.width {
- dirty_width = imagedata_size.width - dirty_x;
- }
- if dirty_y + dirty_height > imagedata_size.height {
- dirty_height = imagedata_size.height - dirty_y;
- }
+ // 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());
- // We take care of ignoring any pixel that would be drawn after the end
- // of the canvas surface.
- let canvas_size = self.canvas.as_ref().map_or(Size2D::zero(), |c| c.get_size()).to_i32();
- let origin = Point2D::new(dest_x, dest_y);
- let drawable_size = (origin - canvas_size.to_vector().to_point()).to_size().abs();
- dirty_width = dirty_width.min(drawable_size.width);
- dirty_height = dirty_height.min(drawable_size.height);
-
- // Step 6.
- if dirty_width <= 0 || dirty_height <= 0 {
- return;
- }
-
- // FIXME(nox): There is no need to make a Vec<u8> of all the pixels
- // if we didn't want to put the entire image.
- let buffer = imagedata.get_data_array();
+ // Steps 3-6.
+ let (src_origin, src_size) = adjust_size_sign(
+ Point2D::new(dirty_x, dirty_y),
+ Size2D::new(dirty_width, dirty_height),
+ );
+ let src_rect = match pixels::clip(src_origin, src_size, imagedata_size) {
+ Some(rect) => rect,
+ None => return,
+ };
+ let (dst_origin, _) = adjust_size_sign(
+ Point2D::new(dirty_x.saturating_add(dx), dirty_y.saturating_add(dy)),
+ Size2D::new(dirty_width, dirty_height),
+ );
+ // By clipping to the canvas surface, we avoid sending any pixel
+ // that would fall outside it.
+ let dst_rect = match pixels::clip(dst_origin, src_rect.size, canvas_size) {
+ Some(rect) => rect,
+ None => return,
+ };
// Step 7.
- self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(
- buffer.into(),
- origin.to_vector(),
- imagedata_size,
- Rect::new(
- Point2D::new(dirty_x, dirty_y),
- Size2D::new(dirty_width, dirty_height),
- ),
- ));
+ let (sender, receiver) = ipc::bytes_channel().unwrap();
+ let pixels = unsafe {
+ &imagedata.get_rect(Rect::new(src_rect.origin, dst_rect.size))
+ };
+ self.send_canvas_2d_msg(Canvas2dMsg::PutImageData(dst_rect, receiver));
+ sender.send(pixels).unwrap();
self.mark_as_dirty();
}
@@ -1539,7 +1491,7 @@ fn is_rect_valid(rect: Rect<f64>) -> bool {
rect.size.width > 0.0 && rect.size.height > 0.0
}
-// https://html.spec.whatwg.org/multipage/#serialisation-of-a-colour
+// https://html.spec.whatwg.org/multipage/#serialisation-of-a-color
fn serialize<W>(color: &RGBA, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
@@ -1570,3 +1522,18 @@ where
)
}
}
+
+fn adjust_size_sign(
+ mut origin: Point2D<i32>,
+ mut size: Size2D<i32>,
+) -> (Point2D<i32>, Size2D<u32>) {
+ if size.width < 0 {
+ size.width = -size.width;
+ origin.x = origin.x.saturating_sub(size.width);
+ }
+ if size.height < 0 {
+ size.height = -size.height;
+ origin.y = origin.y.saturating_sub(size.height);
+ }
+ (origin, size.to_u32())
+}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 09114a95d0a..8f572336573 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -7,14 +7,12 @@ use canvas_traits::canvas::{CanvasMsg, CanvasId, FromScriptMsg};
use canvas_traits::webgl::WebGLVersion;
use dom::attr::Attr;
use dom::bindings::cell::DomRefCell;
-use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::{HTMLCanvasElementMethods, RenderingContext};
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
use dom::bindings::conversions::ConversionResult;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
-use dom::bindings::num::Finite;
use dom::bindings::reflector::DomObject;
use dom::bindings::root::{Dom, DomRoot, LayoutDom};
use dom::bindings::str::{DOMString, USVString};
@@ -28,7 +26,7 @@ use dom::virtualmethods::VirtualMethods;
use dom::webgl2renderingcontext::WebGL2RenderingContext;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use dom_struct::dom_struct;
-use euclid::Size2D;
+use euclid::{Rect, Size2D};
use html5ever::{LocalName, Prefix};
use image::ColorType;
use image::png::PNGEncoder;
@@ -355,10 +353,8 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
_quality: HandleValue,
) -> Fallible<USVString> {
// Step 1.
- if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() {
- if !context.origin_is_clean() {
- return Err(Error::Security);
- }
+ if !self.origin_is_clean() {
+ return Err(Error::Security);
}
// Step 2.
@@ -367,24 +363,18 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
}
// Step 3.
- let raw_data = match *self.context.borrow() {
+ let file = match *self.context.borrow() {
Some(CanvasContext::Context2d(ref context)) => {
- let image_data = context.GetImageData(
- Finite::wrap(0f64),
- Finite::wrap(0f64),
- Finite::wrap(self.Width() as f64),
- Finite::wrap(self.Height() as f64),
- )?;
- image_data.get_data_array()
+ 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())),
}
@@ -397,8 +387,10 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
// FIXME: Only handle image/png for now.
let mut png = Vec::new();
+ // FIXME(nox): https://github.com/PistonDevelopers/image-png/issues/86
+ // FIXME(nox): https://github.com/PistonDevelopers/image-png/issues/87
PNGEncoder::new(&mut png)
- .encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8))
+ .encode(&file, self.Width(), self.Height(), ColorType::RGBA(8))
.unwrap();
let mut url = "data:image/png;base64,".to_owned();
// FIXME(nox): Should this use base64::URL_SAFE?
diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs
index ea65d533ffe..f72ea49c0ff 100644
--- a/components/script/dom/imagedata.rs
+++ b/components/script/dom/imagedata.rs
@@ -9,10 +9,12 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
-use euclid::Size2D;
+use euclid::{Rect, Size2D};
use js::jsapi::{Heap, JSContext, JSObject};
use js::rust::Runtime;
use js::typedarray::{Uint8ClampedArray, CreateWith};
+use pixels;
+use std::borrow::Cow;
use std::default::Default;
use std::ptr;
use std::ptr::NonNull;
@@ -137,16 +139,31 @@ impl ImageData {
Self::new_with_jsobject(global, width, opt_height, Some(jsobject))
}
+ /// Nothing must change the array on the JS side while the slice is live.
#[allow(unsafe_code)]
- pub fn get_data_array(&self) -> Vec<u8> {
- unsafe {
- assert!(!self.data.get().is_null());
- let cx = Runtime::get();
- assert!(!cx.is_null());
- typedarray!(in(cx) let array: Uint8ClampedArray = self.data.get());
- let vec = array.unwrap().as_slice().to_vec();
- vec
- }
+ pub unsafe fn as_slice(&self) -> &[u8] {
+ assert!(!self.data.get().is_null());
+ let cx = Runtime::get();
+ assert!(!cx.is_null());
+ typedarray!(in(cx) let array: Uint8ClampedArray = self.data.get());
+ let array = array.as_ref().unwrap();
+ // 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
+ // this ImageData instance will never change. The method is thus unsafe
+ // because the array may be manipulated from JS while the reference
+ // is live.
+ let ptr = array.as_slice() as *const _;
+ &*ptr
+ }
+
+ #[allow(unsafe_code)]
+ pub fn to_vec(&self) -> Vec<u8> {
+ unsafe { self.as_slice().into() }
+ }
+
+ #[allow(unsafe_code)]
+ pub unsafe fn get_rect(&self, rect: Rect<u32>) -> Cow<[u8]> {
+ pixels::get_rect(self.as_slice(), self.get_size(), rect)
}
pub fn get_size(&self) -> Size2D<u32> {
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index d832776230d..c8f2b1fce4f 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -5,7 +5,6 @@
#[cfg(feature = "webgl_backtrace")]
use backtrace::Backtrace;
use byteorder::{ByteOrder, NativeEndian, WriteBytesExt};
-use canvas_traits::canvas::{byte_swap, multiply_u8_pixel};
use canvas_traits::webgl::{DOMToTextureCommand, Parameter, WebGLCommandBacktrace};
use canvas_traits::webgl::{TexParameter, WebGLCommand, WebGLContextShareMode, WebGLError};
use canvas_traits::webgl::{WebGLFramebufferBindingRequest, WebGLMsg, WebGLMsgSender};
@@ -53,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};
@@ -65,6 +64,7 @@ use js::typedarray::{TypedArray, TypedArrayElementCreator};
use net_traits::image::base::PixelFormat;
use net_traits::image_cache::ImageResponse;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
+use pixels;
use script_layout_interface::HTMLCanvasDataSource;
use serde::{Deserialize, Serialize};
use servo_config::prefs::PREFS;
@@ -524,7 +524,7 @@ impl WebGLRenderingContext {
) -> Fallible<Option<(Vec<u8>, Size2D<u32>, bool)>> {
Ok(Some(match source {
TexImageSource::ImageData(image_data) => {
- (image_data.get_data_array(), image_data.get_size(), false)
+ (image_data.to_vec(), image_data.get_size(), false)
},
TexImageSource::HTMLImageElement(image) => {
let document = document_from_node(&*self.canvas);
@@ -554,7 +554,7 @@ impl WebGLRenderingContext {
_ => unimplemented!(),
};
- byte_swap(&mut data);
+ pixels::byte_swap_colors_inplace(&mut data);
(data, size, false)
},
@@ -567,7 +567,7 @@ impl WebGLRenderingContext {
}
if let Some((mut data, size)) = canvas.fetch_all_data() {
// Pixels got from Canvas have already alpha premultiplied
- byte_swap(&mut data);
+ pixels::byte_swap_colors_inplace(&mut data);
(data, size, true)
} else {
return Ok(None);
@@ -683,15 +683,11 @@ impl WebGLRenderingContext {
match (format, data_type) {
(TexFormat::RGBA, TexDataType::UnsignedByte) => {
- for rgba in pixels.chunks_mut(4) {
- rgba[0] = multiply_u8_pixel(rgba[0], rgba[3]);
- rgba[1] = multiply_u8_pixel(rgba[1], rgba[3]);
- rgba[2] = multiply_u8_pixel(rgba[2], rgba[3]);
- }
+ pixels::premultiply_inplace(pixels);
},
(TexFormat::LuminanceAlpha, TexDataType::UnsignedByte) => {
for la in pixels.chunks_mut(2) {
- la[0] = multiply_u8_pixel(la[0], la[1]);
+ la[0] = pixels::multiply_u8_color(la[0], la[1]);
}
},
(TexFormat::RGBA, TexDataType::UnsignedShort5551) => {
@@ -711,9 +707,9 @@ impl WebGLRenderingContext {
let a = extend_to_8_bits(pix & 0x0f);
NativeEndian::write_u16(
rgba,
- ((multiply_u8_pixel(r, a) & 0xf0) as u16) << 8 |
- ((multiply_u8_pixel(g, a) & 0xf0) as u16) << 4 |
- ((multiply_u8_pixel(b, a) & 0xf0) as u16) |
+ ((pixels::multiply_u8_color(r, a) & 0xf0) as u16) << 8 |
+ ((pixels::multiply_u8_color(g, a) & 0xf0) as u16) << 4 |
+ ((pixels::multiply_u8_color(b, a) & 0xf0) as u16) |
((a & 0x0f) as u16),
);
}
@@ -1078,7 +1074,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!(
@@ -1086,15 +1082,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,
@@ -2887,45 +2880,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;
diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
index f772bd2e8db..82001645924 100644
--- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl
+++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl
@@ -175,11 +175,11 @@ interface CanvasDrawImage {
interface CanvasImageData {
// pixel manipulation
[Throws]
- ImageData createImageData(double sw, double sh);
+ ImageData createImageData(long sw, long sh);
[Throws]
ImageData createImageData(ImageData imagedata);
[Throws]
- ImageData getImageData(double sx, double sy, double sw, double sh);
+ ImageData getImageData(long sx, long sy, long sw, long sh);
void putImageData(ImageData imagedata, long dx, long dy);
void putImageData(ImageData imagedata,
long dx, long dy,