Implement HTMLCanvasElement#toDataURL

This commit is contained in:
David Zbarsky 2015-10-25 15:20:34 -07:00
parent e49c7a3acb
commit a63c98c24a
31 changed files with 49 additions and 131 deletions

View file

@ -92,3 +92,4 @@ tendril = "0.1.1"
rand = "0.3"
serde = "0.6"
caseless = "0.1.0"
image = "0.4.0"

View file

@ -5,13 +5,16 @@
use canvas_traits::{CanvasMsg, FromLayoutMsg};
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElementMethods;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLContextAttributes;
use dom::bindings::codegen::UnionTypes::CanvasRenderingContext2DOrWebGLRenderingContext;
use dom::bindings::conversions::Castable;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document;
@ -21,9 +24,12 @@ use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use euclid::size::Size2D;
use image::ColorType;
use image::png::PNGEncoder;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes;
use rustc_serialize::base64::{STANDARD, ToBase64};
use std::cell::Cell;
use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer};
@ -246,6 +252,44 @@ impl HTMLCanvasElementMethods for HTMLCanvasElement {
_ => None
}
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-todataurl
fn ToDataURL(&self,
_context: *mut JSContext,
_mime_type: Option<DOMString>,
_arguments: Vec<HandleValue>) -> Fallible<DOMString> {
// Step 1: Check the origin-clean flag (should be set in fillText/strokeText
// and currently unimplemented)
// Step 2.
if self.Width() == 0 || self.Height() == 0 {
return Ok("data:,".to_owned());
}
// Step 3.
if let Some(CanvasContext::Context2d(ref context)) = *self.context.borrow() {
let window = window_from_node(self);
let image_data = try!(context.GetImageData(Finite::wrap(0f64), Finite::wrap(0f64),
Finite::wrap(self.Width() as f64),
Finite::wrap(self.Height() as f64)));
let raw_data = image_data.get_data_array(&GlobalRef::Window(window.r()));
// Only handle image/png for now.
let mime_type = "image/png";
let mut encoded = Vec::new();
{
let encoder: PNGEncoder<&mut Vec<u8>> = PNGEncoder::new(&mut encoded);
encoder.encode(&raw_data, self.Width(), self.Height(), ColorType::RGBA(8)).unwrap();
}
let encoded = encoded.to_base64(STANDARD);
Ok(format!("data:{};base64,{}", mime_type, encoded))
} else {
Err(Error::NotSupported)
}
}
}
impl VirtualMethods for HTMLCanvasElement {

View file

@ -18,6 +18,7 @@ interface HTMLCanvasElement : HTMLElement {
//void setContext(RenderingContext context);
//CanvasProxy transferControlToProxy();
//DOMString toDataURL(optional DOMString type, any... arguments);
[Throws]
DOMString toDataURL(optional DOMString type, any... arguments);
//void toBlob(FileCallback? _callback, optional DOMString type, any... arguments);
};

View file

@ -58,6 +58,7 @@ extern crate euclid;
extern crate fnv;
extern crate html5ever;
extern crate hyper;
extern crate image;
extern crate ipc_channel;
extern crate js;
extern crate libc;

View file

@ -1516,6 +1516,7 @@ dependencies = [
"fnv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"js 0.1.0 (git+https://github.com/servo/rust-mozjs)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -1,5 +0,0 @@
[2d.transformation.scale.zero.html]
type: testharness
[scale() with a scale factor of zero works]
expected: FAIL

View file

@ -2,7 +2,6 @@
type: testharness
disabled:
if os == "mac": https://github.com/servo/servo/issues/8157
[XMLHttpRequest: send() - Document]
expected: FAIL

View file

@ -6042,9 +6042,6 @@
[HTMLCanvasElement interface: operation transferControlToProxy()]
expected: FAIL
[HTMLCanvasElement interface: operation toDataURL(DOMString,any)]
expected: FAIL
[HTMLCanvasElement interface: operation toBlob(FileCallback,DOMString,any)]
expected: FAIL
@ -6063,12 +6060,6 @@
[HTMLCanvasElement interface: document.createElement("canvas") must inherit property "transferControlToProxy" with the proper type (5)]
expected: FAIL
[HTMLCanvasElement interface: document.createElement("canvas") must inherit property "toDataURL" with the proper type (6)]
expected: FAIL
[HTMLCanvasElement interface: calling toDataURL(DOMString,any) on document.createElement("canvas") with too few arguments must throw TypeError]
expected: FAIL
[HTMLCanvasElement interface: document.createElement("canvas") must inherit property "toBlob" with the proper type (7)]
expected: FAIL

View file

@ -1,5 +0,0 @@
[security.dataURI.html]
type: testharness
[data: URIs do not count as different-origin, and do not taint the canvas]
expected: FAIL

View file

@ -1,5 +0,0 @@
[security.pattern.canvas.timing.sub.html]
type: testharness
[Pattern safety depends on whether the source was origin-clean, not on whether it still is clean]
expected: FAIL

View file

@ -1,5 +0,0 @@
[security.pattern.create.sub.html]
type: testharness
[Creating an unclean pattern does not make the canvas origin-unclean]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.arguments.1.html]
type: testharness
[toDataURL ignores extra arguments]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.arguments.2.html]
type: testharness
[toDataURL ignores extra arguments]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.arguments.3.html]
type: testharness
[toDataURL ignores extra arguments]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.bogustype.html]
type: testharness
[toDataURL with a syntactically invalid type returns a PNG]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.default.html]
type: testharness
[toDataURL with no arguments returns a PNG]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpeg.alpha.html]
type: testharness
[toDataURL with JPEG composites onto black]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpeg.primarycolours.html]
type: testharness
[toDataURL with JPEG handles simple colours correctly]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpeg.quality.basic.html]
type: testharness
[toDataURL with JPEG uses the quality parameter]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpeg.quality.notnumber.html]
type: testharness
[toDataURL with JPEG handles non-numeric quality parameters]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpeg.quality.outsiderange.html]
type: testharness
[toDataURL with JPEG handles out-of-range quality parameters]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.jpg.html]
type: testharness
[toDataURL with image/jpg is invalid type hence returns a PNG]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.lowercase.ascii.html]
type: testharness
[toDataURL type is case-insensitive]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.lowercase.unicode.html]
type: testharness
[toDataURL type is ASCII-case-insensitive]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.png.complexcolours.html]
type: testharness
[toDataURL with PNG handles non-primary and non-solid colours correctly]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.png.html]
type: testharness
[toDataURL with image/png returns a PNG]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.png.primarycolours.html]
type: testharness
[toDataURL with PNG handles simple colours correctly]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.unrecognised.html]
type: testharness
[toDataURL with an unhandled type returns a PNG]
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.zeroheight.html]
type: testharness
[toDataURL on zero-size canvas returns 'data:,']
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.zerosize.html]
type: testharness
[toDataURL on zero-size canvas returns 'data:,']
expected: FAIL

View file

@ -1,5 +0,0 @@
[toDataURL.zerowidth.html]
type: testharness
[toDataURL on zero-size canvas returns 'data:,']
expected: FAIL