aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2018-09-15 12:28:53 +0200
committerAnthony Ramine <n.oxyde@gmail.com>2018-09-16 20:44:41 +0200
commitf1e8eb640cd59864a3f32c0557a35a1c65a2b8d3 (patch)
tree50abe03fe32823d98d1e73ca234a54c5c556df05
parented673f80708a0a10bef728628c43e975542e4b6c (diff)
downloadservo-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.rs12
-rw-r--r--components/canvas_traits/canvas.rs2
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs104
-rw-r--r--components/script/dom/htmlcanvaselement.rs79
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))