aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2018-09-18 11:06:51 -0400
committerGitHub <noreply@github.com>2018-09-18 11:06:51 -0400
commit82e94e3b678f2638d62d1ced613f0555805b24e3 (patch)
tree39fb1f7e9f5fb6764274c30603ad6b79e848abb9 /components
parentbdf450336e9c16cb5f6e0d462f866f787dc66e7f (diff)
parent900c3cc6b526616d35994fda526e7166f13cd12d (diff)
downloadservo-82e94e3b678f2638d62d1ced613f0555805b24e3.tar.gz
servo-82e94e3b678f2638d62d1ced613f0555805b24e3.zip
Auto merge of #21723 - servo:webgl, r=jdm
More drive-by WebGL and canvas fixes <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21723) <!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r--components/canvas/canvas_data.rs100
-rw-r--r--components/canvas/canvas_paint_thread.rs32
-rw-r--r--components/canvas_traits/canvas.rs3
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs95
-rw-r--r--components/script/dom/htmlcanvaselement.rs94
-rw-r--r--components/script/dom/htmlimageelement.rs11
-rw-r--r--components/script/dom/webglrenderingcontext.rs87
7 files changed, 207 insertions, 215 deletions
diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs
index 492a8da150a..b1768fe8744 100644
--- a/components/canvas/canvas_data.rs
+++ b/components/canvas/canvas_data.rs
@@ -85,21 +85,6 @@ impl<'a> CanvasData<'a> {
}
}
- pub fn draw_image_self(
- &self,
- image_size: Size2D<f64>,
- dest_rect: Rect<f64>,
- source_rect: Rect<f64>,
- smoothing_enabled: bool
- ) {
- // Reads pixels from source image
- // In this case source and target are the same canvas
- let image_data = self.read_pixels(source_rect.to_i32(), image_size);
-
- // The dimensions of image_data are source_rect.size
- self.draw_image(image_data, source_rect.size, dest_rect, source_rect, smoothing_enabled);
- }
-
pub fn save_context_state(&mut self) {
self.saved_states.push(self.state.clone());
}
@@ -405,51 +390,52 @@ impl<'a> CanvasData<'a> {
}
}
+ #[allow(unsafe_code)]
pub fn send_pixels(&mut self, chan: IpcSender<Option<ByteBuf>>) {
- self.drawtarget.snapshot().get_data_surface().with_data(|element| {
- chan.send(Some(Vec::from(element).into())).unwrap();
- })
+ let data = unsafe { self.drawtarget.snapshot().get_data_surface().data().to_vec() };
+ chan.send(Some(data.into())).unwrap();
}
+ #[allow(unsafe_code)]
pub fn send_data(&mut self, chan: IpcSender<CanvasImageData>) {
- self.drawtarget.snapshot().get_data_surface().with_data(|element| {
- let size = self.drawtarget.get_size();
-
- let descriptor = webrender_api::ImageDescriptor {
- size: webrender_api::DeviceUintSize::new(size.width as u32, size.height as u32),
- stride: None,
- format: webrender_api::ImageFormat::BGRA8,
- offset: 0,
- is_opaque: false,
- allow_mipmaps: false,
- };
- let data = webrender_api::ImageData::Raw(Arc::new(element.into()));
-
- let mut txn = webrender_api::Transaction::new();
-
- match self.image_key {
- Some(image_key) => {
- debug!("Updating image {:?}.", image_key);
- txn.update_image(image_key, descriptor, data, None);
- }
- None => {
- self.image_key = Some(self.webrender_api.generate_image_key());
- debug!("New image {:?}.", self.image_key);
- txn.add_image(self.image_key.unwrap(), descriptor, data, None);
- }
- }
+ let size = self.drawtarget.get_size();
+
+ let descriptor = webrender_api::ImageDescriptor {
+ size: webrender_api::DeviceUintSize::new(size.width as u32, size.height as u32),
+ stride: None,
+ format: webrender_api::ImageFormat::BGRA8,
+ offset: 0,
+ is_opaque: false,
+ allow_mipmaps: false,
+ };
+ let data = webrender_api::ImageData::Raw(Arc::new(
+ unsafe { self.drawtarget.snapshot().get_data_surface().data().into() },
+ ));
- if let Some(image_key) = mem::replace(&mut self.very_old_image_key, self.old_image_key.take()) {
- txn.delete_image(image_key);
+ let mut txn = webrender_api::Transaction::new();
+
+ match self.image_key {
+ Some(image_key) => {
+ debug!("Updating image {:?}.", image_key);
+ txn.update_image(image_key, descriptor, data, None);
+ }
+ None => {
+ self.image_key = Some(self.webrender_api.generate_image_key());
+ debug!("New image {:?}.", self.image_key);
+ txn.add_image(self.image_key.unwrap(), descriptor, data, None);
}
+ }
- self.webrender_api.update_resources(txn.resource_updates);
+ if let Some(image_key) = mem::replace(&mut self.very_old_image_key, self.old_image_key.take()) {
+ txn.delete_image(image_key);
+ }
- let data = CanvasImageData {
- image_key: self.image_key.unwrap(),
- };
- chan.send(data).unwrap();
- })
+ self.webrender_api.update_resources(txn.resource_updates);
+
+ let data = CanvasImageData {
+ image_key: self.image_key.unwrap(),
+ };
+ chan.send(data).unwrap();
}
pub fn image_data(
@@ -606,23 +592,25 @@ impl<'a> CanvasData<'a> {
/// It reads image data from the canvas
/// canvas_size: The size of the canvas we're reading from
/// read_rect: The area of the canvas we want to read from
+ #[allow(unsafe_code)]
pub fn read_pixels(&self, read_rect: Rect<i32>, canvas_size: Size2D<f64>) -> Vec<u8> {
let canvas_size = canvas_size.to_i32();
let canvas_rect = Rect::new(Point2D::new(0i32, 0i32), canvas_size);
let src_read_rect = canvas_rect.intersection(&read_rect).unwrap_or(Rect::zero());
- let mut image_data = vec![];
if src_read_rect.is_empty() || canvas_size.width <= 0 && canvas_size.height <= 0 {
- return image_data;
+ return vec![];
}
let data_surface = self.drawtarget.snapshot().get_data_surface();
- let mut src_data = Vec::new();
- data_surface.with_data(|element| { src_data = element.to_vec(); });
+ let src_data = unsafe { data_surface.data() };
let stride = data_surface.stride();
//start offset of the copyable rectangle
let mut src = (src_read_rect.origin.y * stride + src_read_rect.origin.x * 4) as usize;
+ let mut image_data = Vec::with_capacity(
+ (src_read_rect.size.width * src_read_rect.size.height * 4) as usize,
+ );
//copy the data to the destination vector
for _ in 0..src_read_rect.size.height {
let row = &src_data[src .. src + (4 * src_read_rect.size.width) as usize];
diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs
index 7f0130e8f3e..3e66194e94c 100644
--- a/components/canvas/canvas_paint_thread.rs
+++ b/components/canvas/canvas_paint_thread.rs
@@ -132,34 +132,27 @@ 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,
smoothing_enabled,
)
},
- Canvas2dMsg::DrawImageSelf(
- image_size,
- dest_rect,
- source_rect,
- smoothing_enabled
- ) => {
- self.canvas(canvas_id).draw_image_self(
- image_size,
- dest_rect,
- source_rect,
- smoothing_enabled
- )
- },
Canvas2dMsg::DrawImageInOther(
other_canvas_id,
image_size,
@@ -167,9 +160,10 @@ impl<'a> CanvasPaintThread <'a> {
source_rect,
smoothing
) => {
- let mut image_data = self.canvas(canvas_id).read_pixels(
- source_rect.to_i32(),
- image_size);
+ let image_data = self.canvas(canvas_id).read_pixels(
+ source_rect.to_i32(),
+ image_size,
+ );
self.canvas(other_canvas_id).draw_image(
image_data.into(),
source_rect.size,
diff --git a/components/canvas_traits/canvas.rs b/components/canvas_traits/canvas.rs
index 661bae6b606..a9d47d252a4 100644
--- a/components/canvas_traits/canvas.rs
+++ b/components/canvas_traits/canvas.rs
@@ -38,8 +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),
- DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
+ DrawImage(Option<ByteBuf>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
DrawImageInOther(
CanvasId, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
BeginPath,
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 24d6af0282d..948fd0b9efe 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;
@@ -247,8 +247,7 @@ impl CanvasRenderingContext2D {
canvas.origin_is_clean()
}
CanvasImageSource::HTMLImageElement(image) => {
- let image_origin = image.get_origin().expect("Image's origin is missing");
- image_origin.same_origin(GlobalScope::entry().origin())
+ image.same_origin(GlobalScope::entry().origin())
}
CanvasImageSource::CSSStyleValue(_) => true,
}
@@ -315,17 +314,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 +339,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 +357,28 @@ 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) => {
+ context.send_canvas_2d_msg(Canvas2dMsg::DrawImageInOther(
+ self.get_canvas_id(),
+ image_size,
+ dest_rect,
+ source_rect,
+ smoothing_enabled,
+ ));
+ },
+ _ => 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 +448,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 +1206,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 cfc1ee9a3db..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,42 +175,46 @@ 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)
}
- pub fn get_or_init_webgl_context(
+ #[allow(unsafe_code)]
+ unsafe fn get_or_init_webgl_context(
&self,
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)
}
- pub fn get_or_init_webgl2_context(
+ #[allow(unsafe_code)]
+ unsafe fn get_or_init_webgl2_context(
&self,
cx: *mut JSContext,
options: HandleValue,
@@ -217,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.
@@ -243,11 +246,14 @@ impl HTMLCanvasElement {
}
#[allow(unsafe_code)]
- fn get_gl_attributes(cx: *mut JSContext, options: HandleValue) -> Option<GLContextAttributes> {
- match unsafe { WebGLContextAttributes::new(cx, options) } {
+ unsafe fn get_gl_attributes(
+ cx: *mut JSContext,
+ options: HandleValue,
+ ) -> Option<GLContextAttributes> {
+ match WebGLContextAttributes::new(cx, options) {
Ok(ConversionResult::Success(ref attrs)) => Some(From::from(attrs)),
Ok(ConversionResult::Failure(ref error)) => {
- unsafe { throw_type_error(cx, &error); }
+ throw_type_error(cx, &error);
None
}
_ => {
@@ -284,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))
diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs
index 1c49185ad0d..b665014cdca 100644
--- a/components/script/dom/htmlimageelement.rs
+++ b/components/script/dom/htmlimageelement.rs
@@ -55,7 +55,7 @@ use network_listener::{NetworkListener, PreInvoke};
use num_traits::ToPrimitive;
use script_thread::ScriptThread;
use servo_url::ServoUrl;
-use servo_url::origin::ImmutableOrigin;
+use servo_url::origin::MutableOrigin;
use std::cell::{Cell, RefMut};
use std::char;
use std::collections::HashSet;
@@ -1186,11 +1186,10 @@ impl HTMLImageElement {
useMapElements.map(|mapElem| mapElem.get_area_elements())
}
- pub fn get_origin(&self) -> Option<ImmutableOrigin> {
- match self.current_request.borrow_mut().final_url {
- Some(ref url) => Some(url.origin()),
- None => None
- }
+ pub fn same_origin(&self, origin: &MutableOrigin) -> bool {
+ self.current_request.borrow_mut().final_url.as_ref().map_or(false, |url| {
+ url.scheme() == "data" || url.origin().same_origin(origin)
+ })
}
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 2f3df2adb7c..fadfb42f668 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -13,15 +13,16 @@ use canvas_traits::webgl::WebGLError::*;
use dom::bindings::codegen::Bindings::ANGLEInstancedArraysBinding::ANGLEInstancedArraysConstants;
use dom::bindings::codegen::Bindings::EXTBlendMinmaxBinding::EXTBlendMinmaxConstants;
use dom::bindings::codegen::Bindings::OESVertexArrayObjectBinding::OESVertexArrayObjectConstants;
-use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
+use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding;
+use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::TexImageSource;
+use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextMethods;
use dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
use dom::bindings::codegen::UnionTypes::Float32ArrayOrUnrestrictedFloatSequence;
-use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use dom::bindings::codegen::UnionTypes::Int32ArrayOrLongSequence;
use dom::bindings::conversions::{DerivedFrom, ToJSValConvertible};
-use dom::bindings::error::{Error, ErrorResult};
+use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::{Dom, DomOnceCell, DomRoot, LayoutDom, MutNullableDom};
@@ -30,7 +31,7 @@ use dom::event::{Event, EventBubbles, EventCancelable};
use dom::htmlcanvaselement::HTMLCanvasElement;
use dom::htmlcanvaselement::utils as canvas_utils;
use dom::htmliframeelement::HTMLIFrameElement;
-use dom::node::{Node, NodeDamage, window_from_node};
+use dom::node::{Node, NodeDamage, document_from_node, window_from_node};
use dom::webgl_extensions::WebGLExtensions;
use dom::webgl_validations::WebGLValidator;
use dom::webgl_validations::tex_image_2d::{CommonTexImage2DValidator, CommonTexImage2DValidatorResult};
@@ -76,7 +77,6 @@ pub fn is_gles() -> bool {
cfg!(any(target_os = "android", target_os = "ios"))
}
-type ImagePixelResult = Result<(Vec<u8>, Size2D<i32>, bool), ()>;
pub const MAX_UNIFORM_AND_ATTRIBUTE_LEN: usize = 256;
// From the GLES 2.0.25 spec, page 85:
@@ -490,21 +490,21 @@ impl WebGLRenderingContext {
fn get_image_pixels(
&self,
- source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
- ) -> ImagePixelResult {
- // NOTE: Getting the pixels probably can be short-circuited if some
- // parameter is invalid.
- //
- // Nontheless, since it's the error case, I'm not totally sure the
- // complexity is worth it.
- let (pixels, size, premultiplied) = match source {
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::ImageData(image_data) => {
+ source: TexImageSource,
+ ) -> Fallible<Option<(Vec<u8>, Size2D<i32>, bool)>> {
+ Ok(Some(match source {
+ TexImageSource::ImageData(image_data) => {
(image_data.get_data_array(), image_data.get_size(), false)
},
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLImageElement(image) => {
+ TexImageSource::HTMLImageElement(image) => {
+ let document = document_from_node(&*self.canvas);
+ if !image.same_origin(document.origin()) {
+ return Err(Error::Security);
+ }
+
let img_url = match image.get_url() {
Some(url) => url,
- None => return Err(()),
+ None => return Ok(None),
};
let window = window_from_node(&*self.canvas);
@@ -513,7 +513,7 @@ impl WebGLRenderingContext {
ImageResponse::Loaded(img, _) => img,
ImageResponse::PlaceholderLoaded(_, _) | ImageResponse::None |
ImageResponse::MetadataLoaded(_)
- => return Err(()),
+ => return Ok(None),
};
let size = Size2D::new(img.width as i32, img.height as i32);
@@ -531,22 +531,23 @@ impl WebGLRenderingContext {
// TODO(emilio): Getting canvas data is implemented in CanvasRenderingContext2D,
// but we need to refactor it moving it to `HTMLCanvasElement` and support
// WebGLContext (probably via GetPixels()).
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLCanvasElement(canvas) => {
+ TexImageSource::HTMLCanvasElement(canvas) => {
+ if !canvas.origin_is_clean() {
+ return Err(Error::Security);
+ }
if let Some((mut data, size)) = canvas.fetch_all_data() {
// Pixels got from Canvas have already alpha premultiplied
byte_swap(&mut data);
(data, size, true)
} else {
- return Err(());
+ return Ok(None);
}
},
- ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::HTMLVideoElement(_) => {
+ TexImageSource::HTMLVideoElement(_) => {
// TODO: https://github.com/servo/servo/issues/6711
- return Err(());
+ return Ok(None);
}
- };
-
- return Ok((pixels, size, premultiplied));
+ }))
}
// TODO(emilio): Move this logic to a validator.
@@ -1234,7 +1235,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
constants::UNPACK_ALIGNMENT => {
return UInt32Value(self.texture_unpacking_alignment.get());
},
- _ => {}
+ constants::UNPACK_COLORSPACE_CONVERSION_WEBGL => {
+ let unpack = self.texture_unpacking_settings.get();
+ return UInt32Value(if unpack.contains(TextureUnpacking::CONVERT_COLORSPACE) {
+ constants::BROWSER_DEFAULT_WEBGL
+ } else {
+ constants::NONE
+ });
+ },
+ _ => {},
}
// Handle any MAX_ parameters by retrieving the limits that were stored
@@ -3520,16 +3529,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
internal_format: u32,
format: u32,
data_type: u32,
- source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
+ source: TexImageSource,
) -> ErrorResult {
if !self.extension_manager.is_tex_type_enabled(data_type) {
return Ok(self.webgl_error(InvalidEnum));
}
- // Get pixels from image source
- let (pixels, size, premultiplied) = match self.get_image_pixels(source) {
- Ok((pixels, size, premultiplied)) => (pixels, size, premultiplied),
- Err(_) => return Ok(()),
+ let (pixels, size, premultiplied) = match self.get_image_pixels(source)? {
+ Some(triple) => triple,
+ None => return Ok(()),
};
let validator = TexImage2DValidator::new(self,
@@ -3613,7 +3621,7 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
height: i32,
format: u32,
data_type: u32,
- mut pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
+ pixels: CustomAutoRooterGuard<Option<ArrayBufferView>>,
) -> ErrorResult {
let validator = TexImage2DValidator::new(self, target, level,
format, width, height,
@@ -3644,10 +3652,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
// If data is null, a buffer of sufficient size
// initialized to 0 is passed.
- let buff = match *pixels {
- None => vec![0u8; expected_byte_length as usize],
- Some(ref mut data) => data.to_vec(),
- };
+ let buff = handle_potential_webgl_error!(
+ self,
+ pixels.as_ref().map(|p| p.to_vec()).ok_or(InvalidValue),
+ return Ok(())
+ );
// From the WebGL spec:
//
@@ -3677,11 +3686,11 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext {
yoffset: i32,
format: u32,
data_type: u32,
- source: ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement,
+ source: TexImageSource,
) -> ErrorResult {
- let (pixels, size, premultiplied) = match self.get_image_pixels(source) {
- Ok((pixels, size, premultiplied)) => (pixels, size, premultiplied),
- Err(_) => return Ok(()),
+ let (pixels, size, premultiplied) = match self.get_image_pixels(source)? {
+ Some(triple) => triple,
+ None => return Ok(()),
};
let validator = TexImage2DValidator::new(self, target, level, format,