@@ -43,6 +43,7 @@ use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers};
use script::layout_exports::{LayoutElementHelpers, LayoutNodeHelpers, LayoutDom, RawLayoutElementHelpers};
use script::layout_exports::NodeFlags;
use script::layout_exports::PendingRestyle;
use script::typeholder::TypeHolderTrait;
use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress};
use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
@@ -75,6 +76,10 @@ use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
use style::str::is_whitespace;
use style::stylist::CascadeData;
use script::dom::bindings::trace::JSTraceable;
use script::dom::bindings::inheritance::Castable;
use script::dom::bindings::reflector::DomObject;
use script_servoparser::TypeHolder;

pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
let ptr = data.ptr.as_ptr() as *mut StyleData;
@@ -85,7 +90,7 @@ pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) {
#[derive(Clone, Copy)]
pub struct ServoLayoutNode<'a> {
/// The wrapped node.
node: LayoutDom<Node>,
node: LayoutDom<Node<TypeHolder>>,

/// Being chained to a PhantomData prevents `LayoutNode`s from escaping.
chain: PhantomData<&'a ()>,
@@ -113,7 +118,7 @@ impl<'a> PartialEq for ServoLayoutNode<'a> {
}

impl<'ln> ServoLayoutNode<'ln> {
fn from_layout_js(n: LayoutDom<Node>) -> ServoLayoutNode<'ln> {
fn from_layout_js(n: LayoutDom<Node<TypeHolder>>) -> ServoLayoutNode<'ln> {
ServoLayoutNode {
node: n,
chain: PhantomData,
@@ -125,7 +130,7 @@ impl<'ln> ServoLayoutNode<'ln> {
}

/// Creates a new layout node with the same lifetime as this layout node.
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutDom<Node>) -> ServoLayoutNode<'ln> {
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutDom<Node<TypeHolder>>) -> ServoLayoutNode<'ln> {
ServoLayoutNode {
node: *node,
chain: self.chain,
@@ -304,15 +309,15 @@ impl<'le> GetLayoutData for ServoThreadSafeLayoutElement<'le> {
impl<'ln> ServoLayoutNode<'ln> {
/// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
/// call and as such is marked `unsafe`.
pub unsafe fn get_jsmanaged(&self) -> &LayoutDom<Node> {
pub unsafe fn get_jsmanaged(&self) -> &LayoutDom<Node<TypeHolder>> {
&self.node
}
}

// A wrapper around documents that ensures ayout can only ever access safe properties.
#[derive(Clone, Copy)]
pub struct ServoLayoutDocument<'ld> {
document: LayoutDom<Document>,
document: LayoutDom<Document<TypeHolder>>,
chain: PhantomData<&'ld ()>,
}

@@ -354,7 +359,7 @@ impl<'ld> ServoLayoutDocument<'ld> {
unsafe { self.document.style_shared_lock() }
}

pub fn from_layout_js(doc: LayoutDom<Document>) -> ServoLayoutDocument<'ld> {
pub fn from_layout_js(doc: LayoutDom<Document<TypeHolder>>) -> ServoLayoutDocument<'ld> {
ServoLayoutDocument {
document: doc,
chain: PhantomData,
@@ -365,7 +370,7 @@ impl<'ld> ServoLayoutDocument<'ld> {
/// A wrapper around elements that ensures layout can only ever access safe properties.
#[derive(Clone, Copy)]
pub struct ServoLayoutElement<'le> {
element: LayoutDom<Element>,
element: LayoutDom<Element<TypeHolder>>,
chain: PhantomData<&'le ()>,
}

@@ -599,7 +604,7 @@ impl<'le> Hash for ServoLayoutElement<'le> {
impl<'le> Eq for ServoLayoutElement<'le> {}

impl<'le> ServoLayoutElement<'le> {
fn from_layout_js(el: LayoutDom<Element>) -> ServoLayoutElement<'le> {
fn from_layout_js(el: LayoutDom<Element<TypeHolder>>) -> ServoLayoutElement<'le> {
ServoLayoutElement {
element: el,
chain: PhantomData,
@@ -650,7 +655,7 @@ impl<'le> ServoLayoutElement<'le> {
}
}

fn as_element<'le>(node: LayoutDom<Node>) -> Option<ServoLayoutElement<'le>> {
fn as_element<'le>(node: LayoutDom<Node<TypeHolder>>) -> Option<ServoLayoutElement<'le>> {
node.downcast().map(ServoLayoutElement::from_layout_js)
}

@@ -887,7 +892,7 @@ impl<'ln> DangerousThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {

impl<'ln> ServoThreadSafeLayoutNode<'ln> {
/// Creates a new layout node with the same lifetime as this layout node.
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutDom<Node>) -> ServoThreadSafeLayoutNode<'ln> {
pub unsafe fn new_with_this_lifetime(&self, node: &LayoutDom<Node<TypeHolder>>) -> ServoThreadSafeLayoutNode<'ln> {
ServoThreadSafeLayoutNode {
node: self.node.new_with_this_lifetime(node),
pseudo: PseudoElementType::Normal,
@@ -904,7 +909,7 @@ impl<'ln> ServoThreadSafeLayoutNode<'ln> {

/// Returns the interior of this node as a `LayoutDom`. This is highly unsafe for layout to
/// call and as such is marked `unsafe`.
unsafe fn get_jsmanaged(&self) -> &LayoutDom<Node> {
unsafe fn get_jsmanaged(&self) -> &LayoutDom<Node<TypeHolder>> {
self.node.get_jsmanaged()
}
}
@@ -964,7 +969,7 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {

fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool {
unsafe {
let text: LayoutDom<Text> = match self.get_jsmanaged().downcast() {
let text: LayoutDom<Text<TypeHolder>> = match self.get_jsmanaged().downcast() {
Some(text) => text,
None => return false
};
@@ -1030,13 +1035,13 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {

fn get_colspan(&self) -> u32 {
unsafe {
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
self.get_jsmanaged().downcast::<Element<TypeHolder>>().unwrap().get_colspan()
}
}

fn get_rowspan(&self) -> u32 {
unsafe {
self.get_jsmanaged().downcast::<Element>().unwrap().get_rowspan()
self.get_jsmanaged().downcast::<Element<TypeHolder>>().unwrap().get_rowspan()
}
}
}
@@ -50,6 +50,11 @@ extern crate style;
extern crate style_traits;
extern crate time as std_time;
extern crate webrender_api;
#[macro_use]
extern crate jstraceable_derive;
#[macro_use] extern crate malloc_size_of_derive;
extern crate mozjs as js;
extern crate script_servoparser;

mod dom_wrapper;

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -28,6 +28,8 @@ use std::ptr;
use std::rc::Rc;
use std::str;
use url::form_urlencoded;
use typeholder::TypeHolderTrait;


#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
pub enum BodyType {
@@ -38,19 +40,19 @@ pub enum BodyType {
ArrayBuffer
}

pub enum FetchedData {
pub enum FetchedData<TH: TypeHolderTrait + 'static> {
Text(String),
Json(RootedTraceableBox<Heap<JSValue>>),
BlobData(DomRoot<Blob>),
FormData(DomRoot<FormData>),
BlobData(DomRoot<Blob<TH>>),
FormData(DomRoot<FormData<TH>>),
ArrayBuffer(RootedTraceableBox<Heap<*mut JSObject>>),
JSException(RootedTraceableBox<Heap<JSVal>>)
}

// https://fetch.spec.whatwg.org/#concept-body-consume-body
#[allow(unrooted_must_root)]
pub fn consume_body<T: BodyOperations + DomObject>(object: &T, body_type: BodyType) -> Rc<Promise> {
let promise = Promise::new(&object.global());
pub fn consume_body<T: BodyOperations<<T as DomObject>::TypeHolder> + DomObject>(object: &T, body_type: BodyType) -> Rc<Promise<T::TypeHolder>> {
let promise = Promise::<<T as DomObject>::TypeHolder>::new(&object.global());

// Step 1
if object.get_body_used() || object.is_locked() {
@@ -72,9 +74,9 @@ pub fn consume_body<T: BodyOperations + DomObject>(object: &T, body_type: BodyTy

// https://fetch.spec.whatwg.org/#concept-body-consume-body
#[allow(unrooted_must_root)]
pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T,
pub fn consume_body_with_promise<T: BodyOperations<<T as DomObject>::TypeHolder> + DomObject>(object: &T,
body_type: BodyType,
promise: &Promise) {
promise: &Promise<T::TypeHolder>) {
// Step 5
let body = match object.take_body() {
Some(body) => body,
@@ -103,11 +105,11 @@ pub fn consume_body_with_promise<T: BodyOperations + DomObject>(object: &T,

// https://fetch.spec.whatwg.org/#concept-body-package-data
#[allow(unsafe_code)]
fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
fn run_package_data_algorithm<T: BodyOperations<<T as DomObject>::TypeHolder> + DomObject>(object: &T,
bytes: Vec<u8>,
body_type: BodyType,
mime_type: Ref<Vec<u8>>)
-> Fallible<FetchedData> {
-> Fallible<FetchedData<T::TypeHolder>> {
let global = object.global();
let cx = global.get_cx();
let mime = &*mime_type;
@@ -122,13 +124,13 @@ fn run_package_data_algorithm<T: BodyOperations + DomObject>(object: &T,
}
}

fn run_text_data_algorithm(bytes: Vec<u8>) -> Fallible<FetchedData> {
fn run_text_data_algorithm<TH: TypeHolderTrait>(bytes: Vec<u8>) -> Fallible<FetchedData<TH>> {
Ok(FetchedData::Text(String::from_utf8_lossy(&bytes).into_owned()))
}

#[allow(unsafe_code)]
fn run_json_data_algorithm(cx: *mut JSContext,
bytes: Vec<u8>) -> Fallible<FetchedData> {
fn run_json_data_algorithm<TH: TypeHolderTrait>(cx: *mut JSContext,
bytes: Vec<u8>) -> Fallible<FetchedData<TH>> {
let json_text = String::from_utf8_lossy(&bytes);
let json_text: Vec<u16> = json_text.encode_utf16().collect();
rooted!(in(cx) let mut rval = UndefinedValue());
@@ -147,9 +149,9 @@ fn run_json_data_algorithm(cx: *mut JSContext,
}
}

fn run_blob_data_algorithm(root: &GlobalScope,
fn run_blob_data_algorithm<TH: TypeHolderTrait>(root: &GlobalScope<TH>,
bytes: Vec<u8>,
mime: &[u8]) -> Fallible<FetchedData> {
mime: &[u8]) -> Fallible<FetchedData<TH>> {
let mime_string = if let Ok(s) = String::from_utf8(mime.to_vec()) {
s
} else {
@@ -159,7 +161,7 @@ fn run_blob_data_algorithm(root: &GlobalScope,
Ok(FetchedData::BlobData(blob))
}

fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> Fallible<FetchedData> {
fn run_form_data_algorithm<TH: TypeHolderTrait>(root: &GlobalScope<TH>, bytes: Vec<u8>, mime: &[u8]) -> Fallible<FetchedData<TH>> {
let mime_str = if let Ok(s) = str::from_utf8(mime) {
s
} else {
@@ -184,7 +186,7 @@ fn run_form_data_algorithm(root: &GlobalScope, bytes: Vec<u8>, mime: &[u8]) -> F
}

#[allow(unsafe_code)]
unsafe fn run_array_buffer_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData> {
unsafe fn run_array_buffer_data_algorithm<TH: TypeHolderTrait>(cx: *mut JSContext, bytes: Vec<u8>) -> Fallible<FetchedData<TH>> {
rooted!(in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
let arraybuffer = ArrayBuffer::create(cx, CreateWith::Slice(&bytes), array_buffer_ptr.handle_mut());
if arraybuffer.is_err() {
@@ -194,9 +196,9 @@ unsafe fn run_array_buffer_data_algorithm(cx: *mut JSContext, bytes: Vec<u8>) ->
Ok(FetchedData::ArrayBuffer(rooted_heap))
}

pub trait BodyOperations {
pub trait BodyOperations<TH: TypeHolderTrait> {
fn get_body_used(&self) -> bool;
fn set_body_promise(&self, p: &Rc<Promise>, body_type: BodyType);
fn set_body_promise(&self, p: &Rc<Promise<TH>>, body_type: BodyType);
/// Returns `Some(_)` if the body is complete, `None` if there is more to
/// come.
fn take_body(&self) -> Option<Vec<u8>>;
@@ -54,9 +54,12 @@ fn main() {
}
let phf = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("InterfaceObjectMapPhf.rs");
let mut phf = File::create(&phf).unwrap();
write!(&mut phf, "pub static MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = ").unwrap();
write!(&mut phf, "pub static mut MAP: phf::Map<&'static [u8], unsafe fn(*mut JSContext, HandleObject)> = ").unwrap();
phf_codegen::Map::<&'static [u8]>::new().build(&mut phf).unwrap();
write!(&mut phf, ";\n\n").unwrap();
write!(&mut phf, "pub unsafe fn init_MAP<TH: TypeHolderTrait>() {{\n MAP =").unwrap();
map.build(&mut phf).unwrap();
write!(&mut phf, ";\n").unwrap();
write!(&mut phf, ";}}\n").unwrap();
}

#[derive(Eq, Hash, PartialEq)]
@@ -31,10 +31,10 @@ use std::ffi::CStr;
use std::str;
use style::properties::longhands::{margin_bottom, margin_left, margin_right, margin_top};
use uuid::Uuid;

use typeholder::TypeHolderTrait;

#[allow(unsafe_code)]
pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<EvaluateJSReply>) {
pub fn handle_evaluate_js<TH: TypeHolderTrait>(global: &GlobalScope<TH>, eval: String, reply: IpcSender<EvaluateJSReply>) {
// global.get_cx() returns a valid `JSContext` pointer, so this is safe.
let result = unsafe {
let cx = global.get_cx();
@@ -73,31 +73,31 @@ pub fn handle_evaluate_js(global: &GlobalScope, eval: String, reply: IpcSender<E
reply.send(result).unwrap();
}

pub fn handle_get_root_node(documents: &Documents, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
pub fn handle_get_root_node<TH: TypeHolderTrait>(documents: &Documents<TH>, pipeline: PipelineId, reply: IpcSender<Option<NodeInfo>>) {
let info = documents.find_document(pipeline)
.map(|document| document.upcast::<Node>().summarize());
.map(|document| document.upcast::<Node<TH>>().summarize());
reply.send(info).unwrap();
}

pub fn handle_get_document_element(documents: &Documents,
pub fn handle_get_document_element<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
reply: IpcSender<Option<NodeInfo>>) {
let info = documents.find_document(pipeline)
.and_then(|document| document.GetDocumentElement())
.map(|element| element.upcast::<Node>().summarize());
.map(|element| element.upcast::<Node<TH>>().summarize());
reply.send(info).unwrap();
}

fn find_node_by_unique_id(documents: &Documents,
fn find_node_by_unique_id<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
node_id: &str)
-> Option<DomRoot<Node>> {
-> Option<DomRoot<Node<TH>>> {
documents.find_document(pipeline).and_then(|document|
document.upcast::<Node>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
document.upcast::<Node<TH>>().traverse_preorder().find(|candidate| candidate.unique_id() == node_id)
)
}

pub fn handle_get_children(documents: &Documents,
pub fn handle_get_children<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<Option<Vec<NodeInfo>>>) {
@@ -113,7 +113,7 @@ pub fn handle_get_children(documents: &Documents,
};
}

pub fn handle_get_layout(documents: &Documents,
pub fn handle_get_layout<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
node_id: String,
reply: IpcSender<Option<ComputedNodeLayout>>) {
@@ -122,13 +122,13 @@ pub fn handle_get_layout(documents: &Documents,
Some(found_node) => found_node
};

let elem = node.downcast::<Element>().expect("should be getting layout of element");
let elem = node.downcast::<Element<TH>>().expect("should be getting layout of element");
let rect = elem.GetBoundingClientRect();
let width = rect.Width() as f32;
let height = rect.Height() as f32;

let window = window_from_node(&*node);
let elem = node.downcast::<Element>().expect("should be getting layout of element");
let elem = node.downcast::<Element<TH>>().expect("should be getting layout of element");
let computed_style = window.GetComputedStyle(elem, None);

reply.send(Some(ComputedNodeLayout {
@@ -154,7 +154,7 @@ pub fn handle_get_layout(documents: &Documents,
})).unwrap();
}

fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
fn determine_auto_margins<TH: TypeHolderTrait>(window: &Window<TH>, node: &Node<TH>) -> AutoMargins {
let style = window.style_query(node.to_trusted_node_address()).unwrap();
let margin = style.get_margin();
AutoMargins {
@@ -207,7 +207,7 @@ pub fn handle_get_cached_messages(_pipeline_id: PipelineId,
reply.send(messages).unwrap();
}

pub fn handle_modify_attribute(documents: &Documents,
pub fn handle_modify_attribute<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
node_id: String,
modifications: Vec<Modification>) {
@@ -216,7 +216,7 @@ pub fn handle_modify_attribute(documents: &Documents,
Some(found_node) => found_node
};

let elem = node.downcast::<Element>().expect("should be getting layout of element");
let elem = node.downcast::<Element<TH>>().expect("should be getting layout of element");

for modification in modifications {
match modification.newValue {
@@ -229,11 +229,11 @@ pub fn handle_modify_attribute(documents: &Documents,
}
}

pub fn handle_wants_live_notifications(global: &GlobalScope, send_notifications: bool) {
pub fn handle_wants_live_notifications<TH: TypeHolderTrait>(global: &GlobalScope<TH>, send_notifications: bool) {
global.set_devtools_wants_updates(send_notifications);
}

pub fn handle_set_timeline_markers(documents: &Documents,
pub fn handle_set_timeline_markers<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>,
reply: IpcSender<Option<TimelineMarker>>) {
@@ -243,23 +243,23 @@ pub fn handle_set_timeline_markers(documents: &Documents,
}
}

pub fn handle_drop_timeline_markers(documents: &Documents,
pub fn handle_drop_timeline_markers<TH: TypeHolderTrait>(documents: &Documents<TH>,
pipeline: PipelineId,
marker_types: Vec<TimelineMarkerType>) {
if let Some(window) = documents.find_window(pipeline) {
window.drop_devtools_timeline_markers(marker_types);
}
}

pub fn handle_request_animation_frame(documents: &Documents,
pub fn handle_request_animation_frame<TH: TypeHolderTrait>(documents: &Documents<TH>,
id: PipelineId,
actor_name: String) {
if let Some(doc) = documents.find_document(id) {
doc.request_animation_frame(AnimationFrameCallback::DevtoolsFramerateTick { actor_name });
}
}

pub fn handle_reload(documents: &Documents,
pub fn handle_reload<TH: TypeHolderTrait>(documents: &Documents<TH>,
id: PipelineId) {
if let Some(win) = documents.find_window(id) {
win.Location().reload_without_origin_check();
@@ -143,7 +143,7 @@ use dom_struct::dom_struct;
#[dom_struct]
pub struct Document {
node: Node,
window: Dom<Window>,
window: Dom<Window<TH>>,
is_html_document: bool,
...
}
@@ -164,7 +164,7 @@ relationship. The `Document` just has a pointer to a `Window`, one of many
pointers to that object, which can live in native DOM data structures or in
JavaScript objects. These are precisely the pointers we need to tell the
garbage collector about. We do this with a
[custom type for traced pointers: `Dom<T>`][dom] (for example, the `Dom<Window>`
[custom type for traced pointers: `Dom<T>`][dom] (for example, the `Dom<Window<TH>>`
above). The implementation of `trace` for `Dom<T>` is not auto-generated; this
is where we actually call the SpiderMonkey trace hooks:

@@ -14,6 +14,7 @@ use net_traits::{ResourceThreads, IpcSend};
use net_traits::request::RequestInit;
use servo_url::ServoUrl;
use std::thread;
use typeholder::TypeHolderTrait;

#[derive(Clone, Debug, JSTraceable, MallocSizeOf, PartialEq)]
pub enum LoadType {
@@ -43,16 +44,16 @@ impl LoadType {
/// that the owner is destroyed.
#[derive(JSTraceable, MallocSizeOf)]
#[must_root]
pub struct LoadBlocker {
pub struct LoadBlocker<TH: TypeHolderTrait + 'static> {
/// The document whose load event is blocked by this object existing.
doc: Dom<Document>,
doc: Dom<Document<TH>>,
/// The load that is blocking the document's load event.
load: Option<LoadType>,
}

impl LoadBlocker {
impl<TH: TypeHolderTrait> LoadBlocker<TH> {
/// Mark the document's load event as blocked on this new load.
pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
pub fn new(doc: &Document<TH>, load: LoadType) -> Self {
doc.loader_mut().add_blocking_load(load.clone());
LoadBlocker {
doc: Dom::from_ref(doc),
@@ -61,7 +62,7 @@ impl LoadBlocker {
}

/// Remove this load from the associated document's list of blocking loads.
pub fn terminate(blocker: &mut Option<LoadBlocker>) {
pub fn terminate(blocker: &mut Option<LoadBlocker<TH>>) {
if let Some(this) = blocker.as_mut() {
this.doc.finish_load(this.load.take().unwrap());
}
@@ -74,7 +75,7 @@ impl LoadBlocker {
}
}

impl Drop for LoadBlocker {
impl<TH: TypeHolderTrait> Drop for LoadBlocker<TH> {
fn drop(&mut self) {
if !thread::panicking() {
debug_assert!(self.load.is_none());
@@ -8,13 +8,14 @@ use dom::bindings::structuredclone::StructuredCloneData;
use js::jsapi::{JSRuntime, JS_RequestInterruptCallback};
use js::rust::Runtime;
use script_runtime::CommonScriptMsg;
use typeholder::TypeHolderTrait;

/// Messages used to control the worker event loops
pub enum WorkerScriptMsg {
pub enum WorkerScriptMsg<TH: TypeHolderTrait + 'static> {
/// Common variants associated with the script messages
Common(CommonScriptMsg),
/// Message sent through Worker.postMessage
DOMMessage(StructuredCloneData)
DOMMessage(StructuredCloneData<TH>)
}

pub struct SimpleWorkerErrorHandler<T: DomObject> {
@@ -8,6 +8,7 @@ use dom::bindings::reflector::DomObject;
use dom::bindings::trace::JSTraceable;
use script_runtime::{ScriptChan, CommonScriptMsg, ScriptPort};
use std::sync::mpsc::{Receiver, Sender};
use typeholder::TypeHolderTrait;

/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
@@ -35,12 +36,12 @@ impl<T: JSTraceable + DomObject + 'static> ScriptChan for SendableWorkerScriptCh
/// worker event loop messages. While this SendableWorkerScriptChan is alive, the associated
/// Worker object will remain alive.
#[derive(Clone, JSTraceable)]
pub struct WorkerThreadWorkerChan<T: DomObject> {
pub sender: Sender<(Trusted<T>, WorkerScriptMsg)>,
pub struct WorkerThreadWorkerChan<T: DomObject, TH: TypeHolderTrait> {
pub sender: Sender<(Trusted<T>, WorkerScriptMsg<TH>)>,
pub worker: Trusted<T>,
}

impl<T: JSTraceable + DomObject + 'static> ScriptChan for WorkerThreadWorkerChan<T> {
impl<T: JSTraceable + DomObject + 'static, TH: TypeHolderTrait> ScriptChan for WorkerThreadWorkerChan<T, TH> {
fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
self.sender
.send((self.worker.clone(), WorkerScriptMsg::Common(msg)))
@@ -55,7 +56,7 @@ impl<T: JSTraceable + DomObject + 'static> ScriptChan for WorkerThreadWorkerChan
}
}

impl<T: DomObject> ScriptPort for Receiver<(Trusted<T>, WorkerScriptMsg)> {
impl<T: DomObject, TH: TypeHolderTrait> ScriptPort for Receiver<(Trusted<T>, WorkerScriptMsg<TH>)> {
fn recv(&self) -> Result<CommonScriptMsg, ()> {
match self.recv().map(|(_, msg)| msg) {
Ok(WorkerScriptMsg::Common(script_msg)) => Ok(script_msg),
@@ -12,10 +12,11 @@ use dom::mouseevent::MouseEvent;
use dom::node::window_from_node;
use dom::window::ReflowReason;
use script_layout_interface::message::ReflowGoal;
use typeholder::TypeHolderTrait;

/// Trait for elements with defined activation behavior
pub trait Activatable {
fn as_element(&self) -> &Element;
pub trait Activatable<TH: TypeHolderTrait> {
fn as_element(&self) -> &Element<TH>;

// Is this particular instance of the element activatable?
fn is_instance_activatable(&self) -> bool;
@@ -27,7 +28,7 @@ pub trait Activatable {
fn canceled_activation(&self);

// https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
fn activation_behavior(&self, event: &Event, target: &EventTarget);
fn activation_behavior(&self, event: &Event<TH>, target: &EventTarget<TH>);

// https://html.spec.whatwg.org/multipage/#implicit-submission
fn implicit_submission(&self, ctrl_key: bool, shift_key: bool, alt_key: bool, meta_key: bool);
@@ -56,7 +57,7 @@ pub enum ActivationSource {
}

// https://html.spec.whatwg.org/multipage/#run-synthetic-click-activation-steps
pub fn synthetic_click_activation(element: &Element,
pub fn synthetic_click_activation<TH: TypeHolderTrait>(element: &Element<TH>,
ctrl_key: bool,
shift_key: bool,
alt_key: bool,
@@ -77,7 +78,7 @@ pub fn synthetic_click_activation(element: &Element,
// Step 4
// https://html.spec.whatwg.org/multipage/#fire-a-synthetic-mouse-event
let win = window_from_node(element);
let target = element.upcast::<EventTarget>();
let target = element.upcast::<EventTarget<TH>>();
let mouse = MouseEvent::new(&win,
DOMString::from("click"),
EventBubbles::DoesNotBubble,
@@ -95,7 +96,7 @@ pub fn synthetic_click_activation(element: &Element,
0,
None,
None);
let event = mouse.upcast::<Event>();
let event = mouse.upcast::<Event<TH>>();
if source == ActivationSource::FromClick {
event.set_trusted(false);
}
@@ -23,26 +23,27 @@ use std::borrow::ToOwned;
use std::cell::Ref;
use std::mem;
use style::attr::{AttrIdentifier, AttrValue};
use typeholder::TypeHolderTrait;

// https://dom.spec.whatwg.org/#interface-attr
#[dom_struct]
pub struct Attr {
reflector_: Reflector,
pub struct Attr<TH: TypeHolderTrait + 'static> {
reflector_: Reflector<TH>,
identifier: AttrIdentifier,
value: DomRefCell<AttrValue>,

/// the element that owns this attribute.
owner: MutNullableDom<Element>,
owner: MutNullableDom<Element<TH>>,
}

impl Attr {
impl<TH: TypeHolderTrait> Attr<TH> {
fn new_inherited(local_name: LocalName,
value: AttrValue,
name: LocalName,
namespace: Namespace,
prefix: Option<Prefix>,
owner: Option<&Element>)
-> Attr {
owner: Option<&Element<TH>>)
-> Self {
Attr {
reflector_: Reflector::new(),
identifier: AttrIdentifier {
@@ -56,14 +57,14 @@ impl Attr {
}
}

pub fn new(window: &Window,
pub fn new(window: &Window<TH>,
local_name: LocalName,
value: AttrValue,
name: LocalName,
namespace: Namespace,
prefix: Option<Prefix>,
owner: Option<&Element>)
-> DomRoot<Attr> {
owner: Option<&Element<TH>>)
-> DomRoot<Self> {
reflect_dom_object(
Box::new(Attr::new_inherited(
local_name,
@@ -94,7 +95,7 @@ impl Attr {
}
}

impl AttrMethods for Attr {
impl<TH: TypeHolderTrait> AttrMethods<TH> for Attr<TH> {
// https://dom.spec.whatwg.org/#dom-attr-localname
fn LocalName(&self) -> DOMString {
// FIXME(ajeffrey): convert directly from LocalName to DOMString
@@ -165,7 +166,7 @@ impl AttrMethods for Attr {
}

// https://dom.spec.whatwg.org/#dom-attr-ownerelement
fn GetOwnerElement(&self) -> Option<DomRoot<Element>> {
fn GetOwnerElement(&self) -> Option<DomRoot<Element<TH>>> {
self.owner()
}

@@ -176,8 +177,8 @@ impl AttrMethods for Attr {
}


impl Attr {
pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
impl<TH: TypeHolderTrait> Attr<TH> {
pub fn set_value(&self, mut value: AttrValue, owner: &Element<TH>) {
let name = self.local_name().clone();
let namespace = self.namespace().clone();
let old_value = DOMString::from(&**self.value());
@@ -188,11 +189,11 @@ impl Attr {
old_value: old_value.clone(),
};

MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);
MutationObserver::<TH>::queue_a_mutation_record(owner.upcast::<Node<TH>>(), mutation);

if owner.get_custom_element_definition().is_some() {
let reaction = CallbackReaction::AttributeChanged(name, Some(old_value), Some(new_value), namespace);
ScriptThread::enqueue_callback_reaction(owner, reaction, None);
ScriptThread::<TH>::enqueue_callback_reaction(owner, reaction, None);
}

assert_eq!(Some(owner), self.owner().r());
@@ -223,7 +224,7 @@ impl Attr {

/// Sets the owner element. Should be called after the attribute is added
/// or removed from its older parent.
pub fn set_owner(&self, owner: Option<&Element>) {
pub fn set_owner(&self, owner: Option<&Element<TH>>) {
let ns = &self.identifier.namespace;
match (self.owner(), owner) {
(Some(old), None) => {
@@ -236,7 +237,7 @@ impl Attr {
self.owner.set(owner);
}

pub fn owner(&self) -> Option<DomRoot<Element>> {
pub fn owner(&self) -> Option<DomRoot<Element<TH>>> {
self.owner.get()
}

@@ -260,7 +261,7 @@ pub trait AttrHelpersForLayout {
}

#[allow(unsafe_code)]
impl AttrHelpersForLayout for LayoutDom<Attr> {
impl<TH: TypeHolderTrait> AttrHelpersForLayout for LayoutDom<Attr<TH>> {
#[inline]
unsafe fn value_forever(&self) -> &'static AttrValue {
// This transmute is used to cheat the lifetime restriction.
@@ -16,43 +16,44 @@ use dom::event::{Event, EventBubbles, EventCancelable};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_atoms::Atom;
use typeholder::TypeHolderTrait;

// https://html.spec.whatwg.org/multipage/#beforeunloadevent
#[dom_struct]
pub struct BeforeUnloadEvent {
event: Event,
pub struct BeforeUnloadEvent<TH: TypeHolderTrait + 'static> {
event: Event<TH>,
return_value: DomRefCell<DOMString>,
}

impl BeforeUnloadEvent {
fn new_inherited() -> BeforeUnloadEvent {
impl<TH: TypeHolderTrait> BeforeUnloadEvent<TH> {
fn new_inherited() -> Self {
BeforeUnloadEvent {
event: Event::new_inherited(),
return_value: DomRefCell::new(DOMString::new()),
}
}

pub fn new_uninitialized(window: &Window) -> DomRoot<BeforeUnloadEvent> {
pub fn new_uninitialized(window: &Window<TH>) -> DomRoot<Self> {
reflect_dom_object(Box::new(BeforeUnloadEvent::new_inherited()),
window,
BeforeUnloadEventBinding::Wrap)
}

pub fn new(window: &Window,
pub fn new(window: &Window<TH>,
type_: Atom,
bubbles: EventBubbles,
cancelable: EventCancelable) -> DomRoot<BeforeUnloadEvent> {
cancelable: EventCancelable) -> DomRoot<Self> {
let ev = BeforeUnloadEvent::new_uninitialized(window);
{
let event = ev.upcast::<Event>();
let event = ev.upcast::<Event<TH>>();
event.init_event(type_, bool::from(bubbles),
bool::from(cancelable));
}
ev
}
}

impl BeforeUnloadEventMethods for BeforeUnloadEvent {
impl<TH: TypeHolderTrait> BeforeUnloadEventMethods for BeforeUnloadEvent<TH> {
// https://html.spec.whatwg.org/multipage/#dom-beforeunloadevent-returnvalue
fn ReturnValue(&self) -> DOMString {
self.return_value.borrow().clone()
@@ -23,6 +23,7 @@ use std::mem::drop;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use typeholder::TypeHolderTrait;

/// The exception handling used for a call.
#[derive(Clone, Copy, PartialEq)]
@@ -37,7 +38,7 @@ pub enum ExceptionHandling {
/// callback interface types.
#[derive(JSTraceable)]
#[must_root]
pub struct CallbackObject {
pub struct CallbackObject<TH: TypeHolderTrait + 'static> {
/// The underlying `JSObject`.
callback: Heap<*mut JSObject>,
permanent_js_root: Heap<JSVal>,
@@ -53,23 +54,23 @@ pub struct CallbackObject {
///
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
/// [sometimes]: https://github.com/whatwg/html/issues/2248
incumbent: Option<Dom<GlobalScope>>
incumbent: Option<Dom<GlobalScope<TH>>>
}

impl Default for CallbackObject {
impl<TH: TypeHolderTrait> Default for CallbackObject<TH> {
#[allow(unrooted_must_root)]
fn default() -> CallbackObject {
fn default() -> CallbackObject<TH> {
CallbackObject::new()
}
}

impl CallbackObject {
impl<TH: TypeHolderTrait> CallbackObject<TH> {
#[allow(unrooted_must_root)]
fn new() -> CallbackObject {
fn new() -> CallbackObject<TH> {
CallbackObject {
callback: Heap::default(),
permanent_js_root: Heap::default(),
incumbent: GlobalScope::incumbent().map(|i| Dom::from_ref(&*i)),
incumbent: GlobalScope::<TH>::incumbent().map(|i| Dom::from_ref(&*i)),
}
}

@@ -86,7 +87,7 @@ impl CallbackObject {
}
}

impl Drop for CallbackObject {
impl<TH: TypeHolderTrait> Drop for CallbackObject<TH> {
#[allow(unsafe_code)]
fn drop(&mut self) {
unsafe {
@@ -97,20 +98,20 @@ impl Drop for CallbackObject {

}

impl PartialEq for CallbackObject {
fn eq(&self, other: &CallbackObject) -> bool {
impl<TH: TypeHolderTrait> PartialEq for CallbackObject<TH> {
fn eq(&self, other: &CallbackObject<TH>) -> bool {
self.callback.get() == other.callback.get()
}
}


/// A trait to be implemented by concrete IDL callback function and
/// callback interface types.
pub trait CallbackContainer {
pub trait CallbackContainer<TH: TypeHolderTrait> {
/// Create a new CallbackContainer object for the given `JSObject`.
unsafe fn new(cx: *mut JSContext, callback: *mut JSObject) -> Rc<Self>;
/// Returns the underlying `CallbackObject`.
fn callback_holder(&self) -> &CallbackObject;
fn callback_holder(&self) -> &CallbackObject<TH>;
/// Returns the underlying `JSObject`.
fn callback(&self) -> *mut JSObject {
self.callback_holder().get()
@@ -119,7 +120,7 @@ pub trait CallbackContainer {
/// incumbent global when calling the callback.
///
/// ["callback context"]: https://heycam.github.io/webidl/#dfn-callback-context
fn incumbent(&self) -> Option<&GlobalScope> {
fn incumbent(&self) -> Option<&GlobalScope<TH>> {
self.callback_holder().incumbent.as_ref().map(Dom::deref)
}
}
@@ -128,21 +129,21 @@ pub trait CallbackContainer {
/// A common base class for representing IDL callback function types.
#[derive(JSTraceable, PartialEq)]
#[must_root]
pub struct CallbackFunction {
object: CallbackObject,
pub struct CallbackFunction<TH: TypeHolderTrait + 'static> {
object: CallbackObject<TH>,
}

impl CallbackFunction {
impl<TH: TypeHolderTrait> CallbackFunction<TH> {
/// Create a new `CallbackFunction` for this object.
#[allow(unrooted_must_root)]
pub fn new() -> CallbackFunction {
pub fn new() -> CallbackFunction<TH> {
CallbackFunction {
object: CallbackObject::new(),
}
}

/// Returns the underlying `CallbackObject`.
pub fn callback_holder(&self) -> &CallbackObject {
pub fn callback_holder(&self) -> &CallbackObject<TH> {
&self.object
}

@@ -159,20 +160,20 @@ impl CallbackFunction {
/// A common base class for representing IDL callback interface types.
#[derive(JSTraceable, PartialEq)]
#[must_root]
pub struct CallbackInterface {
object: CallbackObject,
pub struct CallbackInterface<TH: TypeHolderTrait + 'static> {
object: CallbackObject<TH>,
}

impl CallbackInterface {
impl<TH: TypeHolderTrait> CallbackInterface<TH> {
/// Create a new CallbackInterface object for the given `JSObject`.
pub fn new() -> CallbackInterface {
pub fn new() -> CallbackInterface<TH> {
CallbackInterface {
object: CallbackObject::new(),
}
}

/// Returns the underlying `CallbackObject`.
pub fn callback_holder(&self) -> &CallbackObject {
pub fn callback_holder(&self) -> &CallbackObject<TH> {
&self.object
}

@@ -220,10 +221,10 @@ pub fn wrap_call_this_object<T: DomObject>(cx: *mut JSContext,

/// A class that performs whatever setup we need to safely make a call while
/// this class is on the stack. After `new` returns, the call is safe to make.
pub struct CallSetup {
pub struct CallSetup<TH: TypeHolderTrait + 'static> {
/// The global for reporting exceptions. This is the global object of the
/// (possibly wrapped) callback object.
exception_global: DomRoot<GlobalScope>,
exception_global: DomRoot<GlobalScope<TH>>,
/// The `JSContext` used for the call.
cx: *mut JSContext,
/// The compartment we were in before the call.
@@ -232,19 +233,19 @@ pub struct CallSetup {
handling: ExceptionHandling,
/// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
/// steps 8 and 18.2.
entry_script: Option<AutoEntryScript>,
entry_script: Option<AutoEntryScript<TH>>,
/// <https://heycam.github.io/webidl/#es-invoking-callback-functions>
/// steps 9 and 18.1.
incumbent_script: Option<AutoIncumbentScript>,
incumbent_script: Option<AutoIncumbentScript<TH>>,
}

impl CallSetup {
impl<TH: TypeHolderTrait> CallSetup<TH> {
/// Performs the setup needed to make a call.
#[allow(unrooted_must_root)]
pub fn new<T: CallbackContainer>(callback: &T,
pub fn new<T: CallbackContainer<TH>>(callback: &T,
handling: ExceptionHandling)
-> CallSetup {
let global = unsafe { GlobalScope::from_object(callback.callback()) };
-> CallSetup<TH> {
let global = unsafe { GlobalScope::<TH>::from_object(callback.callback()) };
let cx = global.get_cx();

let aes = AutoEntryScript::new(&global);
@@ -265,14 +266,14 @@ impl CallSetup {
}
}

impl Drop for CallSetup {
impl<TH: TypeHolderTrait> Drop for CallSetup<TH> {
fn drop(&mut self) {
unsafe {
JS_LeaveCompartment(self.cx, self.old_compartment);
if self.handling == ExceptionHandling::Report {
let _ac = JSAutoCompartment::new(self.cx,
self.exception_global.reflector().get_jsobject().get());
report_pending_exception(self.cx, true);
report_pending_exception::<TH>(self.cx, true);
}
drop(self.incumbent_script.take());
drop(self.entry_script.take().unwrap());
@@ -39,3 +39,8 @@ DOMInterfaces = {
}

}
TypeHolded = [
'DOMParser',
'XMLHttpRequest',
'ServoParser',
]

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -24,6 +24,7 @@ def __init__(self, filename, parseData):
self.descriptors = []
self.interfaces = {}
self.maxProtoChainLength = 0
self.typeHolded = glbl['TypeHolded']
for thing in parseData:
# Servo does not support external interfaces.
if isinstance(thing, IDLExternalInterface):
@@ -138,6 +139,9 @@ def getDescriptorProvider(self):
"""
return DescriptorProvider(self)

def getTypeHolded(self):
return self.typeHolded


class NoSuchDescriptorError(TypeError):
def __init__(self, str):
@@ -182,8 +186,11 @@ def __init__(self, config, interface, desc):

# Read the desc, and fill in the relevant defaults.
ifaceName = self.interface.identifier.name
nativeTypeDefault = ifaceName

self.isGeneric = False
self.typeHolded = False
typeName = desc.get('nativeType', ifaceName)
genericTypeName = typeName
self.concreteWithDisambiguator = typeName
# For generated iterator interfaces for other iterable interfaces, we
# just use IterableIterator as the native type, templated on the
# nativeType of the iterable interface. That way we can have a
@@ -192,35 +199,45 @@ def __init__(self, config, interface, desc):
if self.interface.isIteratorInterface():
itrName = self.interface.iterableInterface.identifier.name
itrDesc = self.getDescriptor(itrName)
nativeTypeDefault = iteratorNativeType(itrDesc)

typeName = desc.get('nativeType', nativeTypeDefault)

self.isGeneric = itrDesc.isGeneric
self.typeHolded = itrDesc.typeHolded
typeName = desc.get('nativeType', iteratorNativeType(itrDesc))
genericTypeName = typeName
self.concreteWithDisambiguator = typeName
else:
genericTypeName = '%s<TH>' % typeName
self.concreteWithDisambiguator = '%s::<TH>' % typeName
self.isGeneric = True
if typeName in config.getTypeHolded():
genericTypeName = 'TH::%s' % typeName
self.concreteWithDisambiguator = 'TH::%s' % typeName
self.isGeneric = True
self.typeHolded = True
spiderMonkeyInterface = desc.get('spiderMonkeyInterface', False)

# Callback and SpiderMonkey types do not use JS smart pointers, so we should not use the
# built-in rooting mechanisms for them.
if spiderMonkeyInterface:
self.returnType = 'Rc<%s>' % typeName
self.argumentType = '&%s' % typeName
self.returnType = 'Rc<%s>' % genericTypeName
self.argumentType = '&%s' % genericTypeName
self.nativeType = typeName
pathDefault = 'dom::types::%s' % typeName
elif self.interface.isCallback():
ty = 'dom::bindings::codegen::Bindings::%sBinding::%s' % (ifaceName, ifaceName)
pathDefault = ty
self.returnType = "Rc<%s>" % ty
self.returnType = "Rc<%s>" % genericTypeName
self.argumentType = "???"
self.nativeType = ty
else:
self.returnType = "DomRoot<%s>" % typeName
self.argumentType = "&%s" % typeName
self.nativeType = "*const %s" % typeName
self.returnType = "DomRoot<%s>" % genericTypeName
self.argumentType = "&%s" % genericTypeName
self.nativeType = "*const %s" % genericTypeName
if self.interface.isIteratorInterface():
pathDefault = 'dom::bindings::iterable::IterableIterator'
else:
pathDefault = 'dom::types::%s' % MakeNativeName(typeName)

self.concreteType = typeName
self.concreteType = genericTypeName
self.register = desc.get('register', True)
self.path = desc.get('path', pathDefault)
self.bindingPath = 'dom::bindings::codegen::Bindings::%s' % ('::'.join([ifaceName + 'Binding'] * 2))
@@ -481,4 +498,4 @@ def iteratorNativeType(descriptor, infer=False):
assert descriptor.interface.isIterable()
iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable
assert iterableDecl.isPairIterator()
return "IterableIterator%s" % ("" if infer else '<%s>' % descriptor.interface.identifier.name)
return "IterableIterator%s" % ("" if infer else '<%s>' % descriptor.concreteType)
@@ -224,7 +224,6 @@ def getDeps(self, visited=None):

return deps


class IDLScope(IDLObject):
def __init__(self, location, parentScope, identifier):
IDLObject.__init__(self, location)
@@ -1962,6 +1961,12 @@ def _getDependentObjects(self):
deps.add(self.parent)
return deps

def isGenericOverTypeHolder(self):
for member in self.members:
if member.isGenericOverTypeHolder():
return True
return bool(self.parent) and self.parent.isGenericOverTypeHolder()


class IDLEnum(IDLObjectWithIdentifier):
def __init__(self, location, parentScope, name, values):
@@ -2186,6 +2191,11 @@ def isDistinguishableFrom(self, other):
def isExposedInAllOf(self, exposureSet):
return True

def isGenericOverTypeHolder(self):
return self.isGeckoInterface() or self.isPromise()

def isTypeHolded(self):
return False

class IDLUnresolvedType(IDLType):
"""
@@ -2380,6 +2390,9 @@ def isDistinguishableFrom(self, other):
return False
return self.inner.isDistinguishableFrom(other)

def isGenericOverTypeHolder(self):
return self.inner.isGenericOverTypeHolder()


class IDLSequenceType(IDLParametrizedType):
def __init__(self, location, parameterType):
@@ -2452,6 +2465,9 @@ def isDistinguishableFrom(self, other):
other.isDictionary() or
other.isCallback() or other.isRecord())

def isGenericOverTypeHolder(self):
return self.inner.isGenericOverTypeHolder()


class IDLRecordType(IDLParametrizedType):
def __init__(self, location, keyType, valueType):
@@ -2636,6 +2652,14 @@ def hasPossiblyEmptyDictionaryType(self):
def _getDependentObjects(self):
return set(self.memberTypes)

def isGenericOverTypeHolder(self):
for member in self.memberTypes:
if member.isGenericOverTypeHolder():
return True
if self.unroll().name == 'TestDictionaryOrLong':
return True
return False


class IDLTypedefType(IDLType):
def __init__(self, location, innerType, name):
@@ -3790,6 +3814,7 @@ def __init__(self, location, identifier, keyType, valueType=None, scope=None):
"iterable", keyType, valueType,
IDLInterfaceMember.Tags.Iterable)
self.iteratorType = None
self.valueType = valueType

def __str__(self):
return "declared iterable with key '%s' and value '%s'" % (self.keyType, self.valueType)
@@ -3827,6 +3852,9 @@ def isValueIterator(self):
def isPairIterator(self):
return self.hasKeyType()

def isGenericOverTypeHolder(self):
return self.valueType.isGenericOverTypeHolder()

# MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):

@@ -4011,6 +4039,8 @@ def handleExtendedAttribute(self, attr):
def _getDependentObjects(self):
return set([self.type, self.value])

def isGenericOverTypeHolder(self):
return self.type.isGenericOverTypeHolder()

class IDLAttribute(IDLInterfaceMember):
def __init__(self, location, identifier, type, readonly, inherit=False,
@@ -4421,6 +4451,9 @@ def isUnforgeable(self):
def _getDependentObjects(self):
return set([self.type])

def isGenericOverTypeHolder(self):
return self.type.isGenericOverTypeHolder()


class IDLArgument(IDLObjectWithIdentifier):
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
@@ -4534,6 +4567,9 @@ def _getDependentObjects(self):
def canHaveMissingValue(self):
return self.optional and not self.defaultValue

def isGenericOverTypeHolder(self):
return self.type.isGenericOverTypeHolder()


class IDLCallback(IDLObjectWithScope):
def __init__(self, location, parentScope, identifier, returnType, arguments):
@@ -4624,6 +4660,8 @@ def isDistinguishableFrom(self, other):
def _getDependentObjects(self):
return self.callback._getDependentObjects()

def isGenericOverTypeHolder(self):
return True

class IDLMethodOverload:
"""
@@ -4645,6 +4683,11 @@ def _getDependentObjects(self):
deps.add(self.returnType)
return deps

def isGenericOverTypeHolder(self):
for argument in self.arguments:
if argument.isGenericOverTypeHolder():
return True
return self.returnType.isGenericOverTypeHolder()

class IDLMethod(IDLInterfaceMember, IDLScope):

@@ -5137,6 +5180,11 @@ def _getDependentObjects(self):
deps.update(overload._getDependentObjects())
return deps

def isGenericOverTypeHolder(self):
for overload in self._overloads:
if overload.isGenericOverTypeHolder():
return True
return False

class IDLImplementsStatement(IDLObject):
def __init__(self, location, implementor, implementee):
@@ -60,6 +60,7 @@ use libc;
use num_traits::Float;
use servo_config::opts;
use std::{char, ffi, ptr, slice};
use typeholder::TypeHolderTrait;

/// A trait to check whether a given `JSObject` implements an IDL interface.
pub trait IDLInterface {
@@ -321,7 +322,7 @@ impl FromJSValConvertible for ByteString {
}


impl ToJSValConvertible for Reflector {
impl<TH: TypeHolderTrait> ToJSValConvertible for Reflector<TH> {
unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {
let obj = self.get_jsobject().get();
assert!(!obj.is_null());
@@ -23,6 +23,7 @@ use js::rust::wrappers::JS_GetPendingException;
use js::rust::wrappers::JS_SetPendingException;
use libc::c_uint;
use std::slice::from_raw_parts;
use typeholder::TypeHolderTrait;

/// DOM exceptions that can be thrown by a native DOM method.
#[derive(Clone, Debug, MallocSizeOf)]
@@ -87,7 +88,7 @@ pub type Fallible<T> = Result<T, Error>;
pub type ErrorResult = Fallible<()>;

/// Set a pending exception for the given `result` on `cx`.
pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, result: Error) {
pub unsafe fn throw_dom_exception<TH: TypeHolderTrait>(cx: *mut JSContext, global: &GlobalScope<TH>, result: Error) {
let code = match result {
Error::IndexSize => DOMErrorName::IndexSizeError,
Error::NotFound => DOMErrorName::NotFoundError,
@@ -182,8 +183,8 @@ impl ErrorInfo {
})
}

fn from_dom_exception(object: HandleObject) -> Option<ErrorInfo> {
let exception = match root_from_object::<DOMException>(object.get()) {
fn from_dom_exception<TH: TypeHolderTrait>(object: HandleObject) -> Option<ErrorInfo> {
let exception = match root_from_object::<DOMException<TH>>(object.get()) {
Ok(exception) => exception,
Err(_) => return None,
};
@@ -201,7 +202,7 @@ impl ErrorInfo {
///
/// The `dispatch_event` argument is temporary and non-standard; passing false
/// prevents dispatching the `error` event.
pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool) {
pub unsafe fn report_pending_exception<TH: TypeHolderTrait>(cx: *mut JSContext, dispatch_event: bool) {
if !JS_IsExceptionPending(cx) { return; }

rooted!(in(cx) let mut value = UndefinedValue());
@@ -215,7 +216,7 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
let error_info = if value.is_object() {
rooted!(in(cx) let object = value.to_object());
ErrorInfo::from_native_error(cx, object.handle())
.or_else(|| ErrorInfo::from_dom_exception(object.handle()))
.or_else(|| ErrorInfo::from_dom_exception::<TH>(object.handle()))
.unwrap_or_else(|| {
ErrorInfo {
message: format!("uncaught exception: unknown (can't convert to string)"),
@@ -247,7 +248,7 @@ pub unsafe fn report_pending_exception(cx: *mut JSContext, dispatch_event: bool)
error_info.message);

if dispatch_event {
GlobalScope::from_context(cx)
GlobalScope::<TH>::from_context(cx)
.report_an_error(error_info, value.handle());
}
}
@@ -271,7 +272,7 @@ pub unsafe fn throw_invalid_this(cx: *mut JSContext, proto_id: u16) {

impl Error {
/// Convert this error value to a JS value, consuming it in the process.
pub unsafe fn to_jsval(self, cx: *mut JSContext, global: &GlobalScope, rval: MutableHandleValue) {
pub unsafe fn to_jsval<TH: TypeHolderTrait>(self, cx: *mut JSContext, global: &GlobalScope<TH>, rval: MutableHandleValue) {
assert!(!JS_IsExceptionPending(cx));
throw_dom_exception(cx, global, self);
assert!(JS_IsExceptionPending(cx));
@@ -86,10 +86,11 @@ use js::rust::HandleObject;
use js::rust::MutableHandleObject;
use script_thread::ScriptThread;
use std::ptr;
use typeholder::TypeHolderTrait;

// https://html.spec.whatwg.org/multipage/#htmlconstructor
pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fallible<DomRoot<T>>
where T: DerivedFrom<Element> {
pub unsafe fn html_constructor<T, TH: TypeHolderTrait>(window: &Window<TH>, call_args: &CallArgs) -> Fallible<DomRoot<T>>
where T: DerivedFrom<Element<TH>> {
let document = window.Document();

// Step 1
@@ -119,11 +120,11 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall
// Since this element is autonomous, its active function object must be the HTMLElement

// Retrieve the constructor object for HTMLElement
HTMLElementBinding::GetConstructorObject(window.get_cx(), global_object.handle(), constructor.handle_mut());
HTMLElementBinding::GetConstructorObject::<TH>(window.get_cx(), global_object.handle(), constructor.handle_mut());

} else {
// Step 5
get_constructor_object_from_local_name(definition.local_name.clone(),
get_constructor_object_from_local_name::<TH>(definition.local_name.clone(),
window.get_cx(),
global_object.handle(),
constructor.handle_mut());
@@ -176,14 +177,14 @@ pub unsafe fn html_constructor<T>(window: &Window, call_args: &CallArgs) -> Fall

/// Returns the constructor object for the element associated with the given local name.
/// This list should only include elements marked with the [HTMLConstructor] extended attribute.
pub fn get_constructor_object_from_local_name(name: LocalName,
pub fn get_constructor_object_from_local_name<TH: TypeHolderTrait>(name: LocalName,
cx: *mut JSContext,
global: HandleObject,
rval: MutableHandleObject)
-> bool {
macro_rules! get_constructor(
($binding:ident) => ({
unsafe { $binding::GetConstructorObject(cx, global, rval); }
unsafe { $binding::GetConstructorObject::<TH>(cx, global, rval); }
true
})
);
@@ -317,10 +318,10 @@ pub fn get_constructor_object_from_local_name(name: LocalName,
}
}

pub fn pop_current_element_queue() {
ScriptThread::pop_current_element_queue();
pub fn pop_current_element_queue<TH: TypeHolderTrait>() {
ScriptThread::<TH>::pop_current_element_queue();
}

pub fn push_new_element_queue() {
ScriptThread::push_new_element_queue();
pub fn push_new_element_queue<TH: TypeHolderTrait>() {
ScriptThread::<TH>::push_new_element_queue();
}
@@ -21,6 +21,7 @@ use js::rust::{HandleValue, MutableHandleObject};
use std::cell::Cell;
use std::ptr;
use std::ptr::NonNull;
use std::marker::PhantomData;

/// The values that an iterator will iterate over.
#[derive(JSTraceable, MallocSizeOf)]
@@ -48,10 +49,9 @@ pub trait Iterable {
}

/// An iterator over the iterable entries of a given DOM interface.
//FIXME: #12811 prevents dom_struct with type parameters
#[dom_struct]
pub struct IterableIterator<T: DomObject + JSTraceable + Iterable> {
reflector: Reflector,
reflector: Reflector<T::TypeHolder>,
iterable: Dom<T>,
type_: IteratorType,
index: Cell<u32>,
@@ -61,15 +61,15 @@ impl<T: DomObject + JSTraceable + Iterable> IterableIterator<T> {
/// Create a new iterator instance for the provided iterable DOM interface.
pub fn new(iterable: &T,
type_: IteratorType,
wrap: unsafe fn(*mut JSContext, &GlobalScope, Box<IterableIterator<T>>)
wrap: unsafe fn(*mut JSContext, &GlobalScope<T::TypeHolder>, Box<IterableIterator<T>>)
-> DomRoot<Self>) -> DomRoot<Self> {
let iterator = Box::new(IterableIterator {
reflector: Reflector::new(),
type_: type_,
iterable: Dom::from_ref(iterable),
index: Cell::new(0),
});
reflect_dom_object(iterator, &*iterable.global(), wrap)
reflect_dom_object::<Self, GlobalScope<T::TypeHolder>,T::TypeHolder>(iterator, &*iterable.global(), wrap)
}

/// Return the next value from the iterable object.
@@ -130,8 +130,6 @@
//! (error/enum.Error.html).

#![allow(unsafe_code)]
#![deny(missing_docs)]
#![deny(non_snake_case)]

pub mod callback;
pub mod cell;
@@ -38,17 +38,18 @@ use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::{Arc, Weak};
use task::TaskOnce;
use typeholder::TypeHolderTrait;


#[allow(missing_docs)] // FIXME
mod dummy { // Attributes don’t apply through the macro.
use std::cell::RefCell;
use std::rc::Rc;
use super::LiveDOMReferences;
thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> =
Rc::new(RefCell::new(None)));
use super::LiveDOMReferencesTrait;
// thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<Box<LiveDOMReferencesTrait>>>> =
// Rc::new(RefCell::new(None)));
}
pub use self::dummy::LIVE_REFERENCES;
// pub use self::dummy::LIVE_REFERENCES;


/// A pointer to a Rust DOM object that needs to be destroyed.
@@ -64,57 +65,59 @@ impl TrustedReference {
/// A safe wrapper around a DOM Promise object that can be shared among threads for use
/// in asynchronous operations. The underlying DOM object is guaranteed to live at least
/// as long as the last outstanding `TrustedPromise` instance. These values cannot be cloned,
/// only created from existing Rc<Promise> values.
pub struct TrustedPromise {
dom_object: *const Promise,
/// only created from existing Rc<Promise<TH>> values.
pub struct TrustedPromise<TH: TypeHolderTrait + 'static> {
dom_object: *const Promise<TH>,
owner_thread: *const libc::c_void,
}

unsafe impl Send for TrustedPromise {}
unsafe impl<TH: TypeHolderTrait> Send for TrustedPromise<TH> {}

impl TrustedPromise {
impl<TH: TypeHolderTrait> TrustedPromise<TH> {
/// Create a new `TrustedPromise` instance from an existing DOM object. The object will
/// be prevented from being GCed for the duration of the resulting `TrustedPromise` object's
/// lifetime.
#[allow(unrooted_must_root)]
pub fn new(promise: Rc<Promise>) -> TrustedPromise {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
let ptr = &*promise as *const Promise;
live_references.addref_promise(promise);
TrustedPromise {
dom_object: ptr,
owner_thread: (&*live_references) as *const _ as *const libc::c_void,
}
})
pub fn new(promise: Rc<Promise<TH>>) -> TrustedPromise<TH> {
// LIVE_REFERENCES.with(|ref r| {
// let r = r.borrow();
// let live_references = r.as_ref().unwrap();
// let ptr = &*promise as *const Promise;
// live_references.addref_promise(promise);
// TrustedPromise {
// dom_object: ptr,
// owner_thread: (&*live_references) as *const _ as *const libc::c_void,
// }
// })
unimplemented!();
}

/// Obtain a usable DOM Promise from a pinned `TrustedPromise` value. Fails if used on
/// a different thread than the original value from which this `TrustedPromise` was
/// obtained.
#[allow(unrooted_must_root)]
pub fn root(self) -> Rc<Promise> {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
assert_eq!(self.owner_thread, (&*live_references) as *const _ as *const libc::c_void);
// Borrow-check error requires the redundant `let promise = ...; promise` here.
let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) {
Occupied(mut entry) => {
let promise = {
let promises = entry.get_mut();
promises.pop().expect("rooted promise list unexpectedly empty")
};
if entry.get().is_empty() {
entry.remove();
}
promise
}
Vacant(_) => unreachable!(),
};
promise
})
pub fn root(self) -> Rc<Promise<TH>> {
// LIVE_REFERENCES.with(|ref r| {
// let r = r.borrow();
// let live_references = r.as_ref().unwrap();
// assert_eq!(self.owner_thread, (&*live_references) as *const _ as *const libc::c_void);
// // Borrow-check error requires the redundant `let promise = ...; promise` here.
// let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) {
// Occupied(mut entry) => {
// let promise = {
// let promises = entry.get_mut();
// promises.pop().expect("rooted promise list unexpectedly empty")
// };
// if entry.get().is_empty() {
// entry.remove();
// }
// promise
// }
// Vacant(_) => unreachable!(),
// };
// promise
// })
unimplemented!();
}

/// A task which will reject the promise.
@@ -161,27 +164,29 @@ impl<T: DomObject> Trusted<T> {
/// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's
/// lifetime.
pub fn new(ptr: &T) -> Trusted<T> {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
let refcount = live_references.addref(&*ptr as *const T);
Trusted {
refcount: refcount,
owner_thread: (&*live_references) as *const _ as *const libc::c_void,
phantom: PhantomData,
}
})
// LIVE_REFERENCES.with(|ref r| {
// let r = r.borrow();
// let live_references = r.as_ref().unwrap();
// let refcount = live_references.addref(&*ptr as *const T);
// Trusted {
// refcount: refcount,
// owner_thread: (&*live_references) as *const _ as *const libc::c_void,
// phantom: PhantomData,
// }
// })
unimplemented!();

}

/// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on
/// a different thread than the original value from which this `Trusted<T>` was
/// obtained.
pub fn root(&self) -> DomRoot<T> {
assert!(LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
}));
// assert!(LIVE_REFERENCES.with(|ref r| {
// let r = r.borrow();
// let live_references = r.as_ref().unwrap();
// self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
// }));
unsafe {
DomRoot::from_ref(&*(self.refcount.0 as *const T))
}
@@ -201,25 +206,29 @@ impl<T: DomObject> Clone for Trusted<T> {
/// The set of live, pinned DOM objects that are currently prevented
/// from being garbage collected due to outstanding references.
#[allow(unrooted_must_root)]
pub struct LiveDOMReferences {
pub struct LiveDOMReferences<TH: TypeHolderTrait + 'static> {
// keyed on pointer to Rust DOM object
reflectable_table: RefCell<HashMap<*const libc::c_void, Weak<TrustedReference>>>,
promise_table: RefCell<HashMap<*const Promise, Vec<Rc<Promise>>>>,
promise_table: RefCell<HashMap<*const Promise<TH>, Vec<Rc<Promise<TH>>>>>,
}

pub trait LiveDOMReferencesTrait {

}

impl LiveDOMReferences {
impl<TH: TypeHolderTrait> LiveDOMReferences<TH> {
/// Set up the thread-local data required for storing the outstanding DOM references.
pub fn initialize() {
LIVE_REFERENCES.with(|ref r| {
*r.borrow_mut() = Some(LiveDOMReferences {
reflectable_table: RefCell::new(HashMap::new()),
promise_table: RefCell::new(HashMap::new()),
})
});
// LIVE_REFERENCES.with(|ref r| {
// *r.borrow_mut() = Some(LiveDOMReferences {
// reflectable_table: RefCell::new(HashMap::new()),
// promise_table: RefCell::new(HashMap::new()),
// })
// });
}

#[allow(unrooted_must_root)]
fn addref_promise(&self, promise: Rc<Promise>) {
fn addref_promise(&self, promise: Rc<Promise<TH>>) {
let mut table = self.promise_table.borrow_mut();
table.entry(&*promise).or_insert(vec![]).push(promise)
}
@@ -268,23 +277,23 @@ fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) {
#[allow(unrooted_must_root)]
pub unsafe fn trace_refcounted_objects(tracer: *mut JSTracer) {
info!("tracing live refcounted references");
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
{
let mut table = live_references.reflectable_table.borrow_mut();
remove_nulls(&mut table);
for obj in table.keys() {
let reflectable = &*(*obj as *const Reflector);
trace_reflector(tracer, "refcounted", reflectable);
}
}
// LIVE_REFERENCES.with(|ref r| {
// let r = r.borrow();
// let live_references = r.as_ref().unwrap();
// {
// let mut table = live_references.reflectable_table.borrow_mut();
// remove_nulls(&mut table);
// for obj in table.keys() {
// let reflectable = &*(*obj as *const Reflector);
// trace_reflector(tracer, "refcounted", reflectable);
// }
// }

{
let table = live_references.promise_table.borrow_mut();
for promise in table.keys() {
trace_reflector(tracer, "refcounted", (**promise).reflector());
}
}
});
// {
// let table = live_references.promise_table.borrow_mut();
// for promise in table.keys() {
// trace_reflector(tracer, "refcounted", (**promise).reflector());
// }
// }
// });
}
@@ -10,15 +10,17 @@ use dom::globalscope::GlobalScope;
use js::jsapi::{JSContext, JSObject, Heap};
use js::rust::HandleObject;
use std::default::Default;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;

/// Create the reflector for a new DOM object and yield ownership to the
/// reflector.
pub fn reflect_dom_object<T, U>(
pub fn reflect_dom_object<T, U, TH: TypeHolderTrait>(
obj: Box<T>,
global: &U,
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope, Box<T>) -> DomRoot<T>)
wrap_fn: unsafe fn(*mut JSContext, &GlobalScope<TH>, Box<T>) -> DomRoot<T>)
-> DomRoot<T>
where T: DomObject, U: DerivedFrom<GlobalScope>
where T: DomObject, U: DerivedFrom<GlobalScope<TH>>
{
let global_scope = global.upcast();
unsafe {
@@ -31,19 +33,20 @@ pub fn reflect_dom_object<T, U>(
#[derive(MallocSizeOf)]
#[must_root]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
pub struct Reflector<TH: TypeHolderTrait> {
#[ignore_malloc_size_of = "defined and measured in rust-mozjs"]
object: Heap<*mut JSObject>,
_p: PhantomData<TH>,
}

#[allow(unrooted_must_root)]
impl PartialEq for Reflector {
fn eq(&self, other: &Reflector) -> bool {
impl<TH: TypeHolderTrait> PartialEq for Reflector<TH> {
fn eq(&self, other: &Reflector<TH>) -> bool {
self.object.get() == other.object.get()
}
}

impl Reflector {
impl<TH: TypeHolderTrait> Reflector<TH> {
/// Get the reflector.
#[inline]
pub fn get_jsobject(&self) -> HandleObject {
@@ -66,38 +69,54 @@ impl Reflector {
}

/// Create an uninitialized `Reflector`.
pub fn new() -> Reflector {
pub fn new() -> Reflector<TH> {
Reflector {
object: Heap::default(),
_p: Default::default(),
}
}
}

/// A trait to provide access to the `Reflector` for a DOM object.
pub trait DomObject: 'static {
type TypeHolder: TypeHolderTrait;
/// Returns the receiver's reflector.
fn reflector(&self) -> &Reflector;
fn reflector(&self) -> &Reflector<Self::TypeHolder>;

/// Returns the global scope of the realm that the DomObject was created in.
fn global(&self) -> DomRoot<GlobalScope> where Self: Sized {
GlobalScope::from_reflector(self)
fn global(&self) -> DomRoot<GlobalScope<Self::TypeHolder>> where Self: Sized {
GlobalScope::<Self::TypeHolder>::from_reflector(self)
}
}

impl DomObject for Reflector {
impl<TH: TypeHolderTrait> DomObject for Reflector<TH> {
type TypeHolder = TH;
fn reflector(&self) -> &Self {
self
}
}

impl<S: DomObject + ?Sized> DomObject for Box<S> {
type TypeHolder = S::TypeHolder;
fn reflector(&self) -> &Reflector<Self::TypeHolder> {
(*self).reflector()
}
}

/// A trait to initialize the `Reflector` for a DOM object.
pub trait MutDomObject: DomObject {
/// Initializes the Reflector
fn init_reflector(&mut self, obj: *mut JSObject);
}

impl MutDomObject for Reflector {
impl<TH: TypeHolderTrait> MutDomObject for Reflector<TH> {
fn init_reflector(&mut self, obj: *mut JSObject) {
self.set_jsobject(obj)
}
}

// impl <S: MutDomObject + ?Sized> MutDomObject for Box<S> {
// fn init_reflector(&mut self, obj: *mut JSObject) {
// (*self).init_reflector(obj)
// }
// }
@@ -44,6 +44,7 @@ use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use style::thread_state;
use typeholder::TypeHolderTrait;

/// A rooted value.
#[allow(unrooted_must_root)]
@@ -68,7 +69,7 @@ where
STACK_ROOTS.with(|ref root_list| {
let root_list = &*root_list.get().unwrap();
root_list.root(value.stable_trace_object());
Root { value, root_list }
Root { value, root_list}
})
}
}
@@ -83,21 +84,21 @@ pub unsafe trait StableTraceObject {

unsafe impl<T> StableTraceObject for Dom<T>
where
T: DomObject,
T: DomObject
{
fn stable_trace_object<'a>(&'a self) -> *const JSTraceable {
// The JSTraceable impl for Reflector doesn't actually do anything,
// so we need this shenanigan to actually trace the reflector of the
// T pointer in Dom<T>.
#[allow(unrooted_must_root)]
struct ReflectorStackRoot(Reflector);
unsafe impl JSTraceable for ReflectorStackRoot {
struct ReflectorStackRoot<TH: TypeHolderTrait>(Reflector<TH>);
unsafe impl<TH: TypeHolderTrait> JSTraceable for ReflectorStackRoot<TH> {
unsafe fn trace(&self, tracer: *mut JSTracer) {
trace_reflector(tracer, "on stack", &self.0);
}
}
unsafe {
&*(self.reflector() as *const Reflector as *const ReflectorStackRoot)
&*(self.reflector() as *const Reflector<T::TypeHolder> as *const ReflectorStackRoot<T::TypeHolder>)
}
}
}
@@ -158,7 +159,7 @@ impl<T: DomObject> DomRoot<T> {

impl<T> MallocSizeOf for DomRoot<T>
where
T: DomObject + MallocSizeOf,
T: DomObject + MallocSizeOf
{
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
(**self).size_of(ops)
@@ -167,7 +168,7 @@ where

impl<T> PartialEq for DomRoot<T>
where
T: DomObject,
T: DomObject
{
fn eq(&self, other: &Self) -> bool {
self.value == other.value
@@ -176,7 +177,7 @@ where

impl<T> Clone for DomRoot<T>
where
T: DomObject,
T: DomObject
{
fn clone(&self) -> DomRoot<T> {
DomRoot::from_ref(&*self)
@@ -185,7 +186,7 @@ where

unsafe impl<T> JSTraceable for DomRoot<T>
where
T: DomObject,
T: DomObject
{
unsafe fn trace(&self, _: *mut JSTracer) {
// Already traced.
@@ -466,14 +467,14 @@ impl <T> Clone for LayoutDom<T> {
}
}

impl LayoutDom<Node> {
impl<TH: TypeHolderTrait> LayoutDom<Node<TH>> {
/// Create a new JS-owned value wrapped from an address known to be a
/// `Node` pointer.
pub unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> LayoutDom<Node> {
pub unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> LayoutDom<Node<TH>> {
debug_assert!(thread_state::get().is_layout());
let TrustedNodeAddress(addr) = inner;
LayoutDom {
ptr: ptr::NonNull::new_unchecked(addr as *const Node as *mut Node),
ptr: ptr::NonNull::new_unchecked(addr as *const Node<TH> as *mut Node<TH>),
}
}
}
@@ -12,8 +12,10 @@ use js::jsapi::UnhideScriptedCaller;
use js::rust::Runtime;
use std::cell::RefCell;
use std::thread;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;

thread_local!(static STACK: RefCell<Vec<StackEntry>> = RefCell::new(Vec::new()));
// thread_local!(static STACK: RefCell<Vec<Box<StackEntryTrait>>> = RefCell::new(Vec::new()));

#[derive(Debug, Eq, JSTraceable, PartialEq)]
enum StackEntryKind {
@@ -23,135 +25,145 @@ enum StackEntryKind {

#[allow(unrooted_must_root)]
#[derive(JSTraceable)]
struct StackEntry {
global: Dom<GlobalScope>,
struct StackEntry<TH: TypeHolderTrait + 'static> {
global: Dom<GlobalScope<TH>>,
kind: StackEntryKind,
}

trait StackEntryTrait {}

/// Traces the script settings stack.
pub unsafe fn trace(tracer: *mut JSTracer) {
STACK.with(|stack| {
stack.borrow().trace(tracer);
})
// STACK.with(|stack| {
// stack.borrow().trace(tracer);
// })
}

pub fn is_execution_stack_empty() -> bool {
STACK.with(|stack| {
stack.borrow().is_empty()
})
// STACK.with(|stack| {
// stack.borrow().is_empty()
// })
false
}

/// RAII struct that pushes and pops entries from the script settings stack.
pub struct AutoEntryScript {
global: DomRoot<GlobalScope>,
pub struct AutoEntryScript<TH: TypeHolderTrait + 'static> {
global: DomRoot<GlobalScope<TH>>,
}

impl AutoEntryScript {
impl<TH: TypeHolderTrait> AutoEntryScript<TH> {
/// <https://html.spec.whatwg.org/multipage/#prepare-to-run-script>
pub fn new(global: &GlobalScope) -> Self {
STACK.with(|stack| {
trace!("Prepare to run script with {:p}", global);
let mut stack = stack.borrow_mut();
stack.push(StackEntry {
global: Dom::from_ref(global),
kind: StackEntryKind::Entry,
});
AutoEntryScript {
global: DomRoot::from_ref(global),
}
})
pub fn new(global: &GlobalScope<TH>) -> Self {
// STACK.with(|stack| {
// trace!("Prepare to run script with {:p}", global);
// let mut stack = stack.borrow_mut();
// stack.push(StackEntry {
// global: Dom::from_ref(global),
// kind: StackEntryKind::Entry,
// });
// AutoEntryScript {
// global: DomRoot::from_ref(global),
// }
// })
unimplemented!();
}
}

impl Drop for AutoEntryScript {
impl<TH: TypeHolderTrait> Drop for AutoEntryScript<TH> {
/// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-script>
fn drop(&mut self) {
STACK.with(|stack| {
let mut stack = stack.borrow_mut();
let entry = stack.pop().unwrap();
assert_eq!(&*entry.global as *const GlobalScope,
&*self.global as *const GlobalScope,
"Dropped AutoEntryScript out of order.");
assert_eq!(entry.kind, StackEntryKind::Entry);
trace!("Clean up after running script with {:p}", &*entry.global);
});

// Step 5
if !thread::panicking() && incumbent_global().is_none() {
self.global.perform_a_microtask_checkpoint();
}
// STACK.with(|stack| {
// let mut stack = stack.borrow_mut();
// let entry = stack.pop().unwrap();
// assert_eq!(&*entry.global as *const GlobalScope<TH>,
// &*self.global as *const GlobalScope<TH>,
// "Dropped AutoEntryScript out of order.");
// assert_eq!(entry.kind, StackEntryKind::Entry);
// trace!("Clean up after running script with {:p}", &*entry.global);
// });

// // Step 5
// if !thread::panicking() && incumbent_global().is_none() {
// self.global.perform_a_microtask_checkpoint();
// }
}
}

/// Returns the ["entry"] global object.
///
/// ["entry"]: https://html.spec.whatwg.org/multipage/#entry
pub fn entry_global() -> DomRoot<GlobalScope> {
STACK.with(|stack| {
stack.borrow()
.iter()
.rev()
.find(|entry| entry.kind == StackEntryKind::Entry)
.map(|entry| DomRoot::from_ref(&*entry.global))
}).unwrap()
pub fn entry_global<TH: TypeHolderTrait>() -> DomRoot<GlobalScope<TH>> {
// STACK.with(|stack| {
// stack.borrow()
// .iter()
// .rev()
// .find(|entry| entry.kind == StackEntryKind::Entry)
// .map(|entry| DomRoot::from_ref(&*entry.global))
// }).unwrap()
unimplemented!();
}

/// RAII struct that pushes and pops entries from the script settings stack.
pub struct AutoIncumbentScript {
pub struct AutoIncumbentScript<TH: TypeHolderTrait + 'static> {
global: usize,
_p: PhantomData<TH>,
}

impl AutoIncumbentScript {
impl<TH: TypeHolderTrait> AutoIncumbentScript<TH> {
/// <https://html.spec.whatwg.org/multipage/#prepare-to-run-a-callback>
pub fn new(global: &GlobalScope) -> Self {
pub fn new(global: &GlobalScope<TH>) -> Self {
// Step 2-3.
unsafe {
let cx = Runtime::get();
assert!(!cx.is_null());
HideScriptedCaller(cx);
// unsafe {
// let cx = Runtime::get();
// assert!(!cx.is_null());
// HideScriptedCaller(cx);
// }
// STACK.with(|stack| {
// trace!("Prepare to run a callback with {:p}", global);
// // Step 1.
// let mut stack = stack.borrow_mut();
// stack.push(StackEntry {
// global: Dom::from_ref(global),
// kind: StackEntryKind::Incumbent,
// });
// AutoIncumbentScript {
// global: global as *const _ as usize,
// }
// })
AutoIncumbentScript {
global: 0,
_p: Default::default(),
}
STACK.with(|stack| {
trace!("Prepare to run a callback with {:p}", global);
// Step 1.
let mut stack = stack.borrow_mut();
stack.push(StackEntry {
global: Dom::from_ref(global),
kind: StackEntryKind::Incumbent,
});
AutoIncumbentScript {
global: global as *const _ as usize,
}
})
}
}

impl Drop for AutoIncumbentScript {
impl<TH: TypeHolderTrait> Drop for AutoIncumbentScript<TH> {
/// <https://html.spec.whatwg.org/multipage/#clean-up-after-running-a-callback>
fn drop(&mut self) {
STACK.with(|stack| {
// Step 4.
let mut stack = stack.borrow_mut();
let entry = stack.pop().unwrap();
// Step 3.
assert_eq!(&*entry.global as *const GlobalScope as usize,
self.global,
"Dropped AutoIncumbentScript out of order.");
assert_eq!(entry.kind, StackEntryKind::Incumbent);
trace!("Clean up after running a callback with {:p}", &*entry.global);
});
unsafe {
// Step 1-2.
let cx = Runtime::get();
assert!(!cx.is_null());
UnhideScriptedCaller(cx);
}
// STACK.with(|stack| {
// // Step 4.
// let mut stack = stack.borrow_mut();
// let entry = stack.pop().unwrap();
// // Step 3.
// assert_eq!(&*entry.global as *const GlobalScope<TH> as usize,
// self.global,
// "Dropped AutoIncumbentScript out of order.");
// assert_eq!(entry.kind, StackEntryKind::Incumbent);
// trace!("Clean up after running a callback with {:p}", &*entry.global);
// });
// unsafe {
// // Step 1-2.
// let cx = Runtime::get();
// assert!(!cx.is_null());
// UnhideScriptedCaller(cx);
// }
}
}

/// Returns the ["incumbent"] global object.
///
/// ["incumbent"]: https://html.spec.whatwg.org/multipage/#incumbent
pub fn incumbent_global() -> Option<DomRoot<GlobalScope>> {
pub fn incumbent_global<TH: TypeHolderTrait>() -> Option<DomRoot<GlobalScope<TH>>> {
// https://html.spec.whatwg.org/multipage/#incumbent-settings-object

// Step 1, 3: See what the JS engine has to say. If we've got a scripted
@@ -163,14 +175,15 @@ pub fn incumbent_global() -> Option<DomRoot<GlobalScope>> {
assert!(!cx.is_null());
let global = GetScriptedCallerGlobal(cx);
if !global.is_null() {
return Some(GlobalScope::from_object(global));
return Some(GlobalScope::<TH>::from_object(global));
}
}

// Step 2: nothing from the JS engine. Let's use whatever's on the explicit stack.
STACK.with(|stack| {
stack.borrow()
.last()
.map(|entry| DomRoot::from_ref(&*entry.global))
})
// STACK.with(|stack| {
// stack.borrow()
// .last()
// .map(|entry| DomRoot::from_ref(&*entry.global))
// })
None
}
@@ -26,6 +26,9 @@ use libc::size_t;
use std::os::raw;
use std::ptr;
use std::slice;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;


// TODO: Should we add Min and Max const to https://github.com/servo/rust-mozjs/blob/master/src/consts.rs?
// TODO: Determine for sure which value Min and Max should have.
@@ -103,18 +106,18 @@ impl StructuredCloneReader {
}
}

unsafe fn read_blob(cx: *mut JSContext,
unsafe fn read_blob<TH: TypeHolderTrait>(cx: *mut JSContext,
r: *mut JSStructuredCloneReader)
-> *mut JSObject {
let structured_reader = StructuredCloneReader { r: r };
let blob_buffer = structured_reader.read_bytes();
let type_str = structured_reader.read_str();
let target_global = GlobalScope::from_context(cx);
let target_global = GlobalScope::<TH>::from_context(cx);
let blob = Blob::new(&target_global, BlobImpl::new_from_bytes(blob_buffer), type_str);
return blob.reflector().get_jsobject().get()
}

unsafe fn write_blob(blob: DomRoot<Blob>,
unsafe fn write_blob<TH: TypeHolderTrait>(blob: DomRoot<Blob<TH>>,
w: *mut JSStructuredCloneWriter)
-> Result<(), ()> {
let structured_writer = StructuredCloneWriter { w: w };
@@ -125,7 +128,7 @@ unsafe fn write_blob(blob: DomRoot<Blob>,
return Ok(())
}

unsafe extern "C" fn read_callback(cx: *mut JSContext,
unsafe extern "C" fn read_callback<TH: TypeHolderTrait>(cx: *mut JSContext,
r: *mut JSStructuredCloneReader,
tag: u32,
_data: u32,
@@ -134,17 +137,17 @@ unsafe extern "C" fn read_callback(cx: *mut JSContext,
assert!(tag < StructuredCloneTags::Max as u32, "tag should be lower than StructuredCloneTags::Max");
assert!(tag > StructuredCloneTags::Min as u32, "tag should be higher than StructuredCloneTags::Min");
if tag == StructuredCloneTags::DomBlob as u32 {
return read_blob(cx, r)
return read_blob::<TH>(cx, r)
}
return ptr::null_mut()
}

unsafe extern "C" fn write_callback(_cx: *mut JSContext,
unsafe extern "C" fn write_callback<TH: TypeHolderTrait>(_cx: *mut JSContext,
w: *mut JSStructuredCloneWriter,
obj: RawHandleObject,
_closure: *mut raw::c_void)
-> bool {
if let Ok(blob) = root_from_handleobject::<Blob>(Handle::from_raw(obj)) {
if let Ok(blob) = root_from_handleobject::<Blob<TH>>(Handle::from_raw(obj)) {
return write_blob(blob, w).is_ok()
}
return false
@@ -182,28 +185,40 @@ unsafe extern "C" fn free_transfer_callback(_tag: u32,
unsafe extern "C" fn report_error_callback(_cx: *mut JSContext, _errorid: u32) {
}

static STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks = JSStructuredCloneCallbacks {
read: Some(read_callback),
write: Some(write_callback),
reportError: Some(report_error_callback),
readTransfer: Some(read_transfer_callback),
writeTransfer: Some(write_transfer_callback),
freeTransfer: Some(free_transfer_callback),
};


static mut STRUCTURED_CLONE_CALLBACKS: JSStructuredCloneCallbacks =
JSStructuredCloneCallbacks {
read: None,
write: None,
reportError: Some(report_error_callback),
readTransfer: Some(read_transfer_callback),
writeTransfer: Some(write_transfer_callback),
freeTransfer: Some(free_transfer_callback),
};

/// A buffer for a structured clone.
pub enum StructuredCloneData {
pub enum StructuredCloneData<TH: TypeHolderTrait + 'static> {
/// A non-serializable (default) variant
Struct(*mut u64, size_t),
/// A variant that can be serialized
Vector(Vec<u8>)
Vector(Vec<u8>),
_p(PhantomData<TH>),
}

unsafe fn init_structured_clone<TH: TypeHolderTrait>() {
STRUCTURED_CLONE_CALLBACKS.read = Some(read_callback::<TH>);
STRUCTURED_CLONE_CALLBACKS.write = Some(write_callback::<TH>);
}

impl StructuredCloneData {
impl<TH: TypeHolderTrait> StructuredCloneData<TH> {
/// Writes a structured clone. Returns a `DataClone` error if that fails.
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData> {
pub fn write(cx: *mut JSContext, message: HandleValue) -> Fallible<StructuredCloneData<TH>> {
let mut data = ptr::null_mut();
let mut nbytes = 0;
unsafe {
init_structured_clone::<TH>();
}
let result = unsafe {
JS_WriteStructuredClone(cx,
message,
@@ -230,20 +245,24 @@ impl StructuredCloneData {
slice::from_raw_parts(data as *mut u8, nbytes).to_vec()
}
}
StructuredCloneData::Vector(msg) => msg
StructuredCloneData::Vector(msg) => msg,
StructuredCloneData::_p(_) => return vec![],
}
}

/// Reads a structured clone.
///
/// Panics if `JS_ReadStructuredClone` fails.
fn read_clone(global: &GlobalScope,
fn read_clone(global: &GlobalScope<TH>,
data: *mut u64,
nbytes: size_t,
rval: MutableHandleValue) {
let cx = global.get_cx();
let globalhandle = global.reflector().get_jsobject();
let _ac = JSAutoCompartment::new(cx, globalhandle.get());
unsafe {
init_structured_clone::<TH>();
}
unsafe {
assert!(JS_ReadStructuredClone(cx,
data,
@@ -256,16 +275,17 @@ impl StructuredCloneData {
}

/// Thunk for the actual `read_clone` method. Resolves proper variant for read_clone.
pub fn read(self, global: &GlobalScope, rval: MutableHandleValue) {
pub fn read(self, global: &GlobalScope<TH>, rval: MutableHandleValue) {
match self {
StructuredCloneData::Vector(mut vec_msg) => {
let nbytes = vec_msg.len();
let data = vec_msg.as_mut_ptr() as *mut u64;
StructuredCloneData::read_clone(global, data, nbytes, rval);
}
StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval)
StructuredCloneData::Struct(data, nbytes) => StructuredCloneData::read_clone(global, data, nbytes, rval),
StructuredCloneData::_p(_) => return,
}
}
}

unsafe impl Send for StructuredCloneData {}
unsafe impl<TH: TypeHolderTrait> Send for StructuredCloneData<TH> {}
@@ -116,6 +116,8 @@ use time::Duration;
use uuid::Uuid;
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::WebVRGamepadHand;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;

/// A trait to allow tracing (only) DOM objects.
pub unsafe trait JSTraceable {
@@ -130,7 +132,7 @@ unsafe_no_jsmanaged_fields!(&'static Encoding);
unsafe_no_jsmanaged_fields!(RefCell<Decoder>);
unsafe_no_jsmanaged_fields!(RefCell<Vec<u8>>);

unsafe_no_jsmanaged_fields!(Reflector);
unsafe_no_jsmanaged_fields_generic!(Reflector<TH>);

unsafe_no_jsmanaged_fields!(Duration);

@@ -150,7 +152,7 @@ pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>)

/// Trace the `JSObject` held by `reflector`.
#[allow(unrooted_must_root)]
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
pub fn trace_reflector<TH: TypeHolderTrait>(tracer: *mut JSTracer, description: &str, reflector: &Reflector<TH>) {
trace!("tracing reflector {}", description);
trace_object(tracer, description, reflector.rootable())
}
@@ -189,6 +191,12 @@ unsafe impl<T: JSTraceable + ?Sized> JSTraceable for Box<T> {
}
}

unsafe impl<'a, T: JSTraceable + ?Sized> JSTraceable for &'a T {
unsafe fn trace(&self, trc: *mut JSTracer) {
(**self).trace(trc)
}
}

unsafe impl<T: JSTraceable> JSTraceable for [T] {
unsafe fn trace(&self, trc: *mut JSTracer) {
for e in self.iter() {
@@ -351,7 +359,7 @@ unsafe_no_jsmanaged_fields!(Image, ImageMetadata, ImageCache, PendingImageId);
unsafe_no_jsmanaged_fields!(Metadata);
unsafe_no_jsmanaged_fields!(NetworkError);
unsafe_no_jsmanaged_fields!(Atom, Prefix, LocalName, Namespace, QualName);
unsafe_no_jsmanaged_fields!(TrustedPromise);
unsafe_no_jsmanaged_fields_generic!(TrustedPromise<TH>);
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
@@ -664,6 +672,12 @@ unsafe impl JSTraceable for StyleLocked<MediaList> {
}
}

unsafe impl<TH> JSTraceable for PhantomData<TH> {
unsafe fn trace(&self, _trc: *mut JSTracer) {
// Do nothing.
}
}

unsafe impl<T> JSTraceable for TypedArray<T, Box<Heap<*mut JSObject>>> where T: TypedArrayElement {
unsafe fn trace(&self, trc: *mut JSTracer) {
self.underlying_object().trace(trc);
@@ -44,6 +44,8 @@ use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::ptr;
use std::slice;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;

/// Proxy handler for a WindowProxy.
pub struct WindowProxyHandler(pub *const libc::c_void);
@@ -64,9 +66,9 @@ pub struct GlobalStaticData {

impl GlobalStaticData {
/// Creates a new GlobalStaticData.
pub fn new() -> GlobalStaticData {
pub fn new<TH: TypeHolderTrait>() -> GlobalStaticData {
GlobalStaticData {
windowproxy_handler: windowproxy::new_window_proxy_handler(),
windowproxy_handler: windowproxy::new_window_proxy_handler::<TH>(),
}
}
}
@@ -328,7 +330,7 @@ pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
}

/// Enumerate lazy properties of a global object.
pub unsafe extern "C" fn enumerate_global(cx: *mut JSContext, obj: RawHandleObject) -> bool {
pub unsafe extern "C" fn enumerate_global<TH: TypeHolderTrait>(cx: *mut JSContext, obj: RawHandleObject) -> bool {
assert!(JS_IsGlobalObject(obj.get()));
if !JS_EnumerateStandardClasses(cx, obj) {
return false;
@@ -340,7 +342,7 @@ pub unsafe extern "C" fn enumerate_global(cx: *mut JSContext, obj: RawHandleObje
}

/// Resolve a lazy global property, for interface objects and named constructors.
pub unsafe extern "C" fn resolve_global(
pub unsafe extern "C" fn resolve_global<TH: TypeHolderTrait>(
cx: *mut JSContext,
obj: RawHandleObject,
id: RawHandleId,
@@ -22,6 +22,8 @@ use std::cell::{Cell, UnsafeCell};
use std::mem;
use std::ops::{Deref, DerefMut, Drop};
use std::ptr;
use typeholder::TypeHolderTrait;
use std::marker::PhantomData;

/// The index of the slot wherein a pointer to the weak holder cell is
/// stored for weak-referenceable bindings. We use slot 1 for holding it,
Oops, something went wrong.