Skip to content

Commit

Permalink
Add guards to almost CanvasRenderingContext2D methods according to th…
Browse files Browse the repository at this point in the history
…e spec.

http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/ says

"Except where otherwise specified, for the 2D context interface,
 any method call with a numeric argument whose value is infinite or a
 NaN value must be ignored."

We might define the annotation to generate this behavior in glue code.
However, at now, I use this workaround way.
  • Loading branch information
tetsuharuohzeki committed Mar 25, 2015
1 parent 05c6d04 commit bc06526
Showing 1 changed file with 89 additions and 1 deletion.
90 changes: 89 additions & 1 deletion components/script/dom/canvasrenderingcontext2d.rs
Expand Up @@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasWin
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::Error::{IndexSize, NotSupported, TypeError};
use dom::bindings::error::Fallible;
use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary};
Expand Down Expand Up @@ -207,22 +207,44 @@ impl LayoutCanvasRenderingContext2DHelpers for LayoutJS<CanvasRenderingContext2D
}
}

// We add a guard to each of methods by the spec:
// http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/
//
// > Except where otherwise specified, for the 2D context interface,
// > any method call with a numeric argument whose value is infinite or a NaN value must be ignored.
//
// Restricted values are guarded in glue code. Therefore we need not add a guard.
//
// FIXME: this behavior should might be generated by some annotattions to idl.
impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> {
fn Canvas(self) -> Temporary<HTMLCanvasElement> {
Temporary::new(self.canvas)
}

fn Scale(self, x: f64, y: f64) {
if !(x.is_finite() && y.is_finite()) {
return;
}

self.transform.set(self.transform.get().scale(x as f32, y as f32));
self.update_transform()
}

fn Translate(self, x: f64, y: f64) {
if !(x.is_finite() && y.is_finite()) {
return;
}

self.transform.set(self.transform.get().translate(x as f32, y as f32));
self.update_transform()
}

fn Transform(self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
d.is_finite() && e.is_finite() && f.is_finite()) {
return;
}

self.transform.set(self.transform.get().mul(&Matrix2D::new(a as f32,
b as f32,
c as f32,
Expand All @@ -233,6 +255,11 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
}

fn SetTransform(self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) {
if !(a.is_finite() && b.is_finite() && c.is_finite() &&
d.is_finite() && e.is_finite() && f.is_finite()) {
return;
}

self.transform.set(Matrix2D::new(a as f32,
b as f32,
c as f32,
Expand All @@ -243,16 +270,31 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
}

fn FillRect(self, x: f64, y: f64, width: f64, height: f64) {
if !(x.is_finite() && y.is_finite() &&
width.is_finite() && height.is_finite()) {
return;
}

let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32));
self.renderer.send(CanvasMsg::FillRect(rect)).unwrap();
}

fn ClearRect(self, x: f64, y: f64, width: f64, height: f64) {
if !(x.is_finite() && y.is_finite() &&
width.is_finite() && height.is_finite()) {
return;
}

let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32));
self.renderer.send(CanvasMsg::ClearRect(rect)).unwrap();
}

fn StrokeRect(self, x: f64, y: f64, width: f64, height: f64) {
if !(x.is_finite() && y.is_finite() &&
width.is_finite() && height.is_finite()) {
return;
}

let rect = Rect(Point2D(x as f32, y as f32), Size2D(width as f32, height as f32));
self.renderer.send(CanvasMsg::StrokeRect(rect)).unwrap();
}
Expand All @@ -272,6 +314,9 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
// https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-drawimage
fn DrawImage(self, image: HTMLCanvasElementOrCanvasRenderingContext2D,
dx: f64, dy: f64) -> Fallible<()> {
if !(dx.is_finite() && dy.is_finite()) {
return Ok(());
}

// From rules described in the spec:
// If the sx, sy, sw, and sh arguments are omitted, they must default to 0, 0,
Expand Down Expand Up @@ -311,6 +356,10 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
// 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<()> {
if !(dx.is_finite() && dy.is_finite() &&
dw.is_finite() && dh.is_finite()) {
return Ok(());
}

// From rules described in the spec:
// If the sx, sy, sw, and sh arguments are omitted, they must default to 0, 0,
Expand Down Expand Up @@ -347,6 +396,11 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
fn DrawImage__(self, image: HTMLCanvasElementOrCanvasRenderingContext2D,
sx: f64, sy: f64, sw: f64, sh: f64,
dx: f64, dy: f64, dw: f64, dh: f64) -> Fallible<()> {
if !(sx.is_finite() && sy.is_finite() && sw.is_finite() && sh.is_finite() &&
dx.is_finite() && dy.is_finite() && dw.is_finite() && dh.is_finite()) {
return Ok(());
}

match image {
HTMLCanvasElementOrCanvasRenderingContext2D::eHTMLCanvasElement(image) => {
let canvas = image.root();
Expand All @@ -366,19 +420,37 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
}

fn MoveTo(self, x: f64, y: f64) {
if !(x.is_finite() && y.is_finite()) {
return;
}

self.renderer.send(CanvasMsg::MoveTo(Point2D(x as f32, y as f32))).unwrap();
}

fn LineTo(self, x: f64, y: f64) {
if !(x.is_finite() && y.is_finite()) {
return;
}

self.renderer.send(CanvasMsg::LineTo(Point2D(x as f32, y as f32))).unwrap();
}

fn QuadraticCurveTo(self, cpx: f64, cpy: f64, x: f64, y: f64) {
if !(cpx.is_finite() && cpy.is_finite() &&
x.is_finite() && y.is_finite()) {
return;
}

self.renderer.send(CanvasMsg::QuadraticCurveTo(Point2D(cpx as f32, cpy as f32),
Point2D(x as f32, y as f32))).unwrap();
}

fn BezierCurveTo(self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, x: f64, y: f64) {
if !(cp1x.is_finite() && cp1y.is_finite() && cp2x.is_finite() && cp2y.is_finite() &&
x.is_finite() && y.is_finite()) {
return;
}

self.renderer.send(CanvasMsg::BezierCurveTo(Point2D(cp1x as f32, cp1y as f32),
Point2D(cp2x as f32, cp2y as f32),
Point2D(x as f32, y as f32))).unwrap();
Expand Down Expand Up @@ -463,6 +535,10 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
}

fn CreateImageData(self, sw: f64, sh: f64) -> Fallible<Temporary<ImageData>> {
if !(sw.is_finite() && sh.is_finite()) {
return Err(NotSupported);
}

if sw == 0.0 || sh == 0.0 {
return Err(IndexSize)
}
Expand Down Expand Up @@ -491,6 +567,12 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
}

fn PutImageData(self, imagedata: JSRef<ImageData>, dx: Finite<f64>, dy: Finite<f64>) {
// XXX:
// By the spec: http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#dom-context-2d-putimagedata
// "If any of the arguments to the method are infinite or NaN, the method must throw a NotSupportedError exception"
// But this arguments are stricted value, so if they are not finite values,
// they will be TypeError by WebIDL spec before call this methods.

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;
Expand All @@ -499,6 +581,12 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>

fn PutImageData_(self, imagedata: JSRef<ImageData>, dx: Finite<f64>, dy: Finite<f64>,
dirtyX: Finite<f64>, dirtyY: Finite<f64>, dirtyWidth: Finite<f64>, dirtyHeight: Finite<f64>) {
// XXX:
// By the spec: http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#dom-context-2d-putimagedata
// "If any of the arguments to the method are infinite or NaN, the method must throw a NotSupportedError exception"
// But this arguments are stricted value, so if they are not finite values,
// they will be TypeError by WebIDL spec before call this methods.

let data = imagedata.get_data_array(&self.global.root().r());
let image_data_rect = Rect(Point2D(dx.to_i32().unwrap(), dy.to_i32().unwrap()),
Size2D(imagedata.Width().to_i32().unwrap(),
Expand Down

0 comments on commit bc06526

Please sign in to comment.