auto merge of #4613 : saneyuki/servo/layoutjs, r=jdm

#4571
This commit is contained in:
bors-servo 2015-01-31 16:24:48 -07:00
commit 462940fc2a
14 changed files with 162 additions and 87 deletions

View file

@ -32,7 +32,7 @@ use gfx::paint_task::{PaintChan, PaintLayer};
use gfx::paint_task::Msg as PaintMsg; use gfx::paint_task::Msg as PaintMsg;
use layout_traits::{LayoutControlMsg, LayoutTaskFactory}; use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
use log; use log;
use script::dom::bindings::js::JS; use script::dom::bindings::js::LayoutJS;
use script::dom::node::{LayoutDataRef, Node, NodeTypeId}; use script::dom::node::{LayoutDataRef, Node, NodeTypeId};
use script::dom::element::ElementTypeId; use script::dom::element::ElementTypeId;
use script::dom::htmlelement::HTMLElementTypeId; use script::dom::htmlelement::HTMLElementTypeId;
@ -719,8 +719,8 @@ impl LayoutTask {
// FIXME: Isolate this transmutation into a "bridge" module. // FIXME: Isolate this transmutation into a "bridge" module.
// FIXME(rust#16366): The following line had to be moved because of a // FIXME(rust#16366): The following line had to be moved because of a
// rustc bug. It should be in the next unsafe block. // rustc bug. It should be in the next unsafe block.
let mut node: JS<Node> = unsafe { let mut node: LayoutJS<Node> = unsafe {
JS::from_trusted_node_address(data.document_root) LayoutJS::from_trusted_node_address(data.document_root)
}; };
let node: &mut LayoutNode = unsafe { let node: &mut LayoutNode = unsafe {
mem::transmute(&mut node) mem::transmute(&mut node)

View file

@ -10,8 +10,7 @@ use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
use gfx::display_list::OpaqueNode; use gfx::display_list::OpaqueNode;
use gfx; use gfx;
use libc::uintptr_t; use libc::uintptr_t;
use script::dom::bindings::js::JS; use script::dom::bindings::js::LayoutJS;
use script::dom::bindings::utils::Reflectable;
use script::dom::node::{Node, SharedLayoutData}; use script::dom::node::{Node, SharedLayoutData};
use script::layout_interface::{LayoutChan, TrustedNodeAddress}; use script::layout_interface::{LayoutChan, TrustedNodeAddress};
use script_traits::UntrustedNodeAddress; use script_traits::UntrustedNodeAddress;
@ -126,7 +125,7 @@ pub trait OpaqueNodeMethods {
fn from_script_node(node: TrustedNodeAddress) -> Self; fn from_script_node(node: TrustedNodeAddress) -> Self;
/// Converts a DOM node to an `OpaqueNode'. /// Converts a DOM node to an `OpaqueNode'.
fn from_jsmanaged(node: &JS<Node>) -> Self; fn from_jsmanaged(node: &LayoutJS<Node>) -> Self;
/// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type /// Converts this node to an `UntrustedNodeAddress`. An `UntrustedNodeAddress` is just the type
/// of node that script expects to receive in a hit test. /// of node that script expects to receive in a hit test.
@ -143,20 +142,20 @@ impl OpaqueNodeMethods for OpaqueNode {
fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> OpaqueNode { fn from_thread_safe_layout_node(node: &ThreadSafeLayoutNode) -> OpaqueNode {
unsafe { unsafe {
let abstract_node = node.get_jsmanaged(); let abstract_node = node.get_jsmanaged();
let ptr: uintptr_t = abstract_node.reflector().get_jsobject() as uintptr_t; let ptr: uintptr_t = abstract_node.get_jsobject() as uintptr_t;
OpaqueNode(ptr) OpaqueNode(ptr)
} }
} }
fn from_script_node(node: TrustedNodeAddress) -> OpaqueNode { fn from_script_node(node: TrustedNodeAddress) -> OpaqueNode {
unsafe { unsafe {
OpaqueNodeMethods::from_jsmanaged(&JS::from_trusted_node_address(node)) OpaqueNodeMethods::from_jsmanaged(&LayoutJS::from_trusted_node_address(node))
} }
} }
fn from_jsmanaged(node: &JS<Node>) -> OpaqueNode { fn from_jsmanaged(node: &LayoutJS<Node>) -> OpaqueNode {
unsafe { unsafe {
let ptr: uintptr_t = mem::transmute(node.reflector().get_jsobject()); let ptr: uintptr_t = node.get_jsobject() as uintptr_t;
OpaqueNode(ptr) OpaqueNode(ptr)
} }
} }

View file

@ -12,7 +12,7 @@
//! //!
//! 1. Layout is not allowed to mutate the DOM. //! 1. Layout is not allowed to mutate the DOM.
//! //!
//! 2. Layout is not allowed to see anything with `JS` in the name, because it could hang //! 2. Layout is not allowed to see anything with `LayoutJS` in the name, because it could hang
//! onto these objects and cause use-after-free. //! onto these objects and cause use-after-free.
//! //!
//! When implementing wrapper functions, be careful that you do not touch the borrow flags, or you //! When implementing wrapper functions, be careful that you do not touch the borrow flags, or you
@ -43,7 +43,7 @@ use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElemen
use script::dom::bindings::codegen::InheritTypes::{HTMLCanvasElementCast, HTMLImageElementCast}; use script::dom::bindings::codegen::InheritTypes::{HTMLCanvasElementCast, HTMLImageElementCast};
use script::dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, HTMLTextAreaElementCast}; use script::dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, HTMLTextAreaElementCast};
use script::dom::bindings::codegen::InheritTypes::{NodeCast, TextCast}; use script::dom::bindings::codegen::InheritTypes::{NodeCast, TextCast};
use script::dom::bindings::js::JS; use script::dom::bindings::js::LayoutJS;
use script::dom::element::{Element, ElementTypeId}; use script::dom::element::{Element, ElementTypeId};
use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers};
use script::dom::htmlelement::HTMLElementTypeId; use script::dom::htmlelement::HTMLElementTypeId;
@ -75,15 +75,15 @@ use url::Url;
/// Allows some convenience methods on generic layout nodes. /// Allows some convenience methods on generic layout nodes.
pub trait TLayoutNode { pub trait TLayoutNode {
/// Creates a new layout node with the same lifetime as this layout node. /// Creates a new layout node with the same lifetime as this layout node.
unsafe fn new_with_this_lifetime(&self, node: &JS<Node>) -> Self; unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> Self;
/// Returns the type ID of this node. Fails if this node is borrowed mutably. Returns `None` /// Returns the type ID of this node. Fails if this node is borrowed mutably. Returns `None`
/// if this is a pseudo-element; otherwise, returns `Some`. /// if this is a pseudo-element; otherwise, returns `Some`.
fn type_id(&self) -> Option<NodeTypeId>; fn type_id(&self) -> Option<NodeTypeId>;
/// Returns the interior of this node as a `JS`. This is highly unsafe for layout to /// Returns the interior of this node as a `LayoutJS`. This is highly unsafe for layout to
/// call and as such is marked `unsafe`. /// call and as such is marked `unsafe`.
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node>; unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node>;
/// Returns the interior of this node as a `Node`. This is highly unsafe for layout to call /// Returns the interior of this node as a `Node`. This is highly unsafe for layout to call
/// and as such is marked `unsafe`. /// and as such is marked `unsafe`.
@ -110,7 +110,7 @@ pub trait TLayoutNode {
/// FIXME(pcwalton): Don't copy URLs. /// FIXME(pcwalton): Don't copy URLs.
fn image_url(&self) -> Option<Url> { fn image_url(&self) -> Option<Url> {
unsafe { unsafe {
match HTMLImageElementCast::to_js(self.get_jsmanaged()) { match HTMLImageElementCast::to_layout_js(self.get_jsmanaged()) {
Some(elem) => elem.image().as_ref().map(|url| (*url).clone()), Some(elem) => elem.image().as_ref().map(|url| (*url).clone()),
None => panic!("not an image!") None => panic!("not an image!")
} }
@ -119,21 +119,21 @@ pub trait TLayoutNode {
fn get_renderer(&self) -> Option<Sender<CanvasMsg>> { fn get_renderer(&self) -> Option<Sender<CanvasMsg>> {
unsafe { unsafe {
let canvas_element: Option<JS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); let canvas_element: Option<LayoutJS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
canvas_element.and_then(|elem| elem.get_renderer()) canvas_element.and_then(|elem| elem.get_renderer())
} }
} }
fn get_canvas_width(&self) -> u32 { fn get_canvas_width(&self) -> u32 {
unsafe { unsafe {
let canvas_element: Option<JS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); let canvas_element: Option<LayoutJS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
canvas_element.unwrap().get_canvas_width() canvas_element.unwrap().get_canvas_width()
} }
} }
fn get_canvas_height(&self) -> u32 { fn get_canvas_height(&self) -> u32 {
unsafe { unsafe {
let canvas_element: Option<JS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); let canvas_element: Option<LayoutJS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_layout_js(self.get_jsmanaged());
canvas_element.unwrap().get_canvas_height() canvas_element.unwrap().get_canvas_height()
} }
} }
@ -142,8 +142,8 @@ pub trait TLayoutNode {
/// not an iframe element, fails. /// not an iframe element, fails.
fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) { fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) {
unsafe { unsafe {
let iframe_element: JS<HTMLIFrameElement> = let iframe_element: LayoutJS<HTMLIFrameElement> =
match HTMLIFrameElementCast::to_js(self.get_jsmanaged()) { match HTMLIFrameElementCast::to_layout_js(self.get_jsmanaged()) {
Some(elem) => elem, Some(elem) => elem,
None => panic!("not an iframe element!") None => panic!("not an iframe element!")
}; };
@ -162,11 +162,11 @@ pub trait TLayoutNode {
} }
/// A wrapper so that layout can access only the methods that it should have access to. Layout must /// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `JS`. /// only ever see these and must never see instances of `LayoutJS`.
#[derive(Copy)] #[derive(Copy)]
pub struct LayoutNode<'a> { pub struct LayoutNode<'a> {
/// The wrapped node. /// The wrapped node.
node: JS<Node>, node: LayoutJS<Node>,
/// Being chained to a ContravariantLifetime prevents `LayoutNode`s from escaping. /// Being chained to a ContravariantLifetime prevents `LayoutNode`s from escaping.
pub chain: ContravariantLifetime<'a>, pub chain: ContravariantLifetime<'a>,
@ -189,7 +189,7 @@ impl<'a> PartialEq for LayoutNode<'a> {
} }
impl<'ln> TLayoutNode for LayoutNode<'ln> { impl<'ln> TLayoutNode for LayoutNode<'ln> {
unsafe fn new_with_this_lifetime(&self, node: &JS<Node>) -> LayoutNode<'ln> { unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> LayoutNode<'ln> {
LayoutNode { LayoutNode {
node: node.transmute_copy(), node: node.transmute_copy(),
chain: self.chain, chain: self.chain,
@ -202,7 +202,7 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> {
} }
} }
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
&self.node &self.node
} }
@ -214,15 +214,15 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> {
fn text(&self) -> String { fn text(&self) -> String {
unsafe { unsafe {
let text: Option<JS<Text>> = TextCast::to_js(self.get_jsmanaged()); let text: Option<LayoutJS<Text>> = TextCast::to_layout_js(self.get_jsmanaged());
if let Some(text) = text { if let Some(text) = text {
return (*text.unsafe_get()).characterdata().data_for_layout().to_owned(); return (*text.unsafe_get()).characterdata().data_for_layout().to_owned();
} }
let input: Option<JS<HTMLInputElement>> = HTMLInputElementCast::to_js(self.get_jsmanaged()); let input: Option<LayoutJS<HTMLInputElement>> = HTMLInputElementCast::to_layout_js(self.get_jsmanaged());
if let Some(input) = input { if let Some(input) = input {
return input.get_value_for_layout(); return input.get_value_for_layout();
} }
let area: Option<JS<HTMLTextAreaElement>> = HTMLTextAreaElementCast::to_js(self.get_jsmanaged()); let area: Option<LayoutJS<HTMLTextAreaElement>> = HTMLTextAreaElementCast::to_layout_js(self.get_jsmanaged());
if let Some(area) = area { if let Some(area) = area {
return area.get_value_for_layout(); return area.get_value_for_layout();
} }
@ -294,7 +294,7 @@ impl<'ln> LayoutNode<'ln> {
} }
pub unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { pub unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
&self.node &self.node
} }
@ -371,7 +371,7 @@ impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
#[inline] #[inline]
fn as_element(self) -> LayoutElement<'ln> { fn as_element(self) -> LayoutElement<'ln> {
unsafe { unsafe {
let elem: JS<Element> = match ElementCast::to_js(&self.node) { let elem: LayoutJS<Element> = match ElementCast::to_layout_js(&self.node) {
Some(elem) => elem, Some(elem) => elem,
None => panic!("not an element") None => panic!("not an element")
}; };
@ -411,7 +411,7 @@ impl<'ln> TNode<'ln, LayoutElement<'ln>> for LayoutNode<'ln> {
fn is_html_element_in_html_document(self) -> bool { fn is_html_element_in_html_document(self) -> bool {
unsafe { unsafe {
match ElementCast::to_js(&self.node) { match ElementCast::to_layout_js(&self.node) {
Some(elem) => elem.html_element_in_html_document_for_layout(), Some(elem) => elem.html_element_in_html_document_for_layout(),
None => false None => false
} }
@ -707,7 +707,7 @@ pub struct ThreadSafeLayoutNode<'ln> {
impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
/// Creates a new layout node with the same lifetime as this layout node. /// Creates a new layout node with the same lifetime as this layout node.
unsafe fn new_with_this_lifetime(&self, node: &JS<Node>) -> ThreadSafeLayoutNode<'ln> { unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> {
ThreadSafeLayoutNode { ThreadSafeLayoutNode {
node: LayoutNode { node: LayoutNode {
node: node.transmute_copy(), node: node.transmute_copy(),
@ -726,7 +726,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> {
self.node.type_id() self.node.type_id()
} }
unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { unsafe fn get_jsmanaged<'a>(&'a self) -> &'a LayoutJS<Node> {
self.node.get_jsmanaged() self.node.get_jsmanaged()
} }
@ -824,7 +824,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
#[inline] #[inline]
pub fn as_element(&self) -> ThreadSafeLayoutElement<'ln> { pub fn as_element(&self) -> ThreadSafeLayoutElement<'ln> {
unsafe { unsafe {
let element = match ElementCast::to_js(self.get_jsmanaged()) { let element = match ElementCast::to_layout_js(self.get_jsmanaged()) {
Some(e) => e.unsafe_get(), Some(e) => e.unsafe_get(),
None => panic!("not an element") None => panic!("not an element")
}; };
@ -936,7 +936,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
pub fn is_ignorable_whitespace(&self) -> bool { pub fn is_ignorable_whitespace(&self) -> bool {
unsafe { unsafe {
let text: JS<Text> = match TextCast::to_js(self.get_jsmanaged()) { let text: LayoutJS<Text> = match TextCast::to_layout_js(self.get_jsmanaged()) {
Some(text) => text, Some(text) => text,
None => return false None => return false
}; };
@ -960,7 +960,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
pub fn get_input_value(&self) -> String { pub fn get_input_value(&self) -> String {
unsafe { unsafe {
let input: Option<JS<HTMLInputElement>> = HTMLInputElementCast::to_js(self.get_jsmanaged()); let input: Option<LayoutJS<HTMLInputElement>> = HTMLInputElementCast::to_layout_js(self.get_jsmanaged());
match input { match input {
Some(input) => input.get_value_for_layout(), Some(input) => input.get_value_for_layout(),
None => panic!("not an input element!") None => panic!("not an input element!")
@ -970,7 +970,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
pub fn get_input_size(&self) -> u32 { pub fn get_input_size(&self) -> u32 {
unsafe { unsafe {
match HTMLInputElementCast::to_js(self.get_jsmanaged()) { match HTMLInputElementCast::to_layout_js(self.get_jsmanaged()) {
Some(input) => input.get_size_for_layout(), Some(input) => input.get_size_for_layout(),
None => panic!("not an input element!") None => panic!("not an input element!")
} }
@ -980,7 +980,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
pub fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute) pub fn get_unsigned_integer_attribute(self, attribute: UnsignedIntegerAttribute)
-> Option<u32> { -> Option<u32> {
unsafe { unsafe {
let elem: Option<JS<Element>> = ElementCast::to_js(self.get_jsmanaged()); let elem: Option<LayoutJS<Element>> = ElementCast::to_layout_js(self.get_jsmanaged());
match elem { match elem {
Some(element) => { Some(element) => {
(*element.unsafe_get()).get_unsigned_integer_attribute_for_layout(attribute) (*element.unsafe_get()).get_unsigned_integer_attribute_for_layout(attribute)

View file

@ -33,8 +33,9 @@ In the `_finalize()` function the pointer of the Rusty DOM object that is contai
For supporting SpiderMonkeys exact GC rooting, we introduce [some types](https://github.com/mozilla/servo/wiki/Using-DOM-types): For supporting SpiderMonkeys exact GC rooting, we introduce [some types](https://github.com/mozilla/servo/wiki/Using-DOM-types):
- `JS<T>` is used for the DOM typed field in a DOM type structure. The GC can trace them recursively while the enclosing DOM object (maybe root) is alive. - `JS<T>` is used for the DOM typed field in a DOM type structure. The GC can trace them recursively while the enclosing DOM object (maybe root) is alive.
- `LayoutJS<T>` is specialized `JS<T>` to use in layout. `Layout*Helper` must be implemented on this type to prevent calling methods from non layout code.
- `Temporary<T>` is used as a return value for functions returning a DOM type. They are rooted for the duration of their lifetime. But a retun value gets moved around which can break the LIFO ordering constraint. Thus we need to introduce `Root<T>`. - `Temporary<T>` is used as a return value for functions returning a DOM type. They are rooted for the duration of their lifetime. But a retun value gets moved around which can break the LIFO ordering constraint. Thus we need to introduce `Root<T>`.
- `Root<T>` contains the pointer to `JSObject` which the represented DOM type has. SpiderMonkey's conservative stack scanner scans it's pointers and marks a pointed `JSObject` as GC root. - `Root<T>` contains the pointer to `JSObject` which the represented DOM type has. SpiderMonkey's conservative stack scanner scans it's pointers and marks a pointed `JSObject` as GC root.
- `JSRef` is just a reference to the value rooted by `Root<T>`. - `JSRef` is just a reference to the value rooted by `Root<T>`.
- `RootCollection` is used to dynamically check if rooting satisfies LIFO ordering, because SpiderMonkey's GC requires LIFO order (See also: [Exact Stack Rooting - Storing a GCPointer on the CStack](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting)). - `RootCollection` is used to dynamically check if rooting satisfies LIFO ordering, because SpiderMonkey's GC requires LIFO order (See also: [Exact Stack Rooting - Storing a GCPointer on the CStack](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting)).
- `MutHeap<T>` is a version of `Cell<T>` that is safe to use for internal mutability of Spidermonkey heap objects like `JSVal` and `JS<T>` - `MutHeap<T>` is a version of `Cell<T>` that is safe to use for internal mutability of Spidermonkey heap objects like `JSVal` and `JS<T>`

View file

@ -5220,7 +5220,7 @@ class GlobalGenRoots():
descriptors = config.getDescriptors(register=True, isCallback=False) descriptors = config.getDescriptors(register=True, isCallback=False)
allprotos = [CGGeneric("#![allow(unused_imports)]\n"), allprotos = [CGGeneric("#![allow(unused_imports)]\n"),
CGGeneric("use dom::types::*;\n"), CGGeneric("use dom::types::*;\n"),
CGGeneric("use dom::bindings::js::{JS, JSRef, Temporary};\n"), CGGeneric("use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary};\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::utils::Reflectable;\n"),
CGGeneric("use js::jsapi::JSTracer;\n\n"), CGGeneric("use js::jsapi::JSTracer;\n\n"),
@ -5279,6 +5279,17 @@ pub trait ${castTraitName} : Sized {
} }
} }
#[inline(always)]
#[allow(unrooted_must_root)]
fn to_layout_js<T: ${toBound}+Reflectable>(base: &LayoutJS<T>) -> Option<LayoutJS<Self>> {
unsafe {
match (*base.unsafe_get()).${checkFn}() {
true => Some(base.transmute_copy()),
false => None
}
}
}
#[inline(always)] #[inline(always)]
fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: JSRef<'a, T>) -> JSRef<'a, Self> { fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: JSRef<'a, T>) -> JSRef<'a, Self> {
unsafe { derived.transmute() } unsafe { derived.transmute() }

View file

@ -129,8 +129,32 @@ pub struct JS<T> {
ptr: NonZero<*const T> ptr: NonZero<*const T>
} }
impl<T> JS<T> {
/// Returns `LayoutJS<T>` containing the same pointer.
fn to_layout(self) -> LayoutJS<T> {
LayoutJS {
ptr: self.ptr.clone()
}
}
}
/// This is specialized `JS<T>` to use in under `layout` crate.
/// `Layout*Helpers` traits must be implemented on this.
pub struct LayoutJS<T> {
ptr: NonZero<*const T>
}
impl<T: Reflectable> LayoutJS<T> {
/// Get the reflector.
pub unsafe fn get_jsobject(&self) -> *mut JSObject {
(**self.ptr).reflector().get_jsobject()
}
}
impl<T> Copy for JS<T> {} impl<T> Copy for JS<T> {}
impl<T> Copy for LayoutJS<T> {}
impl<T> PartialEq for JS<T> { impl<T> PartialEq for JS<T> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
fn eq(&self, other: &JS<T>) -> bool { fn eq(&self, other: &JS<T>) -> bool {
@ -138,6 +162,13 @@ impl<T> PartialEq for JS<T> {
} }
} }
impl<T> PartialEq for LayoutJS<T> {
#[allow(unrooted_must_root)]
fn eq(&self, other: &LayoutJS<T>) -> bool {
self.ptr == other.ptr
}
}
impl <T> Clone for JS<T> { impl <T> Clone for JS<T> {
#[inline] #[inline]
fn clone(&self) -> JS<T> { fn clone(&self) -> JS<T> {
@ -147,6 +178,15 @@ impl <T> Clone for JS<T> {
} }
} }
impl <T> Clone for LayoutJS<T> {
#[inline]
fn clone(&self) -> LayoutJS<T> {
LayoutJS {
ptr: self.ptr.clone()
}
}
}
impl JS<Node> { impl JS<Node> {
/// Create a new JS-owned value wrapped from an address known to be a `Node` pointer. /// 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) -> JS<Node> { pub unsafe fn from_trusted_node_address(inner: TrustedNodeAddress) -> JS<Node> {
@ -158,6 +198,16 @@ impl JS<Node> {
} }
} }
impl LayoutJS<Node> {
/// 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) -> LayoutJS<Node> {
let TrustedNodeAddress(addr) = inner;
LayoutJS {
ptr: NonZero::new(addr as *const Node)
}
}
}
impl<T: Reflectable> JS<T> { impl<T: Reflectable> JS<T> {
/// Create a new JS-owned value wrapped from a raw Rust pointer. /// Create a new JS-owned value wrapped from a raw Rust pointer.
pub unsafe fn from_raw(raw: *const T) -> JS<T> { pub unsafe fn from_raw(raw: *const T) -> JS<T> {
@ -296,6 +346,12 @@ impl<T: Reflectable> MutNullableJS<T> {
self.ptr.get() self.ptr.get()
} }
/// Retrieve a copy of the inner optional `JS<T>` as `LayoutJS<T>`.
/// For use by layout, which can't use safe types like Temporary.
pub unsafe fn get_inner_as_layout(&self) -> Option<LayoutJS<T>> {
self.get_inner().map(|js| js.to_layout())
}
/// Retrieve a copy of the current inner value. If it is `None`, it is /// Retrieve a copy of the current inner value. If it is `None`, it is
/// initialized with the result of `cb` first. /// initialized with the result of `cb` first.
pub fn or_init<F>(&self, cb: F) -> Temporary<T> pub fn or_init<F>(&self, cb: F) -> Temporary<T>
@ -313,9 +369,8 @@ impl<T: Reflectable> MutNullableJS<T> {
} }
impl<T: Reflectable> JS<T> { impl<T: Reflectable> JS<T> {
/// Returns an unsafe pointer to the interior of this object. This is the /// Returns an unsafe pointer to the interior of this object.
/// only method that be safely accessed from layout. (The fact that this is /// This should only be used by the DOM bindings.
/// unsafe is what necessitates the layout wrappers.)
pub unsafe fn unsafe_get(&self) -> *const T { pub unsafe fn unsafe_get(&self) -> *const T {
*self.ptr *self.ptr
} }
@ -328,19 +383,28 @@ impl<T: Reflectable> JS<T> {
} }
} }
impl<From> JS<From> { impl<T: Reflectable> LayoutJS<T> {
/// Return `self` as a `JS` of another type. /// Returns an unsafe pointer to the interior of this JS object without touching the borrow
//XXXjdm It would be lovely if this could be private. /// flags. This is the only method that be safely accessed from layout. (The fact that this
pub unsafe fn transmute<To>(self) -> JS<To> { /// is unsafe is what necessitates the layout wrappers.)
mem::transmute(self) pub unsafe fn unsafe_get(&self) -> *const T {
*self.ptr
} }
}
impl<From> JS<From> {
/// Return `self` as a `JS` of another type. /// Return `self` as a `JS` of another type.
pub unsafe fn transmute_copy<To>(&self) -> JS<To> { pub unsafe fn transmute_copy<To>(&self) -> JS<To> {
mem::transmute_copy(self) mem::transmute_copy(self)
} }
} }
impl<From> LayoutJS<From> {
/// Return `self` as a `LayoutJS` of another type.
pub unsafe fn transmute_copy<To>(&self) -> LayoutJS<To> {
mem::transmute_copy(self)
}
}
/// Get an `Option<JSRef<T>>` out of an `Option<Root<T>>` /// Get an `Option<JSRef<T>>` out of an `Option<Root<T>>`
pub trait RootedReference<T> { pub trait RootedReference<T> {

View file

@ -5,7 +5,7 @@
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding;
use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods; use dom::bindings::codegen::Bindings::CanvasRenderingContext2DBinding::CanvasRenderingContext2DMethods;
use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::js::{JS, JSRef, LayoutJS, Temporary};
use dom::bindings::utils::{Reflector, reflect_dom_object}; use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlcanvaselement::HTMLCanvasElement;
@ -50,7 +50,7 @@ pub trait LayoutCanvasRenderingContext2DHelpers {
unsafe fn get_renderer(&self) -> Sender<CanvasMsg>; unsafe fn get_renderer(&self) -> Sender<CanvasMsg>;
} }
impl LayoutCanvasRenderingContext2DHelpers for JS<CanvasRenderingContext2D> { impl LayoutCanvasRenderingContext2DHelpers for LayoutJS<CanvasRenderingContext2D> {
unsafe fn get_renderer(&self) -> Sender<CanvasMsg> { unsafe fn get_renderer(&self) -> Sender<CanvasMsg> {
(*self.unsafe_get()).renderer.clone() (*self.unsafe_get()).renderer.clone()
} }

View file

@ -23,7 +23,7 @@ use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{NotSupported, InvalidCharacter}; use dom::bindings::error::Error::{NotSupported, InvalidCharacter};
use dom::bindings::error::Error::{HierarchyRequest, NamespaceError}; use dom::bindings::error::Error::{HierarchyRequest, NamespaceError};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalRootable, RootedReference}; use dom::bindings::js::{OptionalRootable, RootedReference};
use dom::bindings::utils::reflect_dom_object; use dom::bindings::utils::reflect_dom_object;
use dom::bindings::utils::xml_name_type; use dom::bindings::utils::xml_name_type;
@ -395,7 +395,7 @@ pub trait LayoutDocumentHelpers {
unsafe fn is_html_document_for_layout(&self) -> bool; unsafe fn is_html_document_for_layout(&self) -> bool;
} }
impl LayoutDocumentHelpers for JS<Document> { impl LayoutDocumentHelpers for LayoutJS<Document> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
#[inline] #[inline]
unsafe fn is_html_document_for_layout(&self) -> bool { unsafe fn is_html_document_for_layout(&self) -> bool {

View file

@ -23,7 +23,7 @@ use dom::bindings::codegen::InheritTypes::{HTMLTableRowElementDerived, HTMLTextA
use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast}; use dom::bindings::codegen::InheritTypes::{HTMLTableSectionElementDerived, NodeCast};
use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{NamespaceError, InvalidCharacter, Syntax}; use dom::bindings::error::Error::{NamespaceError, InvalidCharacter, Syntax};
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{MutNullableJS, JS, JSRef, LayoutJS, Temporary, TemporaryPushable};
use dom::bindings::js::{OptionalRootable, Root}; use dom::bindings::js::{OptionalRootable, Root};
use dom::bindings::utils::xml_name_type; use dom::bindings::utils::xml_name_type;
use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName}; use dom::bindings::utils::XMLName::{QName, Name, InvalidXMLName};
@ -376,13 +376,13 @@ pub trait LayoutElementHelpers {
unsafe fn has_attr_for_layout(&self, namespace: &Namespace, name: &Atom) -> bool; unsafe fn has_attr_for_layout(&self, namespace: &Namespace, name: &Atom) -> bool;
} }
impl LayoutElementHelpers for JS<Element> { impl LayoutElementHelpers for LayoutJS<Element> {
#[inline] #[inline]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool { unsafe fn html_element_in_html_document_for_layout(&self) -> bool {
if (*self.unsafe_get()).namespace != ns!(HTML) { if (*self.unsafe_get()).namespace != ns!(HTML) {
return false return false
} }
let node: JS<Node> = self.transmute_copy(); let node: LayoutJS<Node> = self.transmute_copy();
node.owner_doc_for_layout().is_html_document_for_layout() node.owner_doc_for_layout().is_html_document_for_layout()
} }

View file

@ -10,7 +10,7 @@ use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElemen
use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived; use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary}; use dom::bindings::js::{MutNullableJS, JSRef, LayoutJS, Temporary};
use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers}; use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document; use dom::document::Document;
use dom::element::{Element, AttributeHandlers}; use dom::element::{Element, AttributeHandlers};
@ -68,9 +68,9 @@ pub trait LayoutHTMLCanvasElementHelpers {
unsafe fn get_canvas_height(&self) -> u32; unsafe fn get_canvas_height(&self) -> u32;
} }
impl LayoutHTMLCanvasElementHelpers for JS<HTMLCanvasElement> { impl LayoutHTMLCanvasElementHelpers for LayoutJS<HTMLCanvasElement> {
unsafe fn get_renderer(&self) -> Option<Sender<CanvasMsg>> { unsafe fn get_renderer(&self) -> Option<Sender<CanvasMsg>> {
let context = (*self.unsafe_get()).context.get_inner(); let context = (*self.unsafe_get()).context.get_inner_as_layout();
context.map(|cx| cx.get_renderer()) context.map(|cx| cx.get_renderer())
} }

View file

@ -8,7 +8,7 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLImageElementBinding; use dom::bindings::codegen::Bindings::HTMLImageElementBinding;
use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods; use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLElementCast, HTMLImageElementDerived}; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLElementCast, HTMLImageElementDerived};
use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::js::{JSRef, LayoutJS, Temporary};
use dom::document::{Document, DocumentHelpers}; use dom::document::{Document, DocumentHelpers};
use dom::element::Element; use dom::element::Element;
use dom::element::AttributeHandlers; use dom::element::AttributeHandlers;
@ -88,7 +88,7 @@ pub trait LayoutHTMLImageElementHelpers {
unsafe fn image(&self) -> Option<Url>; unsafe fn image(&self) -> Option<Url>;
} }
impl LayoutHTMLImageElementHelpers for JS<HTMLImageElement> { impl LayoutHTMLImageElementHelpers for LayoutJS<HTMLImageElement> {
unsafe fn image(&self) -> Option<Url> { unsafe fn image(&self) -> Option<Url> {
(*self.unsafe_get()).image.borrow_for_layout().clone() (*self.unsafe_get()).image.borrow_for_layout().clone()
} }

View file

@ -15,7 +15,7 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLInp
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived, EventTargetCast}; use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived, EventTargetCast};
use dom::bindings::codegen::InheritTypes::KeyboardEventCast; use dom::bindings::codegen::InheritTypes::KeyboardEventCast;
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Comparable, JS, JSRef, Root, Temporary, OptionalRootable}; use dom::bindings::js::{Comparable, JSRef, LayoutJS, Root, Temporary, OptionalRootable};
use dom::bindings::js::{ResultRootable, RootedReference, MutNullableJS}; use dom::bindings::js::{ResultRootable, RootedReference, MutNullableJS};
use dom::document::{Document, DocumentHelpers}; use dom::document::{Document, DocumentHelpers};
use dom::element::{AttributeHandlers, Element}; use dom::element::{AttributeHandlers, Element};
@ -140,15 +140,15 @@ pub trait RawLayoutHTMLInputElementHelpers {
unsafe fn get_size_for_layout(&self) -> u32; unsafe fn get_size_for_layout(&self) -> u32;
} }
impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> { impl LayoutHTMLInputElementHelpers for LayoutJS<HTMLInputElement> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
unsafe fn get_value_for_layout(self) -> String { unsafe fn get_value_for_layout(self) -> String {
unsafe fn get_raw_textinput_value(input: JS<HTMLInputElement>) -> String { unsafe fn get_raw_textinput_value(input: LayoutJS<HTMLInputElement>) -> String {
(*input.unsafe_get()).textinput.borrow_for_layout().get_content() (*input.unsafe_get()).textinput.borrow_for_layout().get_content()
} }
unsafe fn get_raw_attr_value(input: JS<HTMLInputElement>) -> Option<String> { unsafe fn get_raw_attr_value(input: LayoutJS<HTMLInputElement>) -> Option<String> {
let elem: JS<Element> = input.transmute_copy(); let elem: LayoutJS<Element> = input.transmute_copy();
(*elem.unsafe_get()).get_attr_val_for_layout(&ns!(""), &atom!("value")) (*elem.unsafe_get()).get_attr_val_for_layout(&ns!(""), &atom!("value"))
.map(|s| s.to_owned()) .map(|s| s.to_owned())
} }

View file

@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived}; use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable}; use dom::bindings::js::{JSRef, LayoutJS, Temporary, OptionalRootable};
use dom::document::{Document, DocumentHelpers}; use dom::document::{Document, DocumentHelpers};
use dom::element::{Element, AttributeHandlers}; use dom::element::{Element, AttributeHandlers};
use dom::event::Event; use dom::event::Event;
@ -58,7 +58,7 @@ pub trait RawLayoutHTMLTextAreaElementHelpers {
unsafe fn get_rows_for_layout(&self) -> u32; unsafe fn get_rows_for_layout(&self) -> u32;
} }
impl LayoutHTMLTextAreaElementHelpers for JS<HTMLTextAreaElement> { impl LayoutHTMLTextAreaElementHelpers for LayoutJS<HTMLTextAreaElement> {
#[allow(unrooted_must_root)] #[allow(unrooted_must_root)]
unsafe fn get_value_for_layout(self) -> String { unsafe fn get_value_for_layout(self) -> String {
(*self.unsafe_get()).textinput.borrow_for_layout().get_content() (*self.unsafe_get()).textinput.borrow_for_layout().get_content()

View file

@ -23,7 +23,7 @@ use dom::bindings::conversions;
use dom::bindings::error::Fallible; use dom::bindings::error::Fallible;
use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax}; use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root}; use dom::bindings::js::{JS, JSRef, LayoutJS, RootedReference, Temporary, Root};
use dom::bindings::js::{TemporaryPushable, OptionalRootedRootable}; use dom::bindings::js::{TemporaryPushable, OptionalRootedRootable};
use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS}; use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS};
use dom::bindings::trace::JSTraceable; use dom::bindings::trace::JSTraceable;
@ -914,20 +914,20 @@ pub fn from_untrusted_node_address(runtime: *mut JSRuntime, candidate: Untrusted
pub trait LayoutNodeHelpers { pub trait LayoutNodeHelpers {
unsafe fn type_id_for_layout(&self) -> NodeTypeId; unsafe fn type_id_for_layout(&self) -> NodeTypeId;
unsafe fn parent_node_ref(&self) -> Option<JS<Node>>; unsafe fn parent_node_ref(&self) -> Option<LayoutJS<Node>>;
unsafe fn first_child_ref(&self) -> Option<JS<Node>>; unsafe fn first_child_ref(&self) -> Option<LayoutJS<Node>>;
unsafe fn last_child_ref(&self) -> Option<JS<Node>>; unsafe fn last_child_ref(&self) -> Option<LayoutJS<Node>>;
unsafe fn prev_sibling_ref(&self) -> Option<JS<Node>>; unsafe fn prev_sibling_ref(&self) -> Option<LayoutJS<Node>>;
unsafe fn next_sibling_ref(&self) -> Option<JS<Node>>; unsafe fn next_sibling_ref(&self) -> Option<LayoutJS<Node>>;
unsafe fn owner_doc_for_layout(&self) -> JS<Document>; unsafe fn owner_doc_for_layout(&self) -> LayoutJS<Document>;
unsafe fn is_element_for_layout(&self) -> bool; unsafe fn is_element_for_layout(&self) -> bool;
unsafe fn get_flag(self, flag: NodeFlags) -> bool; unsafe fn get_flag(self, flag: NodeFlags) -> bool;
unsafe fn set_flag(self, flag: NodeFlags, value: bool); unsafe fn set_flag(self, flag: NodeFlags, value: bool);
} }
impl LayoutNodeHelpers for JS<Node> { impl LayoutNodeHelpers for LayoutJS<Node> {
#[inline] #[inline]
unsafe fn type_id_for_layout(&self) -> NodeTypeId { unsafe fn type_id_for_layout(&self) -> NodeTypeId {
(*self.unsafe_get()).type_id (*self.unsafe_get()).type_id
@ -939,33 +939,33 @@ impl LayoutNodeHelpers for JS<Node> {
} }
#[inline] #[inline]
unsafe fn parent_node_ref(&self) -> Option<JS<Node>> { unsafe fn parent_node_ref(&self) -> Option<LayoutJS<Node>> {
(*self.unsafe_get()).parent_node.get_inner() (*self.unsafe_get()).parent_node.get_inner_as_layout()
} }
#[inline] #[inline]
unsafe fn first_child_ref(&self) -> Option<JS<Node>> { unsafe fn first_child_ref(&self) -> Option<LayoutJS<Node>> {
(*self.unsafe_get()).first_child.get_inner() (*self.unsafe_get()).first_child.get_inner_as_layout()
} }
#[inline] #[inline]
unsafe fn last_child_ref(&self) -> Option<JS<Node>> { unsafe fn last_child_ref(&self) -> Option<LayoutJS<Node>> {
(*self.unsafe_get()).last_child.get_inner() (*self.unsafe_get()).last_child.get_inner_as_layout()
} }
#[inline] #[inline]
unsafe fn prev_sibling_ref(&self) -> Option<JS<Node>> { unsafe fn prev_sibling_ref(&self) -> Option<LayoutJS<Node>> {
(*self.unsafe_get()).prev_sibling.get_inner() (*self.unsafe_get()).prev_sibling.get_inner_as_layout()
} }
#[inline] #[inline]
unsafe fn next_sibling_ref(&self) -> Option<JS<Node>> { unsafe fn next_sibling_ref(&self) -> Option<LayoutJS<Node>> {
(*self.unsafe_get()).next_sibling.get_inner() (*self.unsafe_get()).next_sibling.get_inner_as_layout()
} }
#[inline] #[inline]
unsafe fn owner_doc_for_layout(&self) -> JS<Document> { unsafe fn owner_doc_for_layout(&self) -> LayoutJS<Document> {
(*self.unsafe_get()).owner_doc.get_inner().unwrap() (*self.unsafe_get()).owner_doc.get_inner_as_layout().unwrap()
} }
#[inline] #[inline]