diff --git a/components/canvas/canvas_paint_task.rs b/components/canvas/canvas_paint_task.rs index c8781419f10d..4822fd487509 100644 --- a/components/canvas/canvas_paint_task.rs +++ b/components/canvas/canvas_paint_task.rs @@ -16,7 +16,6 @@ use util::vec::byte_swap; use cssparser::RGBA; use std::borrow::ToOwned; -use std::ops::Add; use std::sync::mpsc::{channel, Sender}; #[derive(Clone)] @@ -27,6 +26,8 @@ pub enum CanvasMsg { BeginPath, ClosePath, Fill, + DrawImage(Vec, Rect, Rect, bool), + DrawImageSelf(Size2D, Rect, Rect, bool), MoveTo(Point2D), LineTo(Point2D), QuadraticCurveTo(Point2D, Point2D), @@ -38,10 +39,140 @@ pub enum CanvasMsg { Recreate(Size2D), SendPixelContents(Sender>), GetImageData(Rect, Size2D, Sender>), - PutImageData(Vec, Rect, Option>, Size2D), + PutImageData(Vec, Rect, Option>), Close, } +impl<'a> CanvasPaintTask<'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 + fn read_pixels(&self, read_rect: Rect, canvas_size: Size2D) -> Vec{ + let canvas_rect = Rect(Point2D(0i32, 0i32), canvas_size); + let src_read_rect = canvas_rect.intersection(&read_rect).unwrap_or(Rect::zero()); + + let mut image_data = Vec::new(); + if src_read_rect.is_empty() || canvas_size.width <= 0 && canvas_size.height <= 0 { + return image_data; + } + + 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 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; + //copy the data to the destination vector + for _ in range(0, src_read_rect.size.height) { + let row = &src_data[src .. src + (4 * src_read_rect.size.width) as usize]; + image_data.push_all(row); + src += stride as usize; + } + + image_data + } + + /// It writes image data to the canvas + /// source_rect: the area of the image data to be written + /// dest_rect: The area of the canvas where the imagedata will be copied + /// smoothing_enabled: if smoothing is applied to the copied pixels + fn write_pixels(&self, imagedata: &Vec, + image_size: Size2D, + source_rect: Rect, + dest_rect: Rect, + smoothing_enabled: bool) { + // From spec https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage + // When scaling up, if the imageSmoothingEnabled attribute is set to true, the user agent should attempt + // to apply a smoothing algorithm to the image data when it is scaled. + // Otherwise, the image must be rendered using nearest-neighbor interpolation. + let filter = if smoothing_enabled { + Filter::Linear + } else { + Filter::Point + }; + + let source_surface = self.drawtarget.create_source_surface_from_data(imagedata.as_slice(), + image_size, image_size.width * 4, SurfaceFormat::B8G8R8A8); + + let draw_surface_options = DrawSurfaceOptions::new(filter, true); + let draw_options = DrawOptions::new(1.0f64 as AzFloat, 0); + + self.drawtarget.draw_surface(source_surface, + dest_rect.to_azfloat(), + source_rect.to_azfloat(), + draw_surface_options, draw_options); + } + + /// dirty_rect: original dirty_rect provided by the putImageData call + /// image_data_rect: the area of the image to be copied + /// Result: It retuns the modified dirty_rect by the rules described in + /// the spec https://html.spec.whatwg.org/#dom-context-2d-putimagedata + fn calculate_dirty_rect(&self, + mut dirty_rect: Rect, + image_data_rect: Rect) -> Rect{ + // 1) If dirtyWidth is negative, + // let dirtyX be dirtyX+dirtyWidth, + // and let dirtyWidth be equal to the absolute magnitude of dirtyWidth. + if dirty_rect.size.width < 0 { + dirty_rect.origin.x = dirty_rect.origin.x + dirty_rect.size.width; + dirty_rect.size.width = -dirty_rect.size.width; + } + + // 2) If dirtyHeight is negative, let dirtyY be dirtyY+dirtyHeight, + // and let dirtyHeight be equal to the absolute magnitude of dirtyHeight. + if dirty_rect.size.height < 0 { + dirty_rect.origin.y = dirty_rect.origin.y + dirty_rect.size.height; + dirty_rect.size.height = -dirty_rect.size.height; + } + + // 3) If dirtyX is negative, let dirtyWidth be dirtyWidth+dirtyX, and let dirtyX be zero. + if dirty_rect.origin.x < 0 { + dirty_rect.size.width += dirty_rect.origin.x; + dirty_rect.origin.x = 0; + } + + // 3) If dirtyY is negative, let dirtyHeight be dirtyHeight+dirtyY, and let dirtyY be zero. + if dirty_rect.origin.y < 0 { + dirty_rect.size.height += dirty_rect.origin.y; + dirty_rect.origin.y = 0; + } + + // 4) If dirtyX+dirtyWidth is greater than the width attribute of the imagedata argument, + // let dirtyWidth be the value of that width attribute, minus the value of dirtyX. + if dirty_rect.origin.x + dirty_rect.size.width > image_data_rect.size.width { + dirty_rect.size.width = image_data_rect.size.width - dirty_rect.origin.x; + } + + // 4) If dirtyY+dirtyHeight is greater than the height attribute of the imagedata argument, + // let dirtyHeight be the value of that height attribute, minus the value of dirtyY. + if dirty_rect.origin.y + dirty_rect.size.height > image_data_rect.size.height { + dirty_rect.size.height = image_data_rect.size.height - dirty_rect.origin.y; + } + + dirty_rect + } + + /// It writes an image to the destination canvas + /// imagedata: Pixel information of the image to be written + /// source_rect: Area of the source image to be copied + /// dest_rect: Area of the destination canvas where the pixels will be copied + /// smoothing_enabled: It determines if smoothing is applied to the image result + fn write_image(&self, mut imagedata: Vec, + source_rect: Rect, dest_rect: Rect, smoothing_enabled: bool) { + if imagedata.len() == 0 { + return + } + // Image data already contains the portion of the image we want to draw + // so the source rect corresponds to the whole area of the copied imagedata + let source_rect = Rect(Point2D(0i32, 0i32), source_rect.size); + // rgba -> bgra + byte_swap(imagedata.as_mut_slice()); + self.write_pixels(&imagedata, source_rect.size, source_rect, dest_rect, smoothing_enabled); + } + +} + pub struct CanvasPaintTask<'a> { drawtarget: DrawTarget, fill_style: Pattern, @@ -80,6 +211,12 @@ impl<'a> CanvasPaintTask<'a> { CanvasMsg::BeginPath => painter.begin_path(), CanvasMsg::ClosePath => painter.close_path(), CanvasMsg::Fill => painter.fill(), + CanvasMsg::DrawImage(imagedata, dest_rect, source_rect, smoothing_enabled) => { + painter.draw_image(imagedata, dest_rect, source_rect, smoothing_enabled) + } + CanvasMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled) => { + painter.draw_image_self(image_size, dest_rect, source_rect, smoothing_enabled) + } CanvasMsg::MoveTo(ref point) => painter.move_to(point), CanvasMsg::LineTo(ref point) => painter.line_to(point), CanvasMsg::QuadraticCurveTo(ref cp, ref pt) => { @@ -97,8 +234,8 @@ impl<'a> CanvasPaintTask<'a> { CanvasMsg::Recreate(size) => painter.recreate(size), CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan), CanvasMsg::GetImageData(dest_rect, canvas_size, chan) => painter.get_image_data(dest_rect, canvas_size, chan), - CanvasMsg::PutImageData(imagedata, image_data_rect, dirty_rect, canvas_size) - => painter.put_image_data(imagedata, image_data_rect, dirty_rect, canvas_size), + CanvasMsg::PutImageData(imagedata, image_data_rect, dirty_rect) + => painter.put_image_data(imagedata, image_data_rect, dirty_rect), CanvasMsg::Close => break, } } @@ -147,6 +284,21 @@ impl<'a> CanvasPaintTask<'a> { }; } + fn draw_image(&self, imagedata: Vec, dest_rect: Rect, + source_rect: Rect, smoothing_enabled: bool) { + self.write_image(imagedata, source_rect, dest_rect, smoothing_enabled); + } + + fn draw_image_self(&self, image_size: Size2D, + dest_rect: Rect, source_rect: Rect, + smoothing_enabled: bool) { + // Reads pixels from source image + // In this case source and target are the same canvas + let imagedata = self.read_pixels(source_rect, image_size); + // Writes on target canvas + self.write_image(imagedata, source_rect, dest_rect, smoothing_enabled); + } + fn move_to(&self, point: &Point2D) { self.path_builder.move_to(*point) } @@ -220,36 +372,16 @@ impl<'a> CanvasPaintTask<'a> { dest_rect.size.height = 1; } - let canvas_rect = Rect(Point2D(0i32, 0i32), canvas_size); - let src_read_rect = canvas_rect.intersection(&dest_rect).unwrap_or(Rect::zero()); - - let mut dest_data = Vec::new(); - //load the canvas data to the source vector - if !src_read_rect.is_empty() && canvas_size.width != 0 && canvas_size.height != 0 { - 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 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; - //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]; - dest_data.push_all(row); - src += stride as usize; - } - } + let mut dest_data = self.read_pixels(dest_rect, canvas_size); + // bgra -> rgba byte_swap(dest_data.as_mut_slice()); chan.send(dest_data).unwrap(); } - fn put_image_data(&mut self, mut imagedata: Vec, image_data_rect: Rect, - dirty_rect: Option>, canvas_size: Size2D) { + fn put_image_data(&mut self, mut imagedata: Vec, + image_data_rect: Rect, + dirty_rect: Option>) { if image_data_rect.size.width <= 0 || image_data_rect.size.height <= 0 { return @@ -259,46 +391,37 @@ impl<'a> CanvasPaintTask<'a> { // rgba -> bgra byte_swap(imagedata.as_mut_slice()); - let new_image_data_rect = Rect(Point2D(0i32, 0i32), - Size2D(image_data_rect.size.width, image_data_rect.size.height)); - - let new_dirty_rect = match dirty_rect { - Some(mut dirty_rect) => { - if dirty_rect.size.width < 0 { - dirty_rect.origin.x = dirty_rect.origin.x + dirty_rect.size.width; - dirty_rect.size.width = -dirty_rect.size.width; - } - if dirty_rect.size.height < 0 { - dirty_rect.origin.y = dirty_rect.origin.y + dirty_rect.size.height; - dirty_rect.size.height = -dirty_rect.size.height; - } - new_image_data_rect.intersection(&dirty_rect) - }, - None => Some(new_image_data_rect) + let image_rect = Rect(Point2D(0i32, 0i32), + Size2D(image_data_rect.size.width, image_data_rect.size.height)); + + // Dirty rectangle defines the area of the source image to be copied + // on the destination canvas + let source_rect = match dirty_rect { + Some(dirty_rect) => + self.calculate_dirty_rect(dirty_rect, image_data_rect), + // If no dirty area is provided we consider the whole source image + // as the area to be copied to the canvas + None => image_rect, }; - if let Some(new_dirty_rect) = new_dirty_rect { - let moved_dirty_rect = Rect(new_dirty_rect.origin.add(image_data_rect.origin), - new_dirty_rect.size).intersection(&Rect(Point2D(0i32, 0i32), - canvas_size)).unwrap_or(Rect::zero()); - if moved_dirty_rect.is_empty() { - return - } - - let source_surface = self.drawtarget.create_source_surface_from_data(&imagedata, - image_data_rect.size, image_data_rect.size.width * 4, SurfaceFormat::B8G8R8A8); - - let draw_surface_options = DrawSurfaceOptions::new(Filter::Linear, true); - let draw_options = DrawOptions::new(1.0f64 as AzFloat, 0); - - self.drawtarget.draw_surface(source_surface, - Rect(Point2D(moved_dirty_rect.origin.x as AzFloat, moved_dirty_rect.origin.y as AzFloat), - Size2D(moved_dirty_rect.size.width as AzFloat, moved_dirty_rect.size.height as AzFloat)), - Rect(Point2D((moved_dirty_rect.origin.x - image_data_rect.origin.x) as AzFloat, - (moved_dirty_rect.origin.y - image_data_rect.origin.y) as AzFloat), - Size2D(moved_dirty_rect.size.width as AzFloat, moved_dirty_rect.size.height as AzFloat)), - draw_surface_options, draw_options); + // 5) If either dirtyWidth or dirtyHeight is negative or zero, + // stop without affecting any bitmaps + if source_rect.size.width <= 0 || source_rect.size.height <= 0 { + return } + + // 6) For all integer values of x and y where dirtyX ≤ x < dirty + // X+dirtyWidth and dirtyY ≤ y < dirtyY+dirtyHeight, copy the + // four channels of the pixel with coordinate (x, y) in the imagedata + // data structure's Canvas Pixel ArrayBuffer to the pixel with coordinate + // (dx+x, dy+y) in the rendering context's scratch bitmap. + // It also clips the destination rectangle to the canvas area + let dest_rect = Rect( + Point2D(image_data_rect.origin.x + source_rect.origin.x, + image_data_rect.origin.y + source_rect.origin.y), + Size2D(source_rect.size.width, source_rect.size.height)); + + self.write_pixels(&imagedata, image_data_rect.size, source_rect, dest_rect, true) } } @@ -404,3 +527,14 @@ impl FillOrStrokeStyle { } } } + +pub trait ToAzFloat { + fn to_azfloat(&self) -> Rect; +} + +impl ToAzFloat for Rect { + fn to_azfloat(&self) -> Rect { + Rect(Point2D(self.origin.x as AzFloat, self.origin.y as AzFloat), + Size2D(self.size.width as AzFloat, self.size.height as AzFloat)) + } +} diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 4c2e05b4b9ec..58f3b51ab05b 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -6,6 +6,7 @@ use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasWindingRule; use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods; +use dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrCanvasRenderingContext2D; use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern; use dom::bindings::error::Error::{IndexSize, TypeError}; use dom::bindings::error::Fallible; @@ -37,6 +38,7 @@ pub struct CanvasRenderingContext2D { global: GlobalField, renderer: Sender, canvas: JS, + image_smoothing_enabled: Cell, stroke_color: Cell, fill_color: Cell, transform: Cell>, @@ -56,6 +58,7 @@ impl CanvasRenderingContext2D { global: GlobalField::from_rooted(&global), renderer: CanvasPaintTask::start(size), canvas: JS::from_rooted(canvas), + image_smoothing_enabled: Cell::new(true), stroke_color: Cell::new(black), fill_color: Cell::new(black), transform: Cell::new(Matrix2D::identity()), @@ -75,6 +78,120 @@ impl CanvasRenderingContext2D { fn update_transform(&self) { self.renderer.send(CanvasMsg::SetTransform(self.transform.get())).unwrap() } + + // It is used by DrawImage to calculate the size of the source and destination rectangles based + // on the drawImage call arguments + // source rectangle = area of the original image to be copied + // destination rectangle = area of the destination canvas where the source image is going to be drawn + fn adjust_source_dest_rects(&self, + canvas: JSRef, + sx: f64, sy: f64, sw: f64, sh: f64, + dx: f64, dy: f64, dw: f64, dh: f64) -> (Rect, Rect) { + let image_size = canvas.get_size(); + let image_rect = Rect(Point2D(0f64, 0f64), + Size2D(image_size.width as f64, image_size.height as f64)); + + // The source rectangle is the rectangle whose corners are the four points (sx, sy), + // (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh). + let source_rect = Rect(Point2D(sx, sy), + Size2D(sw, sh)); + + // When the source rectangle is outside the source image, + // the source rectangle must be clipped to the source image + let source_rect_clipped = source_rect.intersection(&image_rect).unwrap_or(Rect::zero()); + + // Width and height ratios between the non clipped and clipped source rectangles + let width_ratio: f64 = source_rect_clipped.size.width / source_rect.size.width; + let height_ratio: f64 = source_rect_clipped.size.height / source_rect.size.height; + + // When the source rectangle is outside the source image, + // the destination rectangle must be clipped in the same proportion. + let dest_rect_width_scaled: f64 = dw * width_ratio; + let dest_rect_height_scaled: f64 = dh * height_ratio; + + // The destination rectangle is the rectangle whose corners are the four points (dx, dy), + // (dx+dw, dy), (dx+dw, dy+dh), (dx, dy+dh). + let dest_rect = Rect(Point2D(dx.to_i32().unwrap(), + dy.to_i32().unwrap()), + Size2D(dest_rect_width_scaled.to_i32().unwrap(), + dest_rect_height_scaled.to_i32().unwrap())); + + let source_rect = Rect(Point2D(source_rect_clipped.origin.x.to_i32().unwrap(), + source_rect_clipped.origin.y.to_i32().unwrap()), + Size2D(source_rect_clipped.size.width.to_i32().unwrap(), + source_rect_clipped.size.height.to_i32().unwrap())); + + return (source_rect, dest_rect) + } + + // + // drawImage coordinates explained + // + // Source Image Destination Canvas + // +-------------+ +-------------+ + // | | | | + // |(sx,sy) | |(dx,dy) | + // | +----+ | | +----+ | + // | | | | | | | | + // | | |sh |---->| | |dh | + // | | | | | | | | + // | +----+ | | +----+ | + // | sw | | dw | + // | | | | + // +-------------+ +-------------+ + // + // + // The rectangle (sx, sy, sw, sh) from the source image + // is copied on the rectangle (dx, dy, dh, dw) of the destination canvas + // + // https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage + fn draw_html_canvas_element(&self, + canvas: JSRef, + sx: f64, sy: f64, sw: f64, sh: f64, + dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { + + // 1. Check the usability of the image argument + if !canvas.is_valid() { + return Ok(()) + } + + // 2. Establish the source and destination rectangles + let (source_rect, dest_rect) = self.adjust_source_dest_rects(canvas, sx, sy, sw, sh, dx, dy, dw, dh); + + if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) { + return Err(IndexSize) + } + + let smoothing_enabled = self.image_smoothing_enabled.get(); + let canvas_size = canvas.get_size(); + + // If the source and target canvas are the same + let msg = if self.canvas.root().r() == canvas { + CanvasMsg::DrawImageSelf(canvas_size, dest_rect, source_rect, smoothing_enabled) + } else { // Source and target canvases are different + let context = canvas.get_2d_context().root(); + let renderer = context.r().get_renderer(); + let (sender, receiver) = channel::>(); + // Reads pixels from source image + renderer.send(CanvasMsg::GetImageData(source_rect, canvas_size, sender)).unwrap(); + let imagedata = receiver.recv().unwrap(); + // Writes pixels to destination canvas + CanvasMsg::DrawImage(imagedata, dest_rect, source_rect, smoothing_enabled) + }; + + self.renderer.send(msg).unwrap(); + Ok(()) + } +} + +pub trait CanvasRenderingContext2DHelpers { + fn get_renderer(&self) -> Sender; +} + +impl CanvasRenderingContext2DHelpers for CanvasRenderingContext2D { + fn get_renderer(&self) -> Sender { + self.renderer.clone() + } } pub trait LayoutCanvasRenderingContext2DHelpers { @@ -151,6 +268,102 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> self.renderer.send(CanvasMsg::Fill).unwrap(); } + // https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage + fn DrawImage(self, image: HTMLCanvasElementOrCanvasRenderingContext2D, + dx: f64, dy: f64) -> Fallible<()> { + + // From rules described in the spec: + // If the sx, sy, sw, and sh arguments are omitted, they must default to 0, 0, + // the image's intrinsic width in image pixels, + // and the image's intrinsic height in image pixels, respectively + let sx: f64 = 0f64; + let sy: f64 = 0f64; + + match image { + HTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(image) => { + let canvas = image.root(); + let canvas_size = canvas.r().get_size(); + let dw: f64 = canvas_size.width as f64; + let dh: f64 = canvas_size.height as f64; + let sw: f64 = dw; + let sh: f64 = dh; + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + HTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) => { + let image = image.root(); + let context = image.r(); + let canvas = context.Canvas().root(); + let canvas_size = canvas.r().get_size(); + let dw: f64 = canvas_size.width as f64; + let dh: f64 = canvas_size.height as f64; + let sw: f64 = dw; + let sh: f64 = dh; + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + } + } + + // https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage + fn DrawImage_(self, image: HTMLCanvasElementOrCanvasRenderingContext2D, + dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { + + // From rules described in the spec: + // If the sx, sy, sw, and sh arguments are omitted, they must default to 0, 0, + // the image's intrinsic width in image pixels, + // and the image's intrinsic height in image pixels, respectively + let sx: f64 = 0f64; + let sy: f64 = 0f64; + + match image { + HTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(image) => { + let canvas = image.root(); + let canvas_size = canvas.r().get_size(); + let sw: f64 = canvas_size.width as f64; + let sh: f64 = canvas_size.height as f64; + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + HTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) => { + let image = image.root(); + let context = image.r(); + let canvas = context.Canvas().root(); + let canvas_size = canvas.r().get_size(); + let sw: f64 = canvas_size.width as f64; + let sh: f64 = canvas_size.height as f64; + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + } + } + + // https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage + fn DrawImage__(self, image: HTMLCanvasElementOrCanvasRenderingContext2D, + sx: f64, sy: f64, sw: f64, sh: f64, + dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> { + match image { + HTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(image) => { + let canvas = image.root(); + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + HTMLCanvasElementOrCanvasRenderingContext2D::eCanvasRenderingContext2D(image) => { + let image = image.root(); + let context = image.r(); + let canvas = context.Canvas().root(); + return self.draw_html_canvas_element(canvas.r(), + sx, sy, sw, sh, + dx, dy, dw, dh) + } + } + } + fn MoveTo(self, x: f64, y: f64) { self.renderer.send(CanvasMsg::MoveTo(Point2D(x as f32, y as f32))).unwrap(); } @@ -175,6 +388,16 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> start as f32, end as f32, ccw)).unwrap(); } + // https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled + fn ImageSmoothingEnabled(self) -> bool { + self.image_smoothing_enabled.get() + } + + // https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled + fn SetImageSmoothingEnabled(self, value: bool) -> () { + self.image_smoothing_enabled.set(value); + } + fn StrokeStyle(self) -> StringOrCanvasGradientOrCanvasPattern { // FIXME(pcwalton, #4761): This is not spec-compliant. See: // @@ -261,8 +484,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> let data = imagedata.get_data_array(&self.global.root().r()); let image_data_rect = Rect(Point2D(dx.to_i32().unwrap(), dy.to_i32().unwrap()), imagedata.get_size()); let dirty_rect = None; - let canvas_size = self.canvas.root().r().get_size(); - self.renderer.send(CanvasMsg::PutImageData(data, image_data_rect, dirty_rect, canvas_size)).unwrap() + self.renderer.send(CanvasMsg::PutImageData(data, image_data_rect, dirty_rect)).unwrap() } fn PutImageData_(self, imagedata: JSRef, dx: f64, dy: f64, @@ -274,8 +496,7 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> let dirty_rect = Some(Rect(Point2D(dirtyX.to_i32().unwrap(), dirtyY.to_i32().unwrap()), Size2D(dirtyWidth.to_i32().unwrap(), dirtyHeight.to_i32().unwrap()))); - let canvas_size = self.canvas.root().r().get_size(); - self.renderer.send(CanvasMsg::PutImageData(data, image_data_rect, dirty_rect, canvas_size)).unwrap() + self.renderer.send(CanvasMsg::PutImageData(data, image_data_rect, dirty_rect)).unwrap() } fn CreateLinearGradient(self, x0: f64, y0: f64, x1: f64, y1: f64) -> Fallible> { @@ -309,3 +530,8 @@ pub fn parse_color(string: &str) -> Result { } } +// Used by drawImage to determine if a source or destination rectangle is valid +// Origin coordinates and size cannot be negative. Size has to be greater than zero +fn is_rect_valid(rect: Rect) -> bool { + rect.origin.x >= 0 && rect.origin.y >= 0 && rect.size.width > 0 && rect.size.height > 0 +} diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 9c3c11d5dbcc..e4fc68565a31 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -91,12 +91,22 @@ impl LayoutHTMLCanvasElementHelpers for LayoutJS { pub trait HTMLCanvasElementHelpers { fn get_size(&self) -> Size2D; + fn get_2d_context(self) -> Temporary; + fn is_valid(self) -> bool; } impl<'a> HTMLCanvasElementHelpers for JSRef<'a, HTMLCanvasElement> { fn get_size(&self) -> Size2D { Size2D(self.Width() as i32, self.Height() as i32) } + + fn get_2d_context(self) -> Temporary { + self.GetContext(String::from_str("2d")).unwrap() + } + + fn is_valid(self) -> bool { + self.height.get() != 0 && self.width.get() != 0 + } } impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> { diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index 1cc40eb0f3fa..0218600bba1a 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -6,6 +6,12 @@ enum CanvasWindingRule { "nonzero", "evenodd" }; // http://www.whatwg.org/html/#2dcontext +typedef (/* HTMLImageElement or + HTMLVideoElement or */ + HTMLCanvasElement or + CanvasRenderingContext2D /* or + ImageBitmap */) CanvasImageSource; + //[Constructor(optional unsigned long width, unsigned long height), Exposed=Window,Worker] interface CanvasRenderingContext2D { @@ -47,7 +53,7 @@ interface CanvasRenderingContext2D { // attribute DOMString globalCompositeOperation; // (default source-over) // image smoothing - // attribute boolean imageSmoothingEnabled; // (default true) + attribute boolean imageSmoothingEnabled; // (default true) // colours and styles (see also the CanvasDrawingStyles interface) attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black) @@ -101,9 +107,12 @@ interface CanvasRenderingContext2D { //TextMetrics measureText(DOMString text); // drawing images - //void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy); - //void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); - //void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh); + [Throws] + void drawImage(CanvasImageSource image, /* unrestricted */ double dx, /* unrestricted */ double dy); + [Throws] + void drawImage(CanvasImageSource image, /* unrestricted */ double dx, /* unrestricted */ double dy, /* unrestricted */ double dw, /* unrestricted */ double dh); + [Throws] + void drawImage(CanvasImageSource image, /* unrestricted */ double sx, /* unrestricted */ double sy, /* unrestricted */ double sw, /* unrestricted */ double sh, /* unrestricted */ double dx, /* unrestricted */ double dy, /* unrestricted */ double dw, /* unrestricted */ double dh); // hit regions //void addHitRegion(optional HitRegionOptions options); @@ -135,7 +144,7 @@ interface CanvasPathMethods { /*unrestricted*/ double x, /*unrestricted*/ double y); - //void arcTo(double x1, double y1, double x2, double y2, double radius); + //void arcTo(double x1, double y1, double x2, double y2, double radius); // NOT IMPLEMENTED [LenientFloat] void arcTo(double x1, double y1, double x2, double y2, double radiusX, double radiusY, double rotation); //void rect(double x, double y, double w, double h); diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index bc520d62f3ef..750871127ad2 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -898,6 +898,7 @@ dependencies = [ name = "util" version = "0.0.1" dependencies = [ + "azure 0.1.0 (git+https://github.com/servo/rust-azure)", "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)", diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index 1fc0ac21f610..706ca02e9b6d 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -24,6 +24,9 @@ git = "https://github.com/servo/rust-cssparser" [dependencies.selectors] git = "https://github.com/servo/rust-selectors" +[dependencies.azure] +git = "https://github.com/servo/rust-azure" + [dependencies.geom] git = "https://github.com/servo/rust-geom" diff --git a/components/util/lib.rs b/components/util/lib.rs index 620686214679..c9b1c5bb76ab 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -24,6 +24,7 @@ #[macro_use] extern crate log; +extern crate azure; extern crate alloc; #[macro_use] extern crate bitflags; extern crate cssparser; diff --git a/tests/html/test_canvas_drawimage.html b/tests/html/test_canvas_drawimage.html new file mode 100644 index 000000000000..54a7082f9f33 --- /dev/null +++ b/tests/html/test_canvas_drawimage.html @@ -0,0 +1,263 @@ + + + + + + + +

DrawImage canvas to canvas

+ + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_1.html b/tests/ref/2dcontext/drawimage_1.html new file mode 100644 index 000000000000..4c3ab02b123f --- /dev/null +++ b/tests/ref/2dcontext/drawimage_1.html @@ -0,0 +1,39 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_10.html b/tests/ref/2dcontext/drawimage_10.html new file mode 100644 index 000000000000..0430a54d1c0b --- /dev/null +++ b/tests/ref/2dcontext/drawimage_10.html @@ -0,0 +1,42 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_10_ref.html b/tests/ref/2dcontext/drawimage_10_ref.html new file mode 100644 index 000000000000..cd05233b8f75 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_10_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_11.html b/tests/ref/2dcontext/drawimage_11.html new file mode 100644 index 000000000000..b0f148527bea --- /dev/null +++ b/tests/ref/2dcontext/drawimage_11.html @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/tests/ref/2dcontext/drawimage_11_ref.html b/tests/ref/2dcontext/drawimage_11_ref.html new file mode 100644 index 000000000000..970f626dfbd8 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_11_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_12.html b/tests/ref/2dcontext/drawimage_12.html new file mode 100644 index 000000000000..f667f9fa0935 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_12.html @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/tests/ref/2dcontext/drawimage_12_ref.html b/tests/ref/2dcontext/drawimage_12_ref.html new file mode 100644 index 000000000000..190f74f93eff --- /dev/null +++ b/tests/ref/2dcontext/drawimage_12_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_1_ref.html b/tests/ref/2dcontext/drawimage_1_ref.html new file mode 100644 index 000000000000..d0bac45ed5b5 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_1_ref.html @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_2.html b/tests/ref/2dcontext/drawimage_2.html new file mode 100644 index 000000000000..3cca00648c85 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_2.html @@ -0,0 +1,40 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_2_ref.html b/tests/ref/2dcontext/drawimage_2_ref.html new file mode 100644 index 000000000000..72ec289f714b --- /dev/null +++ b/tests/ref/2dcontext/drawimage_2_ref.html @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_3.html b/tests/ref/2dcontext/drawimage_3.html new file mode 100644 index 000000000000..392723bd9f72 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_3.html @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_3_ref.html b/tests/ref/2dcontext/drawimage_3_ref.html new file mode 100644 index 000000000000..3e153f1ca651 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_3_ref.html @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_4.html b/tests/ref/2dcontext/drawimage_4.html new file mode 100644 index 000000000000..a46986a68f03 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_4.html @@ -0,0 +1,42 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_4_ref.html b/tests/ref/2dcontext/drawimage_4_ref.html new file mode 100644 index 000000000000..9a8cc99371cf --- /dev/null +++ b/tests/ref/2dcontext/drawimage_4_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_5.html b/tests/ref/2dcontext/drawimage_5.html new file mode 100644 index 000000000000..3052d66ece81 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_5.html @@ -0,0 +1,42 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_5_ref.html b/tests/ref/2dcontext/drawimage_5_ref.html new file mode 100644 index 000000000000..47dd63ee2b31 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_5_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_6.html b/tests/ref/2dcontext/drawimage_6.html new file mode 100644 index 000000000000..e94efaadfa1d --- /dev/null +++ b/tests/ref/2dcontext/drawimage_6.html @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_6_ref.html b/tests/ref/2dcontext/drawimage_6_ref.html new file mode 100644 index 000000000000..190f74f93eff --- /dev/null +++ b/tests/ref/2dcontext/drawimage_6_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_7.html b/tests/ref/2dcontext/drawimage_7.html new file mode 100644 index 000000000000..9ace085d9790 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_7.html @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_7_ref.html b/tests/ref/2dcontext/drawimage_7_ref.html new file mode 100644 index 000000000000..51b2b276cad5 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_7_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_8.html b/tests/ref/2dcontext/drawimage_8.html new file mode 100644 index 000000000000..d1c1f5bced6e --- /dev/null +++ b/tests/ref/2dcontext/drawimage_8.html @@ -0,0 +1,41 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_8_ref.html b/tests/ref/2dcontext/drawimage_8_ref.html new file mode 100644 index 000000000000..652bf6eb994f --- /dev/null +++ b/tests/ref/2dcontext/drawimage_8_ref.html @@ -0,0 +1,26 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/2dcontext/drawimage_9.html b/tests/ref/2dcontext/drawimage_9.html new file mode 100644 index 000000000000..510f9c923c24 --- /dev/null +++ b/tests/ref/2dcontext/drawimage_9.html @@ -0,0 +1,48 @@ + + + + + + + + + + + diff --git a/tests/ref/2dcontext/drawimage_9_ref.html b/tests/ref/2dcontext/drawimage_9_ref.html new file mode 100644 index 000000000000..b9be7e514f1f --- /dev/null +++ b/tests/ref/2dcontext/drawimage_9_ref.html @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ref/canvas_lineto_a.html b/tests/ref/2dcontext/lineto_a.html similarity index 100% rename from tests/ref/canvas_lineto_a.html rename to tests/ref/2dcontext/lineto_a.html diff --git a/tests/ref/canvas_lineto_ref.html b/tests/ref/2dcontext/lineto_ref.html similarity index 100% rename from tests/ref/canvas_lineto_ref.html rename to tests/ref/2dcontext/lineto_ref.html diff --git a/tests/ref/canvas_transform_a.html b/tests/ref/2dcontext/transform_a.html similarity index 100% rename from tests/ref/canvas_transform_a.html rename to tests/ref/2dcontext/transform_a.html diff --git a/tests/ref/canvas_transform_ref.html b/tests/ref/2dcontext/transform_ref.html similarity index 100% rename from tests/ref/canvas_transform_ref.html rename to tests/ref/2dcontext/transform_ref.html diff --git a/tests/ref/basic.list b/tests/ref/basic.list index d4f0bde917a5..3d322ac5d8c5 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -9,6 +9,21 @@ # Should be == with expected failure: fragment=top != ../html/acid2.html acid2_ref.html +== 2dcontext/drawimage_1.html 2dcontext/drawimage_1_ref.html +== 2dcontext/drawimage_10.html 2dcontext/drawimage_10_ref.html +== 2dcontext/drawimage_11.html 2dcontext/drawimage_11_ref.html +== 2dcontext/drawimage_12.html 2dcontext/drawimage_12_ref.html +== 2dcontext/drawimage_2.html 2dcontext/drawimage_2_ref.html +== 2dcontext/drawimage_3.html 2dcontext/drawimage_3_ref.html +== 2dcontext/drawimage_4.html 2dcontext/drawimage_4_ref.html +== 2dcontext/drawimage_5.html 2dcontext/drawimage_5_ref.html +== 2dcontext/drawimage_6.html 2dcontext/drawimage_6_ref.html +== 2dcontext/drawimage_7.html 2dcontext/drawimage_7_ref.html +== 2dcontext/drawimage_8.html 2dcontext/drawimage_8_ref.html +== 2dcontext/drawimage_9.html 2dcontext/drawimage_9_ref.html +== 2dcontext/lineto_a.html 2dcontext/lineto_ref.html +== 2dcontext/transform_a.html 2dcontext/transform_ref.html + == abs_float_pref_width_a.html abs_float_pref_width_ref.html == acid1_a.html acid1_b.html == acid2_noscroll.html acid2_ref_broken.html @@ -65,10 +80,6 @@ flaky_cpu == append_style_a.html append_style_b.html == box_sizing_sanity_check_a.html box_sizing_sanity_check_ref.html == br.html br-ref.html == canvas_as_block_element_a.html canvas_as_block_element_ref.html -== canvas_linear_gradient_a.html canvas_linear_gradient_ref.html -== canvas_lineto_a.html canvas_lineto_ref.html -== canvas_radial_gradient_a.html canvas_radial_gradient_ref.html -== canvas_transform_a.html canvas_transform_ref.html == case-insensitive-font-family.html case-insensitive-font-family-ref.html == clear_generated_content_table_a.html clear_generated_content_table_ref.html == clip_a.html clip_ref.html diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.canvas.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.canvas.html.ini deleted file mode 100644 index 50084ff0b01e..000000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.canvas.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.drawImage.canvas.html] - type: testharness - [Canvas test: 2d.drawImage.canvas] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.null.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.null.html.ini new file mode 100644 index 000000000000..82a420e5a719 --- /dev/null +++ b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.null.html.ini @@ -0,0 +1,5 @@ +[2d.drawImage.null.html] + type: testharness + [Canvas test: 2d.drawImage.null] + expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.1.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.1.html.ini deleted file mode 100644 index f1466e20fe53..000000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.1.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.drawImage.self.1.html] - type: testharness - [Canvas test: 2d.drawImage.self.1] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.2.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.2.html.ini deleted file mode 100644 index a7e3656486d4..000000000000 --- a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.self.2.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.drawImage.self.2.html] - type: testharness - [Canvas test: 2d.drawImage.self.2] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.wrongtype.html.ini b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.wrongtype.html.ini new file mode 100644 index 000000000000..703d0a05082e --- /dev/null +++ b/tests/wpt/metadata/2dcontext/drawing-images-to-the-canvas/2d.drawImage.wrongtype.html.ini @@ -0,0 +1,5 @@ +[2d.drawImage.wrongtype.html] + type: testharness + [Incorrect image types in drawImage do not match any defined overloads, so WebIDL throws a TypeError] + expected: FAIL + diff --git a/tests/wpt/metadata/2dcontext/image-smoothing/imagesmoothing.html.ini b/tests/wpt/metadata/2dcontext/image-smoothing/imagesmoothing.html.ini deleted file mode 100644 index 0aa58081d2fd..000000000000 --- a/tests/wpt/metadata/2dcontext/image-smoothing/imagesmoothing.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[imagesmoothing.html] - type: testharness - [When the CanvasRenderingContext2D object is created, the attribute must be set to true.] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index a269b210e2f0..6036b185dce2 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -6975,9 +6975,6 @@ [CanvasRenderingContext2D interface: attribute globalCompositeOperation] expected: FAIL - [CanvasRenderingContext2D interface: attribute imageSmoothingEnabled] - expected: FAIL - [CanvasRenderingContext2D interface: operation createPattern(CanvasImageSource,DOMString)] expected: FAIL @@ -7056,9 +7053,6 @@ [CanvasRenderingContext2D interface: operation drawImage(CanvasImageSource,unrestricted double,unrestricted double,unrestricted double,unrestricted double)] expected: FAIL - [CanvasRenderingContext2D interface: operation drawImage(CanvasImageSource,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double)] - expected: FAIL - [CanvasRenderingContext2D interface: operation addHitRegion(HitRegionOptions)] expected: FAIL @@ -7152,9 +7146,6 @@ [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "globalCompositeOperation" with the proper type (14)] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "imageSmoothingEnabled" with the proper type (15)] - expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "strokeStyle" with the proper type (16)] expected: FAIL @@ -7281,21 +7272,9 @@ [CanvasRenderingContext2D interface: calling measureText(DOMString) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "drawImage" with the proper type (49)] - expected: FAIL - - [CanvasRenderingContext2D interface: calling drawImage(CanvasImageSource,unrestricted double,unrestricted double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] - expected: FAIL - - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "drawImage" with the proper type (50)] - expected: FAIL - [CanvasRenderingContext2D interface: calling drawImage(CanvasImageSource,unrestricted double,unrestricted double,unrestricted double,unrestricted double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "drawImage" with the proper type (51)] - expected: FAIL - [CanvasRenderingContext2D interface: calling drawImage(CanvasImageSource,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] expected: FAIL