more refactoring

This commit is contained in:
rohan.prinja 2015-10-27 17:58:34 +09:00
parent bb2536cd01
commit 45224028db
115 changed files with 3387 additions and 354 deletions

View file

@ -39,7 +39,7 @@ use opaque_node::OpaqueNodeMethods;
use script::dom::attr::AttrValue; use script::dom::attr::AttrValue;
use script::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, ElementTypeId}; use script::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, ElementTypeId};
use script::dom::bindings::codegen::InheritTypes::{HTMLElementTypeId, NodeTypeId}; use script::dom::bindings::codegen::InheritTypes::{HTMLElementTypeId, NodeTypeId};
use script::dom::bindings::conversions::Castable; use script::dom::bindings::inheritance::Castable;
use script::dom::bindings::js::LayoutJS; use script::dom::bindings::js::LayoutJS;
use script::dom::characterdata::LayoutCharacterDataHelpers; use script::dom::characterdata::LayoutCharacterDataHelpers;
use script::dom::document::{Document, LayoutDocumentHelpers}; use script::dom::document::{Document, LayoutDocumentHelpers};

View file

@ -16,13 +16,13 @@ pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable:
let struct_name = item.ident; let struct_name = item.ident;
// This path has to be hardcoded, unfortunately, since we can't resolve paths at expansion time // This path has to be hardcoded, unfortunately, since we can't resolve paths at expansion time
match def.fields.iter().find( match def.fields.iter().find(
|f| match_ty_unwrap(&*f.node.ty, &["dom", "bindings", "utils", "Reflector"]).is_some()) { |f| match_ty_unwrap(&*f.node.ty, &["dom", "bindings", "reflector", "Reflector"]).is_some()) {
// If it has a field that is a Reflector, use that // If it has a field that is a Reflector, use that
Some(f) => { Some(f) => {
let field_name = f.node.ident(); let field_name = f.node.ident();
let impl_item = quote_item!(cx, let impl_item = quote_item!(cx,
impl ::dom::bindings::utils::Reflectable for $struct_name { impl ::dom::bindings::reflector::Reflectable for $struct_name {
fn reflector<'a>(&'a self) -> &'a ::dom::bindings::utils::Reflector { fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
&self.$field_name &self.$field_name
} }
fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) { fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
@ -36,8 +36,8 @@ pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable:
None => { None => {
let field_name = def.fields[0].node.ident(); let field_name = def.fields[0].node.ident();
let impl_item = quote_item!(cx, let impl_item = quote_item!(cx,
impl ::dom::bindings::utils::Reflectable for $struct_name { impl ::dom::bindings::reflector::Reflectable for $struct_name {
fn reflector<'a>(&'a self) -> &'a ::dom::bindings::utils::Reflector { fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
self.$field_name.reflector() self.$field_name.reflector()
} }
fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) { fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {

View file

@ -10,7 +10,7 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap}; use dom::bindings::js::{JS, MutNullableHeap};
use dom::bindings::js::{LayoutJS, Root, RootedReference}; use dom::bindings::js::{LayoutJS, Root, RootedReference};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::element::{AttributeMutation, Element}; use dom::element::{AttributeMutation, Element};
use dom::values::UNSIGNED_LONG_MAX; use dom::values::UNSIGNED_LONG_MAX;
use dom::virtualmethods::vtable_for; use dom::virtualmethods::vtable_for;

View file

@ -6,7 +6,7 @@
use dom::bindings::error::{Error, Fallible}; use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::global_object_for_js_object; use dom::bindings::global::global_object_for_js_object;
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use js::jsapi::GetGlobalForObjectCrossCompartment; use js::jsapi::GetGlobalForObjectCrossCompartment;
use js::jsapi::{Heap, MutableHandleObject, RootedObject, RootedValue}; use js::jsapi::{Heap, MutableHandleObject, RootedObject, RootedValue};
use js::jsapi::{IsCallable, JSContext, JSObject, JS_WrapObject}; use js::jsapi::{IsCallable, JSContext, JSObject, JS_WrapObject};

View file

@ -5197,6 +5197,7 @@ class CGBindingRoot(CGThing):
'dom::bindings::global::global_object_for_js_object', 'dom::bindings::global::global_object_for_js_object',
'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{JS, Root, RootedReference}',
'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::reflector::{Reflectable}',
'dom::bindings::utils::{create_dom_global, do_create_interface_objects}', 'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
'dom::bindings::utils::ConstantSpec', 'dom::bindings::utils::ConstantSpec',
'dom::bindings::utils::{DOMClass}', 'dom::bindings::utils::{DOMClass}',
@ -5206,7 +5207,6 @@ class CGBindingRoot(CGThing):
'dom::bindings::utils::{finalize_global, trace_global}', 'dom::bindings::utils::{finalize_global, trace_global}',
'dom::bindings::utils::has_property_on_prototype', 'dom::bindings::utils::has_property_on_prototype',
'dom::bindings::utils::is_platform_object', 'dom::bindings::utils::is_platform_object',
'dom::bindings::utils::{Reflectable}',
'dom::bindings::utils::throwing_constructor', 'dom::bindings::utils::throwing_constructor',
'dom::bindings::utils::get_dictionary_property', 'dom::bindings::utils::get_dictionary_property',
'dom::bindings::utils::set_dictionary_property', 'dom::bindings::utils::set_dictionary_property',
@ -5915,10 +5915,11 @@ class GlobalGenRoots():
descriptors = config.getDescriptors(register=True, isCallback=False) descriptors = config.getDescriptors(register=True, isCallback=False)
imports = [CGGeneric("use dom::types::*;\n"), imports = [CGGeneric("use dom::types::*;\n"),
CGGeneric("use dom::bindings::conversions::{Castable, DerivedFrom, get_dom_class};\n"), CGGeneric("use dom::bindings::conversions::{DerivedFrom, get_dom_class};\n"),
CGGeneric("use dom::bindings::inheritance::Castable;\n"),
CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"), CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"),
CGGeneric("use dom::bindings::trace::JSTraceable;\n"), CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
CGGeneric("use dom::bindings::utils::Reflectable;\n"), CGGeneric("use dom::bindings::reflector::Reflectable;\n"),
CGGeneric("use js::jsapi::JSTracer;\n\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"),
CGGeneric("use std::mem;\n\n")] CGGeneric("use std::mem;\n\n")]
allprotos = [] allprotos = []

View file

@ -38,7 +38,8 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::str::{ByteString, USVString}; use dom::bindings::str::{ByteString, USVString};
use dom::bindings::utils::{DOMClass, Reflectable, Reflector}; use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::utils::DOMClass;
use js; use js;
use js::glue::{GetProxyPrivate, IsWrapper, RUST_JS_NumberValue}; use js::glue::{GetProxyPrivate, IsWrapper, RUST_JS_NumberValue};
use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject}; use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_STRING, UnwrapObject};
@ -56,7 +57,6 @@ use libc;
use num::Float; use num::Float;
use num::traits::{Bounded, Zero}; use num::traits::{Bounded, Zero};
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::mem;
use std::rc::Rc; use std::rc::Rc;
use std::{char, ptr, slice}; use std::{char, ptr, slice};
use util::str::DOMString; use util::str::DOMString;

View file

@ -11,7 +11,8 @@ use devtools_traits::ScriptToDevtoolsControlMsg;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::native_from_reflector_jsmanaged; use dom::bindings::conversions::native_from_reflector_jsmanaged;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::Reflectable;
use dom::window::{self, ScriptHelpers}; use dom::window::{self, ScriptHelpers};
use dom::workerglobalscope::WorkerGlobalScope; use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;

View file

@ -2,9 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! The `Castable` trait.
use dom::bindings::conversions::get_dom_class; use dom::bindings::conversions::get_dom_class;
use dom::bindings::conversions::{DerivedFrom, IDLInterface}; use dom::bindings::conversions::{DerivedFrom, IDLInterface};
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use std::mem; use std::mem;
/// A trait to hold the cast functions of IDL interfaces that either derive /// A trait to hold the cast functions of IDL interfaces that either derive

View file

@ -28,7 +28,8 @@ use dom::bindings::conversions::DerivedFrom;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::trace::trace_reflector; use dom::bindings::trace::trace_reflector;
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::Reflectable;
use dom::node::Node; use dom::node::Node;
use js::jsapi::{Heap, JSObject, JSTracer}; use js::jsapi::{Heap, JSObject, JSTracer};
use js::jsval::JSVal; use js::jsval::JSVal;

View file

@ -137,14 +137,17 @@ pub mod cell;
pub mod conversions; pub mod conversions;
pub mod error; pub mod error;
pub mod global; pub mod global;
pub mod inheritance;
pub mod js; pub mod js;
pub mod num; pub mod num;
pub mod proxyhandler; pub mod proxyhandler;
pub mod refcounted; pub mod refcounted;
pub mod reflector;
pub mod str; pub mod str;
pub mod structuredclone; pub mod structuredclone;
pub mod trace; pub mod trace;
pub mod utils; pub mod utils;
pub mod xmlname;
/// Generated JS-Rust bindings. /// Generated JS-Rust bindings.
#[allow(missing_docs, non_snake_case)] #[allow(missing_docs, non_snake_case)]

View file

@ -25,7 +25,8 @@
use core::nonzero::NonZero; use core::nonzero::NonZero;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::trace::trace_reflector; use dom::bindings::trace::trace_reflector;
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::Reflectable;
use js::jsapi::{JSContext, JSTracer}; use js::jsapi::{JSContext, JSTracer};
use libc; use libc;
use script_task::{CommonScriptMsg, ScriptChan}; use script_task::{CommonScriptMsg, ScriptChan};

View file

@ -0,0 +1,79 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//! The `Reflector` struct.
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use js::jsapi::{HandleObject, JSContext, JSObject};
use std::cell::UnsafeCell;
use std::ptr;
/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
pub fn reflect_dom_object<T: Reflectable>
(obj: Box<T>,
global: GlobalRef,
wrap_fn: extern "Rust" fn(*mut JSContext, GlobalRef, Box<T>) -> Root<T>)
-> Root<T> {
wrap_fn(global.get_cx(), global, obj)
}
/// A struct to store a reference to the reflector of a DOM object.
#[allow(raw_pointer_derive, unrooted_must_root)]
#[must_root]
#[servo_lang = "reflector"]
#[derive(HeapSizeOf)]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
#[ignore_heap_size_of = "defined and measured in rust-mozjs"]
object: UnsafeCell<*mut JSObject>,
}
#[allow(unrooted_must_root)]
impl PartialEq for Reflector {
fn eq(&self, other: &Reflector) -> bool {
unsafe { *self.object.get() == *other.object.get() }
}
}
impl Reflector {
/// Get the reflector.
#[inline]
pub fn get_jsobject(&self) -> HandleObject {
unsafe { HandleObject::from_marked_location(self.object.get()) }
}
/// Initialize the reflector. (May be called only once.)
pub fn set_jsobject(&mut self, object: *mut JSObject) {
unsafe {
let obj = self.object.get();
assert!((*obj).is_null());
assert!(!object.is_null());
*obj = object;
}
}
/// Return a pointer to the memory location at which the JS reflector
/// object is stored. Used to root the reflector, as
/// required by the JSAPI rooting APIs.
pub fn rootable(&self) -> *mut *mut JSObject {
self.object.get()
}
/// Create an uninitialized `Reflector`.
pub fn new() -> Reflector {
Reflector {
object: UnsafeCell::new(ptr::null_mut())
}
}
}
/// A trait to provide access to the `Reflector` for a DOM object.
pub trait Reflectable {
/// Returns the receiver's reflector.
fn reflector(&self) -> &Reflector;
/// Initializes the Reflector
fn init_reflector(&mut self, obj: *mut JSObject);
}

View file

@ -35,7 +35,8 @@ use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, Repetiti
use cssparser::RGBA; use cssparser::RGBA;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler}; use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::utils::WindowProxyHandler;
use encoding::types::EncodingRef; use encoding::types::EncodingRef;
use euclid::length::Length as EuclidLength; use euclid::length::Length as EuclidLength;
use euclid::matrix2d::Matrix2D; use euclid::matrix2d::Matrix2D;

View file

@ -49,14 +49,10 @@ use js::rust::{GCMethods, ToString, define_methods, define_properties};
use js::{JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JS_CALLEE}; use js::{JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JS_CALLEE};
use js::{JSPROP_PERMANENT, JSPROP_READONLY}; use js::{JSPROP_PERMANENT, JSPROP_READONLY};
use libc::{self, c_uint}; use libc::{self, c_uint};
use std::cell::UnsafeCell;
use std::cmp::PartialEq;
use std::default::Default; use std::default::Default;
use std::ffi::CString; use std::ffi::CString;
use std::ptr; use std::ptr;
use string_cache::{Atom, Namespace};
use util::mem::HeapSizeOf; use util::mem::HeapSizeOf;
use util::str::DOMString;
/// Proxy handler for a WindowProxy. /// Proxy handler for a WindowProxy.
#[allow(raw_pointer_derive)] #[allow(raw_pointer_derive)]
@ -391,74 +387,6 @@ pub fn initialize_global(global: *mut JSObject) {
} }
} }
/// A trait to provide access to the `Reflector` for a DOM object.
pub trait Reflectable {
/// Returns the receiver's reflector.
fn reflector(&self) -> &Reflector;
/// Initializes the Reflector
fn init_reflector(&mut self, obj: *mut JSObject);
}
/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
pub fn reflect_dom_object<T: Reflectable>
(obj: Box<T>,
global: GlobalRef,
wrap_fn: extern "Rust" fn(*mut JSContext, GlobalRef, Box<T>) -> Root<T>)
-> Root<T> {
wrap_fn(global.get_cx(), global, obj)
}
/// A struct to store a reference to the reflector of a DOM object.
#[allow(raw_pointer_derive, unrooted_must_root)]
#[must_root]
#[servo_lang = "reflector"]
#[derive(HeapSizeOf)]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
#[ignore_heap_size_of = "defined and measured in rust-mozjs"]
object: UnsafeCell<*mut JSObject>,
}
#[allow(unrooted_must_root)]
impl PartialEq for Reflector {
fn eq(&self, other: &Reflector) -> bool {
unsafe { *self.object.get() == *other.object.get() }
}
}
impl Reflector {
/// Get the reflector.
#[inline]
pub fn get_jsobject(&self) -> HandleObject {
unsafe { HandleObject::from_marked_location(self.object.get()) }
}
/// Initialize the reflector. (May be called only once.)
pub fn set_jsobject(&mut self, object: *mut JSObject) {
unsafe {
let obj = self.object.get();
assert!((*obj).is_null());
assert!(!object.is_null());
*obj = object;
}
}
/// Return a pointer to the memory location at which the JS reflector
/// object is stored. Used to root the reflector, as
/// required by the JSAPI rooting APIs.
pub fn rootable(&self) -> *mut *mut JSObject {
self.object.get()
}
/// Create an uninitialized `Reflector`.
pub fn new() -> Reflector {
Reflector {
object: UnsafeCell::new(ptr::null_mut())
}
}
}
/// Gets the property `id` on `proxy`'s prototype. If it exists, `*found` is /// Gets the property `id` on `proxy`'s prototype. If it exists, `*found` is
/// set to true and `*vp` to the value, otherwise `*found` is set to false. /// set to true and `*vp` to the value, otherwise `*found` is set to false.
/// ///
@ -800,21 +728,6 @@ pub unsafe extern fn generic_lenient_setter(cx: *mut JSContext,
generic_call(cx, argc, vp, true, call_setter) generic_call(cx, argc, vp, true, call_setter)
} }
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
match xml_name_type(qualified_name) {
XMLName::InvalidXMLName => {
// Step 1.
Err(Error::InvalidCharacter)
},
XMLName::Name => {
// Step 2.
Err(Error::Namespace)
},
XMLName::QName => Ok(())
}
}
unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::Class, unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::Class,
proto_id: u32, proto_id: u32,
depth: u32) -> bool { depth: u32) -> bool {
@ -827,155 +740,3 @@ unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::
pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks { pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
instanceClassMatchesProto: Some(instance_class_has_proto_at_depth), instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
}; };
/// Validate a namespace and qualified name and extract their parts.
/// See https://dom.spec.whatwg.org/#validate-and-extract for details.
pub fn validate_and_extract(namespace: Option<DOMString>, qualified_name: &str)
-> Fallible<(Namespace, Option<Atom>, Atom)> {
// Step 1.
let namespace = namespace_from_domstring(namespace);
// Step 2.
try!(validate_qualified_name(qualified_name));
let colon = ':';
// Step 5.
let mut parts = qualified_name.splitn(2, colon);
let (maybe_prefix, local_name) = {
let maybe_prefix = parts.next();
let maybe_local_name = parts.next();
debug_assert!(parts.next().is_none());
if let Some(local_name) = maybe_local_name {
debug_assert!(!maybe_prefix.unwrap().is_empty());
(maybe_prefix, local_name)
} else {
(None, maybe_prefix.unwrap())
}
};
debug_assert!(!local_name.contains(colon));
match (namespace, maybe_prefix) {
(ns!(""), Some(_)) => {
// Step 6.
Err(Error::Namespace)
},
(ref ns, Some("xml")) if ns != &ns!(XML) => {
// Step 7.
Err(Error::Namespace)
},
(ref ns, p) if ns != &ns!(XMLNS) &&
(qualified_name == "xmlns" || p == Some("xmlns")) => {
// Step 8.
Err(Error::Namespace)
},
(ns!(XMLNS), p) if qualified_name != "xmlns" && p != Some("xmlns") => {
// Step 9.
Err(Error::Namespace)
},
(ns, p) => {
// Step 10.
Ok((ns, p.map(Atom::from_slice), Atom::from_slice(local_name)))
}
}
}
/// Results of `xml_name_type`.
#[derive(PartialEq)]
#[allow(missing_docs)]
pub enum XMLName {
QName,
Name,
InvalidXMLName
}
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
/// for details.
pub fn xml_name_type(name: &str) -> XMLName {
fn is_valid_start(c: char) -> bool {
match c {
':' |
'A' ... 'Z' |
'_' |
'a' ... 'z' |
'\u{C0}' ... '\u{D6}' |
'\u{D8}' ... '\u{F6}' |
'\u{F8}' ... '\u{2FF}' |
'\u{370}' ... '\u{37D}' |
'\u{37F}' ... '\u{1FFF}' |
'\u{200C}' ... '\u{200D}' |
'\u{2070}' ... '\u{218F}' |
'\u{2C00}' ... '\u{2FEF}' |
'\u{3001}' ... '\u{D7FF}' |
'\u{F900}' ... '\u{FDCF}' |
'\u{FDF0}' ... '\u{FFFD}' |
'\u{10000}' ... '\u{EFFFF}' => true,
_ => false,
}
}
fn is_valid_continuation(c: char) -> bool {
is_valid_start(c) || match c {
'-' |
'.' |
'0' ... '9' |
'\u{B7}' |
'\u{300}' ... '\u{36F}' |
'\u{203F}' ... '\u{2040}' => true,
_ => false,
}
}
let mut iter = name.chars();
let mut non_qname_colons = false;
let mut seen_colon = false;
let mut last = match iter.next() {
None => return XMLName::InvalidXMLName,
Some(c) => {
if !is_valid_start(c) {
return XMLName::InvalidXMLName;
}
if c == ':' {
non_qname_colons = true;
}
c
}
};
for c in iter {
if !is_valid_continuation(c) {
return XMLName::InvalidXMLName;
}
if c == ':' {
match seen_colon {
true => non_qname_colons = true,
false => seen_colon = true
}
}
last = c
}
if last == ':' {
non_qname_colons = true
}
match non_qname_colons {
false => XMLName::QName,
true => XMLName::Name
}
}
/// Convert a possibly-null URL to a namespace.
///
/// If the URL is None, returns the empty namespace.
pub fn namespace_from_domstring(url: Option<DOMString>) -> Namespace {
match url {
None => ns!(""),
Some(ref s) => Namespace(Atom::from_slice(s)),
}
}

View file

@ -0,0 +1,176 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//! Functions for validating and extracting qualified XML names.
use dom::bindings::error::{Error, ErrorResult, Fallible};
use string_cache::{Atom, Namespace};
use util::str::DOMString;
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
match xml_name_type(qualified_name) {
XMLName::InvalidXMLName => {
// Step 1.
Err(Error::InvalidCharacter)
},
XMLName::Name => {
// Step 2.
Err(Error::Namespace)
},
XMLName::QName => Ok(())
}
}
/// Validate a namespace and qualified name and extract their parts.
/// See https://dom.spec.whatwg.org/#validate-and-extract for details.
pub fn validate_and_extract(namespace: Option<DOMString>, qualified_name: &str)
-> Fallible<(Namespace, Option<Atom>, Atom)> {
// Step 1.
let namespace = namespace_from_domstring(namespace);
// Step 2.
try!(validate_qualified_name(qualified_name));
let colon = ':';
// Step 5.
let mut parts = qualified_name.splitn(2, colon);
let (maybe_prefix, local_name) = {
let maybe_prefix = parts.next();
let maybe_local_name = parts.next();
debug_assert!(parts.next().is_none());
if let Some(local_name) = maybe_local_name {
debug_assert!(!maybe_prefix.unwrap().is_empty());
(maybe_prefix, local_name)
} else {
(None, maybe_prefix.unwrap())
}
};
debug_assert!(!local_name.contains(colon));
match (namespace, maybe_prefix) {
(ns!(""), Some(_)) => {
// Step 6.
Err(Error::Namespace)
},
(ref ns, Some("xml")) if ns != &ns!(XML) => {
// Step 7.
Err(Error::Namespace)
},
(ref ns, p) if ns != &ns!(XMLNS) &&
(qualified_name == "xmlns" || p == Some("xmlns")) => {
// Step 8.
Err(Error::Namespace)
},
(ns!(XMLNS), p) if qualified_name != "xmlns" && p != Some("xmlns") => {
// Step 9.
Err(Error::Namespace)
},
(ns, p) => {
// Step 10.
Ok((ns, p.map(Atom::from_slice), Atom::from_slice(local_name)))
}
}
}
/// Results of `xml_name_type`.
#[derive(PartialEq)]
#[allow(missing_docs)]
pub enum XMLName {
QName,
Name,
InvalidXMLName
}
/// Check if an element name is valid. See http://www.w3.org/TR/xml/#NT-Name
/// for details.
pub fn xml_name_type(name: &str) -> XMLName {
fn is_valid_start(c: char) -> bool {
match c {
':' |
'A' ... 'Z' |
'_' |
'a' ... 'z' |
'\u{C0}' ... '\u{D6}' |
'\u{D8}' ... '\u{F6}' |
'\u{F8}' ... '\u{2FF}' |
'\u{370}' ... '\u{37D}' |
'\u{37F}' ... '\u{1FFF}' |
'\u{200C}' ... '\u{200D}' |
'\u{2070}' ... '\u{218F}' |
'\u{2C00}' ... '\u{2FEF}' |
'\u{3001}' ... '\u{D7FF}' |
'\u{F900}' ... '\u{FDCF}' |
'\u{FDF0}' ... '\u{FFFD}' |
'\u{10000}' ... '\u{EFFFF}' => true,
_ => false,
}
}
fn is_valid_continuation(c: char) -> bool {
is_valid_start(c) || match c {
'-' |
'.' |
'0' ... '9' |
'\u{B7}' |
'\u{300}' ... '\u{36F}' |
'\u{203F}' ... '\u{2040}' => true,
_ => false,
}
}
let mut iter = name.chars();
let mut non_qname_colons = false;
let mut seen_colon = false;
let mut last = match iter.next() {
None => return XMLName::InvalidXMLName,
Some(c) => {
if !is_valid_start(c) {
return XMLName::InvalidXMLName;
}
if c == ':' {
non_qname_colons = true;
}
c
}
};
for c in iter {
if !is_valid_continuation(c) {
return XMLName::InvalidXMLName;
}
if c == ':' {
match seen_colon {
true => non_qname_colons = true,
false => seen_colon = true
}
}
last = c
}
if last == ':' {
non_qname_colons = true
}
match non_qname_colons {
false => XMLName::QName,
true => XMLName::Name
}
}
/// Convert a possibly-null URL to a namespace.
///
/// If the URL is None, returns the empty namespace.
pub fn namespace_from_domstring(url: Option<DOMString>) -> Namespace {
match url {
None => ns!(""),
Some(ref s) => Namespace(Atom::from_slice(s)),
}
}

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use num::ToPrimitive; use num::ToPrimitive;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::ToOwned; use std::borrow::ToOwned;

View file

@ -7,7 +7,8 @@ use dom::bindings::conversions::{ToJSValConvertible};
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor}; use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::utils::get_array_index_from_id; use dom::bindings::utils::get_array_index_from_id;
use dom::bindings::utils::{Reflectable, WindowProxyHandler}; use dom::bindings::reflector::Reflectable;
use dom::bindings::utils::WindowProxyHandler;
use dom::document::Document; use dom::document::Document;
use dom::element::Element; use dom::element::Element;
use dom::window::Window; use dom::window::Window;

View file

@ -10,7 +10,7 @@ use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::canvasrenderingcontext2d::parse_color; use dom::canvasrenderingcontext2d::parse_color;
// https://html.spec.whatwg.org/multipage/#canvasgradient // https://html.spec.whatwg.org/multipage/#canvasgradient

View file

@ -6,7 +6,7 @@ use canvas_traits::{FillOrStrokeStyle, RepetitionStyle, SurfaceStyle};
use dom::bindings::codegen::Bindings::CanvasPatternBinding; use dom::bindings::codegen::Bindings::CanvasPatternBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::canvasgradient::ToFillOrStrokeStyle; use dom::canvasgradient::ToFillOrStrokeStyle;
use euclid::size::Size2D; use euclid::size::Size2D;

View file

@ -19,7 +19,7 @@ use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, LayoutJS, Root}; use dom::bindings::js::{JS, LayoutJS, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeStyle}; use dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeStyle};
use dom::canvaspattern::CanvasPattern; use dom::canvaspattern::CanvasPattern;
use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::HTMLCanvasElement;

View file

@ -9,7 +9,7 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use script_task::ScriptChan; use script_task::ScriptChan;
use util::str::DOMString; use util::str::DOMString;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::ConsoleBinding;
use dom::bindings::codegen::Bindings::ConsoleBinding::ConsoleMethods; use dom::bindings::codegen::Bindings::ConsoleBinding::ConsoleMethods;
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use util::str::DOMString; use util::str::DOMString;
// https://developer.mozilla.org/en-US/docs/Web/API/Console // https://developer.mozilla.org/en-US/docs/Web/API/Console

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::CryptoBinding::CryptoMethods;
use dom::bindings::error::{Error, Fallible}; use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use js::jsapi::{JSContext, JSObject}; use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetArrayBufferViewType, JS_GetObjectAsArrayBufferView, Type}; use js::jsapi::{JS_GetArrayBufferViewType, JS_GetObjectAsArrayBufferView, Type};
use rand::{OsRng, Rng}; use rand::{OsRng, Rng};

View file

@ -5,7 +5,7 @@
use cssparser::serialize_identifier; use cssparser::serialize_identifier;
use dom::bindings::error::{Error, Fallible}; use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::utils::Reflector; use dom::bindings::reflector::Reflector;
use util::str::DOMString; use util::str::DOMString;
#[dom_struct] #[dom_struct]

View file

@ -7,7 +7,7 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::element::{Element, StylePriority}; use dom::element::{Element, StylePriority};
use dom::node::{Node, NodeDamage, document_from_node, window_from_node}; use dom::node::{Node, NodeDamage, document_from_node, window_from_node};
use dom::window::Window; use dom::window::Window;

View file

@ -9,7 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::js::{MutHeapJSVal, Root};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::Event; use dom::event::Event;
use js::jsapi::{HandleValue, JSContext}; use js::jsapi::{HandleValue, JSContext};
use js::jsval::JSVal; use js::jsval::JSVal;

View file

@ -14,7 +14,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootCollection}; use dom::bindings::js::{Root, RootCollection};
use dom::bindings::refcounted::LiveDOMReferences; use dom::bindings::refcounted::LiveDOMReferences;
use dom::bindings::structuredclone::StructuredCloneData; use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::messageevent::MessageEvent; use dom::messageevent::MessageEvent;
use dom::worker::{SimpleWorkerErrorHandler, TrustedWorkerAddress, WorkerMessageHandler}; use dom::worker::{SimpleWorkerErrorHandler, TrustedWorkerAddress, WorkerMessageHandler};
use dom::workerglobalscope::WorkerGlobalScope; use dom::workerglobalscope::WorkerGlobalScope;

View file

@ -24,9 +24,10 @@ use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::RootedVec; use dom::bindings::trace::RootedVec;
use dom::bindings::utils::XMLName::InvalidXMLName; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::utils::{Reflectable, reflect_dom_object}; use dom::bindings::reflector::Reflectable;
use dom::bindings::utils::{validate_and_extract, xml_name_type}; use dom::bindings::xmlname::{validate_and_extract, xml_name_type};
use dom::bindings::xmlname::XMLName::InvalidXMLName;
use dom::comment::Comment; use dom::comment::Comment;
use dom::customevent::CustomEvent; use dom::customevent::CustomEvent;
use dom::documentfragment::DocumentFragment; use dom::documentfragment::DocumentFragment;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionConstants
use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods; use dom::bindings::codegen::Bindings::DOMExceptionBinding::DOMExceptionMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use std::borrow::ToOwned; use std::borrow::ToOwned;
use util::str::DOMString; use util::str::DOMString;

View file

@ -11,8 +11,8 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::validate_qualified_name; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::xmlname::validate_qualified_name;
use dom::document::DocumentSource; use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument}; use dom::document::{Document, IsHTMLDocument};
use dom::documenttype::DocumentType; use dom::documenttype::DocumentType;

View file

@ -11,7 +11,7 @@ use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::document::DocumentSource; use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument}; use dom::document::{Document, IsHTMLDocument};
use dom::window::Window; use dom::window::Window;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::DOMPointReadOnlyM
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::dompointreadonly::{DOMPointReadOnly, DOMPointWriteMethods}; use dom::dompointreadonly::{DOMPointReadOnly, DOMPointWriteMethods};
// http://dev.w3.org/fxtf/geometry/Overview.html#dompoint // http://dev.w3.org/fxtf/geometry/Overview.html#dompoint

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::DOMPointReadOnlyBinding::{DOMPointReadOnly
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use std::cell::Cell; use std::cell::Cell;
// http://dev.w3.org/fxtf/geometry/Overview.html#dompointreadonly // http://dev.w3.org/fxtf/geometry/Overview.html#dompointreadonly

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::DOMRectReadOnlyMet
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::domrectreadonly::DOMRectReadOnly; use dom::domrectreadonly::DOMRectReadOnly;
#[dom_struct] #[dom_struct]

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::DOMRectListBinding;
use dom::bindings::codegen::Bindings::DOMRectListBinding::DOMRectListMethods; use dom::bindings::codegen::Bindings::DOMRectListBinding::DOMRectListMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::domrect::DOMRect; use dom::domrect::DOMRect;
use dom::window::Window; use dom::window::Window;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::DOMRectReadOnlyBinding::{DOMRectReadOnlyMe
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use std::cell::Cell; use std::cell::Cell;
#[dom_struct] #[dom_struct]

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::DOMStringMapBinding::DOMStringMapMethods;
use dom::bindings::error::ErrorResult; use dom::bindings::error::ErrorResult;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;
use dom::node::window_from_node; use dom::node::window_from_node;
use util::str::DOMString; use util::str::DOMString;

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::element::Element; use dom::element::Element;
use dom::node::window_from_node; use dom::node::window_from_node;
use std::borrow::ToOwned; use std::borrow::ToOwned;

View file

@ -26,8 +26,8 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap}; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
use dom::bindings::js::{Root, RootedReference}; use dom::bindings::js::{Root, RootedReference};
use dom::bindings::utils::XMLName::InvalidXMLName; use dom::bindings::xmlname::{namespace_from_domstring, validate_and_extract, xml_name_type};
use dom::bindings::utils::{namespace_from_domstring, validate_and_extract, xml_name_type}; use dom::bindings::xmlname::XMLName::InvalidXMLName;
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::create::create_element; use dom::create::create_element;
use dom::document::{Document, LayoutDocumentHelpers}; use dom::document::{Document, LayoutDocumentHelpers};

View file

@ -11,7 +11,7 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutHeapJSVal, Root}; use dom::bindings::js::{MutHeapJSVal, Root};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use js::jsapi::{RootedValue, HandleValue, JSContext}; use js::jsapi::{RootedValue, HandleValue, JSContext};
use js::jsval::JSVal; use js::jsval::JSVal;

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethod
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::Cell; use std::cell::Cell;

View file

@ -9,7 +9,8 @@ use dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
use dom::bindings::codegen::InheritTypes::EventTargetTypeId; use dom::bindings::codegen::InheritTypes::EventTargetTypeId;
use dom::bindings::error::{Error, Fallible, report_pending_exception}; use dom::bindings::error::{Error, Fallible, report_pending_exception};
use dom::bindings::utils::{Reflectable, Reflector}; use dom::bindings::reflector::Reflector;
use dom::bindings::reflector::Reflectable;
use dom::event::Event; use dom::event::Event;
use dom::eventdispatcher::dispatch_event; use dom::eventdispatcher::dispatch_event;
use dom::virtualmethods::VirtualMethods; use dom::virtualmethods::VirtualMethods;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::FileBinding;
use dom::bindings::codegen::Bindings::FileBinding::FileMethods; use dom::bindings::codegen::Bindings::FileBinding::FileMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::blob::Blob; use dom::blob::Blob;
use util::str::DOMString; use util::str::DOMString;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::FileListBinding;
use dom::bindings::codegen::Bindings::FileListBinding::FileListMethods; use dom::bindings::codegen::Bindings::FileListBinding::FileListMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::file::File; use dom::file::File;
use dom::window::Window; use dom::window::Window;

View file

@ -10,7 +10,8 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::utils::{Reflectable, reflect_dom_object}; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::reflector::Reflectable;
use dom::blob::Blob; use dom::blob::Blob;
use dom::domexception::{DOMErrorName, DOMException}; use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};

View file

@ -11,7 +11,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::{Fallible}; use dom::bindings::error::{Fallible};
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::blob::Blob; use dom::blob::Blob;
use dom::file::File; use dom::file::File;
use dom::htmlformelement::HTMLFormElement; use dom::htmlformelement::HTMLFormElement;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::HTMLAreaElementBinding;
use dom::bindings::codegen::Bindings::HTMLAreaElementBinding::HTMLAreaElementMethods; use dom::bindings::codegen::Bindings::HTMLAreaElementBinding::HTMLAreaElementMethods;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::document::Document; use dom::document::Document;
use dom::domtokenlist::DOMTokenList; use dom::domtokenlist::DOMTokenList;
use dom::htmlelement::HTMLElement; use dom::htmlelement::HTMLElement;

View file

@ -10,7 +10,7 @@ use dom::bindings::codegen::Bindings::HTMLBodyElementBinding::{self, HTMLBodyEle
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers}; use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;

View file

@ -14,7 +14,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root}; use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflectable}; use dom::bindings::reflector::Reflectable;
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers}; use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document; use dom::document::Document;
use dom::element::{AttributeMutation, Element}; use dom::element::{AttributeMutation, Element};

View file

@ -0,0 +1,355 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, 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;
<<<<<<< HEAD
use dom::bindings::conversions::Castable;
use dom::bindings::error::{Error, Fallible};
=======
use dom::bindings::inheritance::Castable;
>>>>>>> move Castable into dom::bindings::inheritance
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;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => 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 {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,355 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, 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;
<<<<<<< HEAD
use dom::bindings::conversions::Castable;
use dom::bindings::error::{Error, Fallible};
=======
use dom::bindings::inheritance::Castable;
>>>>>>> move Castable into dom::bindings::inheritance
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;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => 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 {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,307 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, FromLayoutMsg};
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
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::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes;
use std::cell::Cell;
use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => None
}
}
}
impl VirtualMethods for HTMLCanvasElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,307 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, FromLayoutMsg};
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
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::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes;
use std::cell::Cell;
use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => None
}
}
}
impl VirtualMethods for HTMLCanvasElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,351 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, 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;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => 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 {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,351 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, 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;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => 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 {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,307 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, FromLayoutMsg};
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
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::inheritance::Castable;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes;
use std::cell::Cell;
use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => None
}
}
}
impl VirtualMethods for HTMLCanvasElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,307 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, FromLayoutMsg};
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
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::inheritance::Castable;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{HeapGCValue, JS, LayoutJS, Root};
use dom::bindings::utils::{Reflectable};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::webglrenderingcontext::{LayoutCanvasWebGLRenderingContextHelpers, WebGLRenderingContext};
use euclid::size::Size2D;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::{HandleValue, JSContext};
use offscreen_gl_context::GLContextAttributes;
use std::cell::Cell;
use std::iter::repeat;
use util::str::{DOMString, parse_unsigned_integer};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => None
}
}
}
impl VirtualMethods for HTMLCanvasElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -0,0 +1,355 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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, 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;
<<<<<<< HEAD
use dom::bindings::conversions::Castable;
use dom::bindings::error::{Error, Fallible};
=======
use dom::bindings::inheritance::Castable;
>>>>>>> move Castable into dom::bindings::inheritance
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;
use dom::element::{AttributeMutation, Element};
use dom::htmlelement::HTMLElement;
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};
const DEFAULT_WIDTH: u32 = 300;
const DEFAULT_HEIGHT: u32 = 150;
#[must_root]
#[derive(JSTraceable, Clone, HeapSizeOf)]
pub enum CanvasContext {
Context2d(JS<CanvasRenderingContext2D>),
WebGL(JS<WebGLRenderingContext>),
}
impl HeapGCValue for CanvasContext {}
#[dom_struct]
pub struct HTMLCanvasElement {
htmlelement: HTMLElement,
context: DOMRefCell<Option<CanvasContext>>,
width: Cell<u32>,
height: Cell<u32>,
}
impl PartialEq for HTMLCanvasElement {
fn eq(&self, other: &HTMLCanvasElement) -> bool {
self as *const HTMLCanvasElement == &*other
}
}
impl HTMLCanvasElement {
fn new_inherited(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> HTMLCanvasElement {
HTMLCanvasElement {
htmlelement: HTMLElement::new_inherited(localName, prefix, document),
context: DOMRefCell::new(None),
width: Cell::new(DEFAULT_WIDTH),
height: Cell::new(DEFAULT_HEIGHT),
}
}
#[allow(unrooted_must_root)]
pub fn new(localName: DOMString,
prefix: Option<DOMString>,
document: &Document) -> Root<HTMLCanvasElement> {
let element = HTMLCanvasElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLCanvasElementBinding::Wrap)
}
fn recreate_contexts(&self) {
let size = self.get_size();
if let Some(ref context) = *self.context.borrow() {
match *context {
CanvasContext::Context2d(ref context) => context.recreate(size),
CanvasContext::WebGL(ref context) => context.recreate(size),
}
}
}
pub fn get_size(&self) -> Size2D<i32> {
Size2D::new(self.width.get() as i32, self.height.get() as i32)
}
}
pub struct HTMLCanvasData {
pub renderer_id: Option<usize>,
pub ipc_renderer: Option<IpcSender<CanvasMsg>>,
pub width: u32,
pub height: u32,
}
pub trait LayoutHTMLCanvasElementHelpers {
fn data(&self) -> HTMLCanvasData;
}
impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
#[allow(unsafe_code)]
fn data(&self) -> HTMLCanvasData {
unsafe {
let canvas = &*self.unsafe_get();
let (renderer_id, ipc_renderer) = match canvas.context.borrow_for_layout().as_ref() {
Some(&CanvasContext::Context2d(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
Some(&CanvasContext::WebGL(ref context)) => {
let context = context.to_layout();
(Some(context.get_renderer_id()), Some(context.get_ipc_renderer()))
},
None => (None, None),
};
HTMLCanvasData {
renderer_id: renderer_id,
ipc_renderer: ipc_renderer,
width: canvas.width.get(),
height: canvas.height.get(),
}
}
}
}
impl HTMLCanvasElement {
pub fn ipc_renderer(&self) -> Option<IpcSender<CanvasMsg>> {
self.context.borrow().as_ref().map(|context| {
match *context {
CanvasContext::Context2d(ref context) => context.ipc_renderer(),
CanvasContext::WebGL(ref context) => context.ipc_renderer(),
}
})
}
pub fn get_or_init_2d_context(&self) -> Option<Root<CanvasRenderingContext2D>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let context = CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size);
*self.context.borrow_mut() = Some(CanvasContext::Context2d(JS::from_rooted(&context)));
}
match *self.context.borrow().as_ref().unwrap() {
CanvasContext::Context2d(ref context) => Some(context.root()),
_ => None,
}
}
pub fn get_or_init_webgl_context(&self,
cx: *mut JSContext,
attrs: Option<HandleValue>) -> Option<Root<WebGLRenderingContext>> {
if self.context.borrow().is_none() {
let window = window_from_node(self);
let size = self.get_size();
let attrs = if let Some(webgl_attributes) = attrs {
if let Ok(ref attrs) = WebGLContextAttributes::new(cx, webgl_attributes) {
From::from(attrs)
} else {
debug!("Unexpected error on conversion of WebGLContextAttributes");
return None;
}
} else {
GLContextAttributes::default()
};
let maybe_ctx = WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size, attrs);
*self.context.borrow_mut() = maybe_ctx.map( |ctx| CanvasContext::WebGL(JS::from_rooted(&ctx)));
}
if let Some(CanvasContext::WebGL(ref context)) = *self.context.borrow() {
Some(context.root())
} else {
None
}
}
pub fn is_valid(&self) -> bool {
self.height.get() != 0 && self.width.get() != 0
}
pub fn fetch_all_data(&self) -> Option<(Vec<u8>, Size2D<i32>)> {
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 {
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn Width(&self) -> u32 {
self.width.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-width
fn SetWidth(&self, width: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("width"), width)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn Height(&self) -> u32 {
self.height.get()
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-height
fn SetHeight(&self, height: u32) {
self.upcast::<Element>().set_uint_attribute(&atom!("height"), height)
}
// https://html.spec.whatwg.org/multipage/#dom-canvas-getcontext
fn GetContext(&self,
cx: *mut JSContext,
id: DOMString,
attributes: Vec<HandleValue>)
-> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
match &*id {
"2d" => {
self.get_or_init_2d_context()
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D)
}
"webgl" | "experimental-webgl" => {
self.get_or_init_webgl_context(cx, attributes.get(0).map(|p| *p))
.map(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext)
}
_ => 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 {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
let recreate = match attr.local_name() {
&atom!(width) => {
let width = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.width.set(width.unwrap_or(DEFAULT_WIDTH));
true
},
&atom!(height) => {
let height = mutation.new_value(attr).and_then(|value| {
parse_unsigned_integer(value.chars())
});
self.height.set(height.unwrap_or(DEFAULT_HEIGHT));
true
},
_ => false,
};
if recreate {
self.recreate_contexts();
}
}
}
impl<'a> From<&'a WebGLContextAttributes> for GLContextAttributes {
fn from(attrs: &'a WebGLContextAttributes) -> GLContextAttributes {
GLContextAttributes {
alpha: attrs.alpha,
depth: attrs.depth,
stencil: attrs.stencil,
antialias: attrs.antialias,
premultiplied_alpha: attrs.premultipliedAlpha,
preserve_drawing_buffer: attrs.preserveDrawingBuffer,
}
}
}
pub mod utils {
use dom::window::Window;
use ipc_channel::ipc;
use net_traits::image_cache_task::{ImageCacheChan, ImageResponse};
use url::Url;
pub fn request_image_from_cache(window: &Window, url: Url) -> ImageResponse {
let image_cache = window.image_cache_task();
let (response_chan, response_port) = ipc::channel().unwrap();
image_cache.request_image(url, ImageCacheChan(response_chan), None);
let result = response_port.recv().unwrap();
result.image_response
}
}

View file

@ -8,7 +8,8 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflector, namespace_from_domstring, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::xmlname::namespace_from_domstring;
use dom::element::Element; use dom::element::Element;
use dom::node::{Node, TreeIterator}; use dom::node::{Node, TreeIterator};
use dom::window::Window; use dom::window::Window;

View file

@ -13,7 +13,7 @@ use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, Nod
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration}; use dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration};
use dom::document::Document; use dom::document::Document;
use dom::domstringmap::DOMStringMap; use dom::domstringmap::DOMStringMap;

View file

@ -10,11 +10,11 @@ use dom::bindings::codegen::Bindings::HTMLFormElementBinding;
use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods; use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods; use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId}; use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId, NodeTypeId};
use dom::bindings::conversions::{DerivedFrom}; use dom::bindings::conversions::DerivedFrom;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root}; use dom::bindings::js::{Root};
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::document::Document; use dom::document::Document;
use dom::element::Element; use dom::element::Element;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};

View file

@ -11,7 +11,7 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, LayoutJS}; use dom::bindings::js::{Root, LayoutJS};
use dom::bindings::utils::Reflectable; use dom::bindings::reflector::Reflectable;
use dom::customevent::CustomEvent; use dom::customevent::CustomEvent;
use dom::document::Document; use dom::document::Document;
use dom::element::{self, AttributeMutation, Element}; use dom::element::{self, AttributeMutation, Element};

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::ImageDataBinding;
use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods; use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use euclid::size::Size2D; use euclid::size::Size2D;
use js::jsapi::{Heap, JSContext, JSObject}; use js::jsapi::{Heap, JSContext, JSObject};
use js::jsapi::{JS_GetUint8ClampedArrayData, JS_NewUint8ClampedArray}; use js::jsapi::{JS_GetUint8ClampedArrayData, JS_NewUint8ClampedArray};

View file

@ -9,7 +9,8 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Root, RootedReference}; use dom::bindings::js::{Root, RootedReference};
use dom::bindings::utils::{Reflectable, reflect_dom_object}; use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::reflector::Reflectable;
use dom::event::Event; use dom::event::Event;
use dom::uievent::UIEvent; use dom::uievent::UIEvent;
use dom::window::Window; use dom::window::Window;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::str::USVString; use dom::bindings::str::USVString;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::urlhelper::UrlHelper; use dom::urlhelper::UrlHelper;
use dom::window::Window; use dom::window::Window;
use url::{Url, UrlParser}; use url::{Url, UrlParser};

View file

@ -9,7 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::Event; use dom::event::Event;
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use js::jsapi::{RootedValue, HandleValue, Heap, JSContext}; use js::jsapi::{RootedValue, HandleValue, Heap, JSContext};

View file

@ -9,7 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::uievent::UIEvent; use dom::uievent::UIEvent;

View file

@ -8,7 +8,8 @@ use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods;
use dom::bindings::error::{Error, Fallible}; use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, namespace_from_domstring, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::xmlname::namespace_from_domstring;
use dom::element::Element; use dom::element::Element;
use dom::window::Window; use dom::window::Window;
use string_cache::Atom; use string_cache::Atom;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::NavigatorBinding;
use dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods; use dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::navigatorinfo; use dom::navigatorinfo;
use dom::window::Window; use dom::window::Window;
use util::str::DOMString; use util::str::DOMString;

View file

@ -31,7 +31,8 @@ use dom::bindings::js::RootedReference;
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap}; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::trace::RootedVec; use dom::bindings::trace::RootedVec;
use dom::bindings::utils::{Reflectable, namespace_from_domstring, reflect_dom_object}; use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::xmlname::namespace_from_domstring;
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::comment::Comment; use dom::comment::Comment;
use dom::document::{Document, DocumentSource, IsHTMLDocument}; use dom::document::{Document, DocumentSource, IsHTMLDocument};

View file

@ -11,7 +11,7 @@ use dom::bindings::codegen::Bindings::NodeIteratorBinding::NodeIteratorMethods;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::document::Document; use dom::document::Document;
use dom::node::Node; use dom::node::Node;
use std::cell::Cell; use std::cell::Cell;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::NodeListBinding;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods; use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::node::{ChildrenMutation, Node}; use dom::node::{ChildrenMutation, Node};
use dom::window::Window; use dom::window::Window;
use std::cell::Cell; use std::cell::Cell;

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::performancetiming::PerformanceTiming; use dom::performancetiming::PerformanceTiming;
use dom::window::Window; use dom::window::Window;
use time; use time;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::PerformanceTimingBinding;
use dom::bindings::codegen::Bindings::PerformanceTimingBinding::PerformanceTimingMethods; use dom::bindings::codegen::Bindings::PerformanceTimingBinding::PerformanceTimingMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::window::Window; use dom::window::Window;
#[dom_struct] #[dom_struct]

View file

@ -9,7 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use util::str::DOMString; use util::str::DOMString;

View file

@ -15,7 +15,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root, RootedReference}; use dom::bindings::js::{JS, MutHeap, Root, RootedReference};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::characterdata::CharacterData; use dom::characterdata::CharacterData;
use dom::document::Document; use dom::document::Document;
use dom::documentfragment::DocumentFragment; use dom::documentfragment::DocumentFragment;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::ScreenBinding;
use dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods; use dom::bindings::codegen::Bindings::ScreenBinding::ScreenMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::window::Window; use dom::window::Window;
#[dom_struct] #[dom_struct]

View file

@ -12,7 +12,7 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::document::Document; use dom::document::Document;
use dom::node::Node; use dom::node::Node;
use dom::text::Text; use dom::text::Text;

View file

@ -9,7 +9,7 @@ use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{Root, RootedReference}; use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted; use dom::bindings::refcounted::Trusted;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent; use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper; use dom::urlhelper::UrlHelper;

View file

@ -9,7 +9,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::utils::{reflect_dom_object}; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storage::Storage; use dom::storage::Storage;
use util::str::DOMString; use util::str::DOMString;

View file

@ -18,7 +18,7 @@ use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::str::{ByteString, USVString}; use dom::bindings::str::{ByteString, USVString};
use dom::bindings::utils::Reflector; use dom::bindings::reflector::Reflector;
use dom::blob::Blob; use dom::blob::Blob;
use js::jsapi::{HandleValue, JSContext, JSObject}; use js::jsapi::{HandleValue, JSContext, JSObject};
use js::jsval::{JSVal, NullValue}; use js::jsval::{JSVal, NullValue};

View file

@ -5,7 +5,7 @@
// check-tidy: no specs after this line // check-tidy: no specs after this line
use dom::bindings::codegen::Bindings::TestBindingProxyBinding::TestBindingProxyMethods; use dom::bindings::codegen::Bindings::TestBindingProxyBinding::TestBindingProxyMethods;
use dom::bindings::utils::Reflector; use dom::bindings::reflector::Reflector;
use util::str::DOMString; use util::str::DOMString;

View file

@ -9,7 +9,7 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::str::USVString; use dom::bindings::str::USVString;
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use encoding::Encoding; use encoding::Encoding;
use encoding::label::encoding_from_whatwg_label; use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef}; use encoding::types::{DecoderTrap, EncodingRef};

View file

@ -8,7 +8,7 @@ use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::str::USVString; use dom::bindings::str::USVString;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use encoding::label::encoding_from_whatwg_label; use encoding::label::encoding_from_whatwg_label;
use encoding::types::EncodingRef; use encoding::types::EncodingRef;
use encoding::{EncoderTrap, Encoding}; use encoding::{EncoderTrap, Encoding};

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::TouchBinding::TouchMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::num::Finite; use dom::bindings::num::Finite;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::eventtarget::EventTarget; use dom::eventtarget::EventTarget;
use dom::window::Window; use dom::window::Window;

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutHeap, Root}; use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{EventBubbles, EventCancelable}; use dom::event::{EventBubbles, EventCancelable};
use dom::touchlist::TouchList; use dom::touchlist::TouchList;
use dom::uievent::UIEvent; use dom::uievent::UIEvent;

View file

@ -6,7 +6,7 @@ use dom::bindings::codegen::Bindings::TouchListBinding;
use dom::bindings::codegen::Bindings::TouchListBinding::TouchListMethods; use dom::bindings::codegen::Bindings::TouchListBinding::TouchListMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root}; use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::touch::Touch; use dom::touch::Touch;
use dom::window::Window; use dom::window::Window;

View file

@ -12,7 +12,7 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::js::{JS, MutHeap}; use dom::bindings::js::{JS, MutHeap};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::document::Document; use dom::document::Document;
use dom::node::Node; use dom::node::Node;
use std::rc::Rc; use std::rc::Rc;

View file

@ -10,7 +10,7 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::js::{JS, MutNullableHeap, RootedReference}; use dom::bindings::js::{JS, MutNullableHeap, RootedReference};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::window::Window; use dom::window::Window;
use std::cell::Cell; use std::cell::Cell;

View file

@ -7,7 +7,7 @@ use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::str::USVString; use dom::bindings::str::USVString;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::urlhelper::UrlHelper; use dom::urlhelper::UrlHelper;
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::cell::RefCell; use std::cell::RefCell;

View file

@ -10,7 +10,7 @@ use dom::bindings::codegen::UnionTypes::StringOrURLSearchParams::{eString, eURLS
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use encoding::types::EncodingRef; use encoding::types::EncodingRef;
use url::form_urlencoded::{parse, serialize_with_encoding}; use url::form_urlencoded::{parse, serialize_with_encoding};
use util::str::DOMString; use util::str::DOMString;

View file

@ -5,7 +5,7 @@
use dom::bindings::codegen::Bindings::ValidityStateBinding; use dom::bindings::codegen::Bindings::ValidityStateBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::window::Window; use dom::window::Window;
// https://html.spec.whatwg.org/multipage/#validitystate // https://html.spec.whatwg.org/multipage/#validitystate

View file

@ -7,7 +7,7 @@ use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding;
use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoMethods; use dom::bindings::codegen::Bindings::WebGLActiveInfoBinding::WebGLActiveInfoMethods;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use util::str::DOMString; use util::str::DOMString;
#[dom_struct] #[dom_struct]

View file

@ -7,7 +7,7 @@ use canvas_traits::{CanvasMsg, CanvasWebGLMsg, WebGLError, WebGLResult};
use dom::bindings::codegen::Bindings::WebGLBufferBinding; use dom::bindings::codegen::Bindings::WebGLBufferBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::webglobject::WebGLObject; use dom::webglobject::WebGLObject;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use std::cell::Cell; use std::cell::Cell;

View file

@ -10,7 +10,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use util::str::DOMString; use util::str::DOMString;

View file

@ -7,7 +7,7 @@ use canvas_traits::{CanvasMsg, CanvasWebGLMsg, WebGLFramebufferBindingRequest};
use dom::bindings::codegen::Bindings::WebGLFramebufferBinding; use dom::bindings::codegen::Bindings::WebGLFramebufferBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::webglobject::WebGLObject; use dom::webglobject::WebGLObject;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use std::cell::Cell; use std::cell::Cell;

View file

@ -6,7 +6,7 @@
use dom::bindings::codegen::Bindings::WebGLObjectBinding; use dom::bindings::codegen::Bindings::WebGLObjectBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
#[dom_struct] #[dom_struct]
pub struct WebGLObject { pub struct WebGLObject {

View file

@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::WebGLProgramBinding;
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::webglobject::WebGLObject; use dom::webglobject::WebGLObject;
use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN; use dom::webglrenderingcontext::MAX_UNIFORM_AND_ATTRIBUTE_LEN;
use dom::webglshader::WebGLShader; use dom::webglshader::WebGLShader;

View file

@ -7,7 +7,7 @@ use canvas_traits::{CanvasMsg, CanvasWebGLMsg};
use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding; use dom::bindings::codegen::Bindings::WebGLRenderbufferBinding;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root; use dom::bindings::js::Root;
use dom::bindings::utils::reflect_dom_object; use dom::bindings::reflector::reflect_dom_object;
use dom::webglobject::WebGLObject; use dom::webglobject::WebGLObject;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use std::cell::Cell; use std::cell::Cell;

View file

@ -9,11 +9,11 @@ use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderi
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{WebGLRenderingContextMethods}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{WebGLRenderingContextMethods};
use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes}; use dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::{self, WebGLContextAttributes};
use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement; use dom::bindings::codegen::UnionTypes::ImageDataOrHTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
use dom::bindings::conversions::{ToJSValConvertible}; use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::{GlobalField, GlobalRef}; use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root}; use dom::bindings::js::{JS, LayoutJS, MutNullableHeap, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable}; use dom::event::{Event, EventBubbles, EventCancelable};
use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::HTMLCanvasElement;
use dom::htmlcanvaselement::utils as canvas_utils; use dom::htmlcanvaselement::utils as canvas_utils;

Some files were not shown because too many files have changed in this diff Show more