mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Don't create 2D canvas contexts arbitrarily
Sometimes, the canvas still has no rendering context, in this case it represents a transparent black rectangle.
This commit is contained in:
parent
ed673f8070
commit
f1e8eb640c
4 changed files with 107 additions and 90 deletions
|
@ -132,15 +132,21 @@ impl<'a> CanvasPaintThread <'a> {
|
||||||
self.canvas(canvas_id).is_point_in_path(x, y, fill_rule, chan)
|
self.canvas(canvas_id).is_point_in_path(x, y, fill_rule, chan)
|
||||||
},
|
},
|
||||||
Canvas2dMsg::DrawImage(
|
Canvas2dMsg::DrawImage(
|
||||||
mut imagedata,
|
imagedata,
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled,
|
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(
|
self.canvas(canvas_id).draw_image(
|
||||||
imagedata.into(),
|
data,
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub struct CanvasImageData {
|
||||||
pub enum Canvas2dMsg {
|
pub enum Canvas2dMsg {
|
||||||
Arc(Point2D<f32>, f32, f32, f32, bool),
|
Arc(Point2D<f32>, f32, f32, f32, bool),
|
||||||
ArcTo(Point2D<f32>, Point2D<f32>, f32),
|
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),
|
DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
||||||
DrawImageInOther(
|
DrawImageInOther(
|
||||||
CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
|
||||||
|
|
|
@ -27,7 +27,7 @@ use dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeSty
|
||||||
use dom::canvaspattern::CanvasPattern;
|
use dom::canvaspattern::CanvasPattern;
|
||||||
use dom::element::Element;
|
use dom::element::Element;
|
||||||
use dom::globalscope::GlobalScope;
|
use dom::globalscope::GlobalScope;
|
||||||
use dom::htmlcanvaselement::HTMLCanvasElement;
|
use dom::htmlcanvaselement::{CanvasContext, HTMLCanvasElement};
|
||||||
use dom::imagedata::ImageData;
|
use dom::imagedata::ImageData;
|
||||||
use dom::node::{Node, NodeDamage, window_from_node};
|
use dom::node::{Node, NodeDamage, window_from_node};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
@ -315,7 +315,8 @@ impl CanvasRenderingContext2D {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_html_canvas_element(&self,
|
fn draw_html_canvas_element(
|
||||||
|
&self,
|
||||||
canvas: &HTMLCanvasElement,
|
canvas: &HTMLCanvasElement,
|
||||||
sx: f64,
|
sx: f64,
|
||||||
sy: f64,
|
sy: f64,
|
||||||
|
@ -324,8 +325,8 @@ impl CanvasRenderingContext2D {
|
||||||
dx: f64,
|
dx: f64,
|
||||||
dy: f64,
|
dy: f64,
|
||||||
dw: Option<f64>,
|
dw: Option<f64>,
|
||||||
dh: Option<f64>)
|
dh: Option<f64>,
|
||||||
-> ErrorResult {
|
) -> ErrorResult {
|
||||||
// 1. Check the usability of the image argument
|
// 1. Check the usability of the image argument
|
||||||
if !canvas.is_valid() {
|
if !canvas.is_valid() {
|
||||||
return Err(Error::InvalidState);
|
return Err(Error::InvalidState);
|
||||||
|
@ -339,7 +340,8 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64);
|
||||||
// 2. Establish the source and destination rectangles
|
// 2. Establish the source and destination rectangles
|
||||||
let (source_rect, dest_rect) = self.adjust_source_dest_rects(image_size,
|
let (source_rect, dest_rect) = self.adjust_source_dest_rects(
|
||||||
|
image_size,
|
||||||
sx,
|
sx,
|
||||||
sy,
|
sy,
|
||||||
sw,
|
sw,
|
||||||
|
@ -347,7 +349,8 @@ impl CanvasRenderingContext2D {
|
||||||
dx,
|
dx,
|
||||||
dy,
|
dy,
|
||||||
dw,
|
dw,
|
||||||
dh);
|
dh,
|
||||||
|
);
|
||||||
|
|
||||||
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -355,29 +358,40 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
let smoothing_enabled = self.state.borrow().image_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) {
|
if self.canvas.as_ref().map_or(false, |c| &**c == canvas) {
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::DrawImageSelf(
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawImageSelf(
|
||||||
image_size, dest_rect, source_rect, smoothing_enabled));
|
image_size,
|
||||||
|
dest_rect,
|
||||||
|
source_rect,
|
||||||
|
smoothing_enabled,
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
let context = match canvas.get_or_init_2d_context() {
|
context.get_ipc_renderer().send(CanvasMsg::Canvas2d(
|
||||||
Some(context) => context,
|
|
||||||
None => return Err(Error::InvalidState),
|
|
||||||
};
|
|
||||||
|
|
||||||
let msg = CanvasMsg::Canvas2d(
|
|
||||||
Canvas2dMsg::DrawImageInOther(
|
Canvas2dMsg::DrawImageInOther(
|
||||||
self.get_canvas_id(),
|
self.get_canvas_id(),
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
smoothing_enabled
|
smoothing_enabled,
|
||||||
),
|
),
|
||||||
context.get_canvas_id()
|
context.get_canvas_id(),
|
||||||
);
|
)).unwrap();
|
||||||
|
}
|
||||||
let renderer = context.get_ipc_renderer();
|
},
|
||||||
renderer.send(msg).unwrap();
|
_ => return Err(Error::InvalidState),
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
||||||
|
None,
|
||||||
|
image_size,
|
||||||
|
dest_rect,
|
||||||
|
source_rect,
|
||||||
|
smoothing_enabled,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
self.mark_as_dirty();
|
self.mark_as_dirty();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -447,7 +461,7 @@ impl CanvasRenderingContext2D {
|
||||||
|
|
||||||
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
|
||||||
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
|
||||||
image_data.into(),
|
Some(image_data.into()),
|
||||||
image_size,
|
image_size,
|
||||||
dest_rect,
|
dest_rect,
|
||||||
source_rect,
|
source_rect,
|
||||||
|
@ -1205,8 +1219,6 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D {
|
||||||
.ok_or(Error::InvalidState)?
|
.ok_or(Error::InvalidState)?
|
||||||
},
|
},
|
||||||
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
CanvasImageSource::HTMLCanvasElement(ref canvas) => {
|
||||||
let _ = canvas.get_or_init_2d_context();
|
|
||||||
|
|
||||||
canvas.fetch_all_data().ok_or(Error::InvalidState)?
|
canvas.fetch_all_data().ok_or(Error::InvalidState)?
|
||||||
},
|
},
|
||||||
CanvasImageSource::CSSStyleValue(ref value) => {
|
CanvasImageSource::CSSStyleValue(ref value) => {
|
||||||
|
|
|
@ -37,9 +37,10 @@ use js::jsapi::JSContext;
|
||||||
use js::rust::HandleValue;
|
use js::rust::HandleValue;
|
||||||
use offscreen_gl_context::GLContextAttributes;
|
use offscreen_gl_context::GLContextAttributes;
|
||||||
use profile_traits::ipc;
|
use profile_traits::ipc;
|
||||||
|
use ref_filter_map;
|
||||||
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
|
use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
|
||||||
use servo_config::prefs::PREFS;
|
use servo_config::prefs::PREFS;
|
||||||
use std::iter::repeat;
|
use std::cell::Ref;
|
||||||
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
|
||||||
|
|
||||||
const DEFAULT_WIDTH: u32 = 300;
|
const DEFAULT_WIDTH: u32 = 300;
|
||||||
|
@ -174,18 +175,22 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<HTMLCanvasElement> {
|
||||||
|
|
||||||
|
|
||||||
impl HTMLCanvasElement {
|
impl HTMLCanvasElement {
|
||||||
pub fn get_or_init_2d_context(&self) -> Option<DomRoot<CanvasRenderingContext2D>> {
|
pub fn context(&self) -> Option<Ref<CanvasContext>> {
|
||||||
if self.context.borrow().is_none() {
|
ref_filter_map::ref_filter_map(self.context.borrow(), |ctx| ctx.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
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 window = window_from_node(self);
|
||||||
let size = self.get_size();
|
let size = self.get_size();
|
||||||
let context = CanvasRenderingContext2D::new(window.upcast::<GlobalScope>(), self, size);
|
let context = CanvasRenderingContext2D::new(window.upcast::<GlobalScope>(), self, size);
|
||||||
*self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context)));
|
*self.context.borrow_mut() = Some(CanvasContext::Context2d(Dom::from_ref(&*context)));
|
||||||
}
|
Some(context)
|
||||||
|
|
||||||
match *self.context.borrow().as_ref().unwrap() {
|
|
||||||
CanvasContext::Context2d(ref context) => Some(DomRoot::from_ref(&*context)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -194,20 +199,18 @@ impl HTMLCanvasElement {
|
||||||
cx: *mut JSContext,
|
cx: *mut JSContext,
|
||||||
options: HandleValue,
|
options: HandleValue,
|
||||||
) -> Option<DomRoot<WebGLRenderingContext>> {
|
) -> Option<DomRoot<WebGLRenderingContext>> {
|
||||||
if self.context.borrow().is_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 window = window_from_node(self);
|
||||||
let size = self.get_size();
|
let size = self.get_size();
|
||||||
let attrs = Self::get_gl_attributes(cx, options)?;
|
let attrs = Self::get_gl_attributes(cx, options)?;
|
||||||
let maybe_ctx = WebGLRenderingContext::new(&window, self, WebGLVersion::WebGL1, size, attrs);
|
let context = WebGLRenderingContext::new(&window, self, WebGLVersion::WebGL1, size, attrs)?;
|
||||||
|
*self.context.borrow_mut() = Some(CanvasContext::WebGL(Dom::from_ref(&*context)));
|
||||||
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(Dom::from_ref(&*ctx)));
|
Some(context)
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
|
|
||||||
Some(DomRoot::from_ref(&*context))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -219,20 +222,18 @@ impl HTMLCanvasElement {
|
||||||
if !PREFS.is_webgl2_enabled() {
|
if !PREFS.is_webgl2_enabled() {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
if self.context.borrow().is_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 window = window_from_node(self);
|
||||||
let size = self.get_size();
|
let size = self.get_size();
|
||||||
let attrs = Self::get_gl_attributes(cx, options)?;
|
let attrs = Self::get_gl_attributes(cx, options)?;
|
||||||
let maybe_ctx = WebGL2RenderingContext::new(&window, self, size, attrs);
|
let context = WebGL2RenderingContext::new(&window, self, size, attrs)?;
|
||||||
|
*self.context.borrow_mut() = Some(CanvasContext::WebGL2(Dom::from_ref(&*context)));
|
||||||
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL2(Dom::from_ref(&*ctx)));
|
Some(context)
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(CanvasContext::WebGL2(ref context)) = *self.context.borrow() {
|
|
||||||
Some(DomRoot::from_ref(&*context))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the base WebGLRenderingContext for WebGL or WebGL 2, if exists.
|
/// 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.
|
// TODO: add a method in WebGL2RenderingContext to get the pixels.
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
None => {
|
None => vec![0; size.height as usize * size.width as usize * 4]
|
||||||
repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Some((data, size))
|
Some((data, size))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue