diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 748f3746c6e..9a6443c052f 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -143,6 +143,10 @@ impl CanvasRenderingContext2D { .unwrap(); } + pub fn ipc_renderer(&self) -> IpcSender { + self.ipc_renderer.clone() + } + fn mark_as_dirty(&self) { let canvas = self.canvas.root(); let node = NodeCast::from_ref(canvas.r()); @@ -245,6 +249,7 @@ impl CanvasRenderingContext2D { // Pixels come from cache in BGRA order and drawImage expects RGBA so we // have to swap the color values byte_swap(&mut data); + let size = Size2D::new(size.width as f64, size.height as f64); (data, size) }, None => return Err(InvalidState), @@ -338,7 +343,7 @@ impl CanvasRenderingContext2D { fn fetch_image_data(&self, image_element: &HTMLImageElement) - -> Option<(Vec, Size2D)> { + -> Option<(Vec, Size2D)> { let url = match image_element.get_url() { Some(url) => url, None => return None, @@ -351,7 +356,7 @@ impl CanvasRenderingContext2D { } }; - let image_size = Size2D::new(img.width as f64, img.height as f64); + let image_size = Size2D::new(img.width as i32, img.height as i32); let image_data = match img.format { PixelFormat::RGBA8 => img.bytes.to_vec(), PixelFormat::K8 => panic!("K8 color type not supported"), @@ -362,28 +367,6 @@ impl CanvasRenderingContext2D { Some((image_data, image_size)) } - // TODO(ecoal95): Move this to `HTMLCanvasElement`, and support WebGL contexts - fn fetch_canvas_data(&self, - canvas_element: &HTMLCanvasElement, - source_rect: Rect) - -> Option<(Vec, Size2D)> { - let context = match canvas_element.get_or_init_2d_context() { - Some(context) => context, - None => return None, - }; - - let canvas_size = canvas_element.get_size(); - let image_size = Size2D::new(canvas_size.width as f64, canvas_size.height as f64); - - let renderer = context.r().get_ipc_renderer(); - let (sender, receiver) = ipc::channel::>().unwrap(); - // Reads pixels from source canvas - renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::GetImageData(source_rect.to_i32(), - image_size, sender))).unwrap(); - - Some((receiver.recv().unwrap(), image_size)) - } - #[inline] fn request_image_from_cache(&self, url: Url) -> ImageResponse { let canvas = self.canvas.root(); @@ -975,26 +958,20 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { } }, HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(canvas) => { - let canvas_element = canvas.r(); + let canvas = canvas.r(); + let _ = canvas.get_or_init_2d_context(); - let canvas_size = canvas_element.get_size(); - let source_rect = Rect::new(Point2D::zero(), - Size2D::new(canvas_size.width as f64, canvas_size.height as f64)); - - match self.fetch_canvas_data(&canvas_element, source_rect) { + match canvas.fetch_all_data() { Some((data, size)) => (data, size), None => return Err(InvalidState), } }, HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(context) => { let canvas = context.r().Canvas(); - let canvas_element = canvas.r(); + let canvas = canvas.r(); + let _ = canvas.get_or_init_2d_context(); - let canvas_size = canvas_element.get_size(); - let source_rect = Rect::new(Point2D::zero(), - Size2D::new(canvas_size.width as f64, canvas_size.height as f64)); - - match self.fetch_canvas_data(&canvas_element, source_rect) { + match canvas.fetch_all_data() { Some((data, size)) => (data, size), None => return Err(InvalidState), } @@ -1004,7 +981,7 @@ impl CanvasRenderingContext2DMethods for CanvasRenderingContext2D { if let Ok(rep) = RepetitionStyle::from_str(&repetition) { return Ok(CanvasPattern::new(self.global.root().r(), image_data, - Size2D::new(image_size.width as i32, image_size.height as i32), + image_size, rep)); } return Err(Syntax); diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 3c254ffa330..7677f1afcaf 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use canvas_traits::CanvasMsg; +use canvas_traits::{CanvasMsg, FromLayoutMsg}; use dom::attr::Attr; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods; @@ -22,11 +22,12 @@ use dom::node::{Node, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext}; use euclid::size::Size2D; -use ipc_channel::ipc::IpcSender; +use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{HandleValue, JSContext}; use offscreen_gl_context::GLContextAttributes; use std::cell::Cell; use std::default::Default; +use std::iter::repeat; use util::str::{DOMString, parse_unsigned_integer}; const DEFAULT_WIDTH: u32 = 300; @@ -114,27 +115,23 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS { #[allow(unsafe_code)] unsafe fn get_renderer_id(&self) -> Option { let ref canvas = *self.unsafe_get(); - if let Some(context) = canvas.context.get() { + canvas.context.get().map(|context| { match context { - CanvasContext::Context2d(context) => Some(context.to_layout().get_renderer_id()), - CanvasContext::WebGL(context) => Some(context.to_layout().get_renderer_id()), + CanvasContext::Context2d(context) => context.to_layout().get_renderer_id(), + CanvasContext::WebGL(context) => context.to_layout().get_renderer_id(), } - } else { - None - } + }) } #[allow(unsafe_code)] unsafe fn get_ipc_renderer(&self) -> Option> { let ref canvas = *self.unsafe_get(); - if let Some(context) = canvas.context.get() { + canvas.context.get().map(|context| { match context { - CanvasContext::Context2d(context) => Some(context.to_layout().get_ipc_renderer()), - CanvasContext::WebGL(context) => Some(context.to_layout().get_ipc_renderer()), + CanvasContext::Context2d(context) => context.to_layout().get_ipc_renderer(), + CanvasContext::WebGL(context) => context.to_layout().get_ipc_renderer(), } - } else { - None - } + }) } #[allow(unsafe_code)] @@ -150,6 +147,15 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS { impl HTMLCanvasElement { + pub fn ipc_renderer(&self) -> Option> { + self.context.get().map(|context| { + match context { + CanvasContext::Context2d(context) => context.root().r().ipc_renderer(), + CanvasContext::WebGL(context) => context.root().r().ipc_renderer(), + } + }) + } + pub fn get_or_init_2d_context(&self) -> Option> { if self.context.get().is_none() { let window = window_from_node(self); @@ -200,6 +206,26 @@ impl HTMLCanvasElement { pub fn is_valid(&self) -> bool { self.height.get() != 0 && self.width.get() != 0 } + + pub fn fetch_all_data(&self) -> Option<(Vec, Size2D)> { + let size = self.get_size(); + + if size.width == 0 || size.height == 0 { + return None + } + + let data = if let Some(renderer) = self.ipc_renderer() { + let (sender, receiver) = ipc::channel().unwrap(); + let msg = CanvasMsg::FromLayout(FromLayoutMsg::SendPixelContents(sender)); + renderer.send(msg).unwrap(); + + receiver.recv().unwrap().to_vec() + } else { + repeat(0xffu8).take((size.height as usize) * (size.width as usize) * 4).collect() + }; + + Some((data, size)) + } } impl HTMLCanvasElementMethods for HTMLCanvasElement { diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 93398ffee56..cd71f64d077 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -124,6 +124,27 @@ impl WebGLRenderingContext { self.ipc_renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap(); } + pub fn ipc_renderer(&self) -> IpcSender { + self.ipc_renderer.clone() + } + + pub fn webgl_error(&self, err: WebGLError) { + // If an error has been detected no further errors must be + // recorded until `getError` has been called + if self.last_error.get().is_none() { + self.last_error.set(Some(err)); + } + } + + pub fn bound_texture_for(&self, target: u32) -> Option> { + match target { + constants::TEXTURE_2D => self.bound_texture_2d.get(), + constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(), + + _ => unreachable!(), + } + } + fn mark_as_dirty(&self) { let canvas = self.canvas.root(); let node = NodeCast::from_ref(canvas.r()); @@ -845,8 +866,15 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { }, // TODO(ecoal95): Getting canvas data is implemented in CanvasRenderingContext2D, but // we need to refactor it moving it to `HTMLCanvasElement` and supporting WebGLContext - ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(_rooted_canvas) - => unimplemented!(), + ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLCanvasElement(canvas) => { + let canvas = canvas.r(); + if let Some((mut data, size)) = canvas.fetch_all_data() { + byte_swap(&mut data); + (data, size) + } else { + return + } + }, ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement::eHTMLVideoElement(_rooted_video) => unimplemented!(), }; @@ -898,26 +926,6 @@ impl WebGLRenderingContextMethods for WebGLRenderingContext { } } - -impl WebGLRenderingContext { - pub fn webgl_error(&self, err: WebGLError) { - // If an error has been detected no further errors must be - // recorded until `getError` has been called - if self.last_error.get().is_none() { - self.last_error.set(Some(err)); - } - } - - pub fn bound_texture_for(&self, target: u32) -> Option> { - match target { - constants::TEXTURE_2D => self.bound_texture_2d.get(), - constants::TEXTURE_CUBE_MAP => self.bound_texture_cube_map.get(), - - _ => unreachable!(), - } - } -} - pub trait LayoutCanvasWebGLRenderingContextHelpers { #[allow(unsafe_code)] unsafe fn get_renderer_id(&self) -> usize; diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 694fd477774..fbcb78bc891 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -402,6 +402,9 @@ prefs:"layout.viewport.enabled" == viewport_rule.html viewport_rule_ref.html == webgl-context/clearcolor.html webgl-context/clearcolor_ref.html == webgl-context/draw_arrays_simple.html webgl-context/draw_arrays_simple_ref.html +== webgl-context/tex_image_2d_canvas.html webgl-context/tex_image_2d_canvas_ref.html +== webgl-context/tex_image_2d_canvas2d.html webgl-context/tex_image_2d_canvas_ref.html +== webgl-context/tex_image_2d_canvas_no_context.html webgl-context/tex_image_2d_canvas_no_context_ref.html == webgl-context/tex_image_2d_simple.html webgl-context/tex_image_2d_simple_ref.html flaky_macos == white_space_intrinsic_sizes_a.html white_space_intrinsic_sizes_ref.html diff --git a/tests/ref/webgl-context/tex_image_2d_canvas.html b/tests/ref/webgl-context/tex_image_2d_canvas.html new file mode 100644 index 00000000000..0b21aad94bf --- /dev/null +++ b/tests/ref/webgl-context/tex_image_2d_canvas.html @@ -0,0 +1,111 @@ + + + + WebGL texture test + + + + + + + + diff --git a/tests/ref/webgl-context/tex_image_2d_canvas2d.html b/tests/ref/webgl-context/tex_image_2d_canvas2d.html new file mode 100644 index 00000000000..e360f9ceddf --- /dev/null +++ b/tests/ref/webgl-context/tex_image_2d_canvas2d.html @@ -0,0 +1,111 @@ + + + + WebGL texture test + + + + + + + + diff --git a/tests/ref/webgl-context/tex_image_2d_canvas_no_context.html b/tests/ref/webgl-context/tex_image_2d_canvas_no_context.html new file mode 100644 index 00000000000..157773ff10d --- /dev/null +++ b/tests/ref/webgl-context/tex_image_2d_canvas_no_context.html @@ -0,0 +1,111 @@ + + + + WebGL texture test + + + + + + + + diff --git a/tests/ref/webgl-context/tex_image_2d_canvas_no_context_ref.html b/tests/ref/webgl-context/tex_image_2d_canvas_no_context_ref.html new file mode 100644 index 00000000000..36cb7914e64 --- /dev/null +++ b/tests/ref/webgl-context/tex_image_2d_canvas_no_context_ref.html @@ -0,0 +1,26 @@ + + +WebGL texture test + + +
diff --git a/tests/ref/webgl-context/tex_image_2d_canvas_ref.html b/tests/ref/webgl-context/tex_image_2d_canvas_ref.html new file mode 100644 index 00000000000..2015696fc30 --- /dev/null +++ b/tests/ref/webgl-context/tex_image_2d_canvas_ref.html @@ -0,0 +1,11 @@ + + +WebGL texture test + + +
diff --git a/tests/wpt/metadata/2dcontext/compositing/2d.composite.globalAlpha.canvaspattern.html.ini b/tests/wpt/metadata/2dcontext/compositing/2d.composite.globalAlpha.canvaspattern.html.ini deleted file mode 100644 index 004da3989cd..00000000000 --- a/tests/wpt/metadata/2dcontext/compositing/2d.composite.globalAlpha.canvaspattern.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.composite.globalAlpha.canvaspattern.html] - type: testharness - [Canvas test: 2d.composite.globalAlpha.canvaspattern] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/fill-and-stroke-styles/2d.pattern.basic.zerocanvas.html.ini b/tests/wpt/metadata/2dcontext/fill-and-stroke-styles/2d.pattern.basic.zerocanvas.html.ini deleted file mode 100644 index 3625c104df0..00000000000 --- a/tests/wpt/metadata/2dcontext/fill-and-stroke-styles/2d.pattern.basic.zerocanvas.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.pattern.basic.zerocanvas.html] - type: testharness - [Canvas test: 2d.pattern.basic.zerocanvas] - expected: FAIL -