diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2018-09-15 12:28:53 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2018-09-16 20:44:41 +0200 |
commit | f1e8eb640cd59864a3f32c0557a35a1c65a2b8d3 (patch) | |
tree | 50abe03fe32823d98d1e73ca234a54c5c556df05 | |
parent | ed673f80708a0a10bef728628c43e975542e4b6c (diff) | |
download | servo-f1e8eb640cd59864a3f32c0557a35a1c65a2b8d3.tar.gz servo-f1e8eb640cd59864a3f32c0557a35a1c65a2b8d3.zip |
Don't create 2D canvas contexts arbitrarily
Sometimes, the canvas still has no rendering context, in this case it represents
a transparent black rectangle.
-rw-r--r-- | components/canvas/canvas_paint_thread.rs | 12 | ||||
-rw-r--r-- | components/canvas_traits/canvas.rs | 2 | ||||
-rw-r--r-- | components/script/dom/canvasrenderingcontext2d.rs | 104 | ||||
-rw-r--r-- | components/script/dom/htmlcanvaselement.rs | 79 |
4 files changed, 107 insertions, 90 deletions
diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 7f0130e8f3e..a6050d93564 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -132,15 +132,21 @@ impl<'a> CanvasPaintThread <'a> { self.canvas(canvas_id).is_point_in_path(x, y, fill_rule, chan) }, Canvas2dMsg::DrawImage( - mut imagedata, + imagedata, image_size, dest_rect, source_rect, smoothing_enabled, ) => { - byte_swap(&mut imagedata); + let data = match imagedata { + None => vec![0; image_size.width as usize * image_size.height as usize * 4], + Some(mut data) => { + byte_swap(&mut data); + data.into() + }, + }; self.canvas(canvas_id).draw_image( - imagedata.into(), + data, image_size, dest_rect, source_rect, diff --git a/components/canvas_traits/canvas.rs b/components/canvas_traits/canvas.rs index 661bae6b606..a2af3a70d42 100644 --- a/components/canvas_traits/canvas.rs +++ b/components/canvas_traits/canvas.rs @@ -38,7 +38,7 @@ pub struct CanvasImageData { pub enum Canvas2dMsg { Arc(Point2D<f32>, f32, f32, f32, bool), ArcTo(Point2D<f32>, Point2D<f32>, f32), - DrawImage(ByteBuf, Size2D<f64>, Rect<f64>, Rect<f64>, bool), + DrawImage(Option<ByteBuf>, Size2D<f64>, Rect<f64>, Rect<f64>, bool), DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool), DrawImageInOther( CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool), diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 24d6af0282d..12e3ad17959 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -27,7 +27,7 @@ use dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeSty use dom::canvaspattern::CanvasPattern; use dom::element::Element; use dom::globalscope::GlobalScope; -use dom::htmlcanvaselement::HTMLCanvasElement; +use dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement}; use dom::imagedata::ImageData; use dom::node::{Node, NodeDamage, window_from_node}; use dom_struct::dom_struct; @@ -315,17 +315,18 @@ impl CanvasRenderingContext2D { result } - fn draw_html_canvas_element(&self, - canvas: &HTMLCanvasElement, - sx: f64, - sy: f64, - sw: Option<f64>, - sh: Option<f64>, - dx: f64, - dy: f64, - dw: Option<f64>, - dh: Option<f64>) - -> ErrorResult { + fn draw_html_canvas_element( + &self, + canvas: &HTMLCanvasElement, + sx: f64, + sy: f64, + sw: Option<f64>, + sh: Option<f64>, + dx: f64, + dy: f64, + dw: Option<f64>, + dh: Option<f64>, + ) -> ErrorResult { // 1. Check the usability of the image argument if !canvas.is_valid() { return Err(Error::InvalidState); @@ -339,15 +340,17 @@ impl CanvasRenderingContext2D { let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); // 2. Establish the source and destination rectangles - let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size, - sx, - sy, - sw, - sh, - dx, - dy, - dw, - dh); + let (source_rect, dest_rect) = self.adjust_source_dest_rects( + image_size, + sx, + sy, + sw, + sh, + dx, + dy, + dw, + dh, + ); if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { return Ok(()); @@ -355,29 +358,40 @@ impl CanvasRenderingContext2D { let smoothing_enabled = self.state.borrow().image_smoothing_enabled; - if self.canvas.as_ref().map_or(false, |c| &**c == canvas) { - self.send_canvas_2d_msg(Canvas2dMsg::DrawImageSelf( - image_size, dest_rect, source_rect, smoothing_enabled)); + if let Some(context) = canvas.context() { + match *context { + CanvasContext::Context2d(ref context) => { + if self.canvas.as_ref().map_or(false, |c| &**c == canvas) { + self.send_canvas_2d_msg(Canvas2dMsg::DrawImageSelf( + image_size, + dest_rect, + source_rect, + smoothing_enabled, + )); + } else { + context.get_ipc_renderer().send(CanvasMsg::Canvas2d( + Canvas2dMsg::DrawImageInOther( + self.get_canvas_id(), + image_size, + dest_rect, + source_rect, + smoothing_enabled, + ), + context.get_canvas_id(), + )).unwrap(); + } + }, + _ => return Err(Error::InvalidState), + } } else { - let context = match canvas.get_or_init_2d_context() { - Some(context) => context, - None => return Err(Error::InvalidState), - }; - - let msg = CanvasMsg::Canvas2d( - Canvas2dMsg::DrawImageInOther( - self.get_canvas_id(), - image_size, - dest_rect, - source_rect, - smoothing_enabled - ), - context.get_canvas_id() - ); - - let renderer = context.get_ipc_renderer(); - renderer.send(msg).unwrap(); - }; + self.send_canvas_2d_msg(Canvas2dMsg::DrawImage( + None, + image_size, + dest_rect, + source_rect, + smoothing_enabled, + )); + } self.mark_as_dirty(); Ok(()) @@ -447,7 +461,7 @@ impl CanvasRenderingContext2D { let smoothing_enabled = self.state.borrow().image_smoothing_enabled; self.send_canvas_2d_msg(Canvas2dMsg::DrawImage( - image_data.into(), + Some(image_data.into()), image_size, dest_rect, source_rect, @@ -1205,8 +1219,6 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { .ok_or(Error::InvalidState)? }, CanvasImageSource::HTMLCanvasElement(ref canvas) => { - let _ = canvas.get_or_init_2d_context(); - canvas.fetch_all_data().ok_or(Error::InvalidState)? }, CanvasImageSource::CSSStyleValue(ref value) => { diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index dd1538b8529..7bc6a233e66 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -37,9 +37,10 @@ use js::jsapi::JSContext; use js::rust::HandleValue; use offscreen_gl_context::GLContextAttributes; use profile_traits::ipc; +use ref_filter_map; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; use servo_config::prefs::PREFS; -use std::iter::repeat; +use std::cell::Ref; use style::attr::{AttrValue, LengthOrPercentageOrAuto}; const DEFAULT_WIDTH: u32 = 300; @@ -174,18 +175,22 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<HTMLCanvasElement> { impl HTMLCanvasElement { - pub fn get_or_init_2d_context(&self) -> Option<DomRoot<CanvasRenderingContext2D>> { - if self.context.borrow().is_none() { - let window = window_from_node(self); - let size = self.get_size(); - let context = CanvasRenderingContext2D::new(window.upcast::<GlobalScope>(), self, size); - *self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context))); - } + pub fn context(&self) -> Option<Ref<CanvasContext>> { + ref_filter_map::ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref()) + } - match *self.context.borrow().as_ref().unwrap() { - CanvasContext::Context2d(ref context) => Some(DomRoot::from_ref(&*context)), - _ => None, + fn get_or_init_2d_context(&self) -> Option<DomRoot<CanvasRenderingContext2D>> { + if let Some(ctx) = self.context() { + return match *ctx { + CanvasContext::Context2d(ref ctx) => Some(DomRoot::from_ref(ctx)), + _ => None, + }; } + let window = window_from_node(self); + let size = self.get_size(); + let context = CanvasRenderingContext2D::new(window.upcast::<GlobalScope>(), self, size); + *self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context))); + Some(context) } #[allow(unsafe_code)] @@ -194,20 +199,18 @@ impl HTMLCanvasElement { cx: *mut JSContext, options: HandleValue, ) -> Option<DomRoot<WebGLRenderingContext>> { - if self.context.borrow().is_none() { - let window = window_from_node(self); - let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, options)?; - let maybe_ctx = WebGLRenderingContext::new(&window, self, WebGLVersion::WebGL1, size, attrs); - - *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(Dom::from_ref(&*ctx))); - } - - if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() { - Some(DomRoot::from_ref(&*context)) - } else { - None + if let Some(ctx) = self.context() { + return match *ctx { + CanvasContext::WebGL(ref ctx) => Some(DomRoot::from_ref(ctx)), + _ => None, + }; } + let window = window_from_node(self); + let size = self.get_size(); + let attrs = Self::get_gl_attributes(cx, options)?; + let context = WebGLRenderingContext::new(&window, self, WebGLVersion::WebGL1, size, attrs)?; + *self.context.borrow_mut() = Some(CanvasContext::WebGL(Dom::from_ref(&*context))); + Some(context) } #[allow(unsafe_code)] @@ -219,20 +222,18 @@ impl HTMLCanvasElement { if !PREFS.is_webgl2_enabled() { return None } - if self.context.borrow().is_none() { - let window = window_from_node(self); - let size = self.get_size(); - let attrs = Self::get_gl_attributes(cx, options)?; - let maybe_ctx = WebGL2RenderingContext::new(&window, self, size, attrs); - - *self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL2(Dom::from_ref(&*ctx))); - } - - if let Some(CanvasContext::WebGL2(ref context)) = *self.context.borrow() { - Some(DomRoot::from_ref(&*context)) - } else { - None + if let Some(ctx) = self.context() { + return match *ctx { + CanvasContext::WebGL2(ref ctx) => Some(DomRoot::from_ref(ctx)), + _ => None, + }; } + let window = window_from_node(self); + let size = self.get_size(); + let attrs = Self::get_gl_attributes(cx, options)?; + let context = WebGL2RenderingContext::new(&window, self, size, attrs)?; + *self.context.borrow_mut() = Some(CanvasContext::WebGL2(Dom::from_ref(&*context))); + Some(context) } /// Gets the base WebGLRenderingContext for WebGL or WebGL 2, if exists. @@ -289,9 +290,7 @@ impl HTMLCanvasElement { // TODO: add a method in WebGL2RenderingContext to get the pixels. return None; }, - None => { - repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect() - } + None => vec![0; size.height as usize * size.width as usize * 4] }; Some((data, size)) |