diff options
Diffstat (limited to 'src/components/layout/wrapper.rs')
-rw-r--r-- | src/components/layout/wrapper.rs | 783 |
1 files changed, 0 insertions, 783 deletions
diff --git a/src/components/layout/wrapper.rs b/src/components/layout/wrapper.rs deleted file mode 100644 index d052c263655..00000000000 --- a/src/components/layout/wrapper.rs +++ /dev/null @@ -1,783 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! A safe wrapper for DOM nodes that prevents layout from mutating the DOM, from letting DOM nodes -//! escape, and from generally doing anything that it isn't supposed to. This is accomplished via -//! a simple whitelist of allowed operations, along with some lifetime magic to prevent nodes from -//! escaping. -//! -//! As a security wrapper is only as good as its whitelist, be careful when adding operations to -//! this list. The cardinal rules are: -//! -//! 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 -//! onto these objects and cause use-after-free. -//! -//! When implementing wrapper functions, be careful that you do not touch the borrow flags, or you -//! will race and cause spurious task failure. (Note that I do not believe these races are -//! exploitable, but they'll result in brokenness nonetheless.) -//! -//! Rules of the road for this file: -//! -//! * In general, you must not use the `Cast` functions; use explicit checks and `transmute_copy` -//! instead. -//! -//! * You must also not use `.get()`; instead, use `.unsafe_get()`. -//! -//! * Do not call any methods on DOM nodes without checking to see whether they use borrow flags. -//! -//! o Instead of `get_attr()`, use `.get_attr_val_for_layout()`. -//! -//! o Instead of `html_element_in_html_document()`, use -//! `html_element_in_html_document_for_layout()`. - -use css::node_style::StyledNode; -use util::LayoutDataWrapper; - -use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived}; -use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived}; -use script::dom::bindings::js::JS; -use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId}; -use script::dom::element::{HTMLLinkElementTypeId, LayoutElementHelpers, RawLayoutElementHelpers}; -use script::dom::htmliframeelement::HTMLIFrameElement; -use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; -use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId}; -use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, TextNodeTypeId}; -use script::dom::text::Text; -use servo_msg::constellation_msg::{PipelineId, SubpageId}; -use servo_util::atom::Atom; -use servo_util::namespace::Namespace; -use servo_util::namespace; -use servo_util::str::is_whitespace; -use std::cell::{RefCell, Ref, RefMut}; -use std::kinds::marker::ContravariantLifetime; -use std::mem; -use style::computed_values::{content, display, white_space}; -use style::{AnyNamespace, AttrSelector, PropertyDeclarationBlock, SpecificNamespace, TElement}; -use style::{TNode}; -use url::Url; - -/// Allows some convenience methods on generic layout nodes. -pub trait TLayoutNode { - /// Creates a new layout node with the same lifetime as this layout node. - unsafe fn new_with_this_lifetime(&self, node: &JS<Node>) -> Self; - - /// 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`. - fn type_id(&self) -> Option<NodeTypeId>; - - /// Returns the interior of this node as a `JS`. This is highly unsafe for layout to - /// call and as such is marked `unsafe`. - unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node>; - - /// Returns the interior of this node as a `Node`. This is highly unsafe for layout to call - /// and as such is marked `unsafe`. - unsafe fn get<'a>(&'a self) -> &'a Node { - &*self.get_jsmanaged().unsafe_get() - } - - fn node_is_element(&self) -> bool { - match self.type_id() { - Some(ElementNodeTypeId(..)) => true, - _ => false - } - } - - fn node_is_document(&self) -> bool { - match self.type_id() { - Some(DocumentNodeTypeId(..)) => true, - _ => false - } - } - - /// If this is an image element, returns its URL. If this is not an image element, fails. - /// - /// FIXME(pcwalton): Don't copy URLs. - fn image_url(&self) -> Option<Url> { - unsafe { - if !self.get().is_htmlimageelement() { - fail!("not an image!") - } - let image_element: JS<HTMLImageElement> = self.get_jsmanaged().transmute_copy(); - image_element.image().as_ref().map(|url| (*url).clone()) - } - } - - /// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is - /// not an iframe element, fails. - fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) { - unsafe { - if !self.get().is_htmliframeelement() { - fail!("not an iframe element!") - } - let iframe_element: JS<HTMLIFrameElement> = self.get_jsmanaged().transmute_copy(); - let size = (*iframe_element.unsafe_get()).size.deref().get().unwrap(); - (size.pipeline_id, size.subpage_id) - } - } - - /// If this is a text node, copies out the text. If this is not a text node, fails. - /// - /// FIXME(pcwalton): Don't copy text. Atomically reference count instead. - fn text(&self) -> String; - - /// Returns the first child of this node. - fn first_child(&self) -> Option<Self>; - - /// Dumps this node tree, for debugging. - fn dump(&self) { - // TODO(pcwalton): Reimplement this in a way that's safe for layout to call. - } -} - -/// 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`. -pub struct LayoutNode<'a> { - /// The wrapped node. - node: JS<Node>, - - /// Being chained to a ContravariantLifetime prevents `LayoutNode`s from escaping. - pub chain: ContravariantLifetime<'a>, -} - -impl<'ln> Clone for LayoutNode<'ln> { - fn clone(&self) -> LayoutNode<'ln> { - LayoutNode { - node: self.node.clone(), - chain: self.chain, - } - } -} - -impl<'a> PartialEq for LayoutNode<'a> { - #[inline] - fn eq(&self, other: &LayoutNode) -> bool { - self.node == other.node - } -} - - -impl<'ln> TLayoutNode for LayoutNode<'ln> { - unsafe fn new_with_this_lifetime(&self, node: &JS<Node>) -> LayoutNode<'ln> { - LayoutNode { - node: node.transmute_copy(), - chain: self.chain, - } - } - - fn type_id(&self) -> Option<NodeTypeId> { - unsafe { - Some(self.node.type_id_for_layout()) - } - } - - unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { - &self.node - } - - fn first_child(&self) -> Option<LayoutNode<'ln>> { - unsafe { - self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn text(&self) -> String { - unsafe { - if !self.get().is_text() { - fail!("not text!") - } - let text: JS<Text> = self.get_jsmanaged().transmute_copy(); - (*text.unsafe_get()).characterdata.data.deref().borrow().clone() - } - } -} - -impl<'ln> LayoutNode<'ln> { - /// Creates a new layout node, scoped to the given closure. - pub unsafe fn with_layout_node<R>(node: JS<Node>, f: <'a> |LayoutNode<'a>| -> R) -> R { - f(LayoutNode { - node: node, - chain: ContravariantLifetime, - }) - } - - /// Iterates over this node and all its descendants, in preorder. - /// - /// FIXME(pcwalton): Terribly inefficient. We should use parallelism. - pub fn traverse_preorder(&self) -> LayoutTreeIterator<'ln> { - let mut nodes = vec!(); - gather_layout_nodes(self, &mut nodes, false); - LayoutTreeIterator::new(nodes) - } - - /// Returns an iterator over this node's children. - pub fn children(&self) -> LayoutNodeChildrenIterator<'ln> { - LayoutNodeChildrenIterator { - current_node: self.first_child(), - } - } - - pub unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { - &self.node - } -} - -impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> { - fn parent_node(&self) -> Option<LayoutNode<'ln>> { - unsafe { - self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn prev_sibling(&self) -> Option<LayoutNode<'ln>> { - unsafe { - self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn next_sibling(&self) -> Option<LayoutNode<'ln>> { - unsafe { - self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - /// If this is an element, accesses the element data. Fails if this is not an element node. - #[inline] - fn as_element(&self) -> LayoutElement<'ln> { - unsafe { - assert!(self.node.is_element_for_layout()); - let elem: JS<Element> = self.node.transmute_copy(); - let element = &*elem.unsafe_get(); - LayoutElement { - element: mem::transmute(element), - } - } - } - - fn is_element(&self) -> bool { - self.node_is_element() - } - - fn is_document(&self) -> bool { - self.node_is_document() - } - - fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool { - assert!(self.is_element()) - let name = if self.is_html_element_in_html_document() { - attr.lower_name.as_slice() - } else { - attr.name.as_slice() - }; - match attr.namespace { - SpecificNamespace(ref ns) => { - let element = self.as_element(); - element.get_attr(ns, name) - .map_or(false, |attr| test(attr)) - }, - // FIXME: https://github.com/mozilla/servo/issues/1558 - AnyNamespace => false, - } - } - - fn is_html_element_in_html_document(&self) -> bool { - unsafe { - self.is_element() && { - let element: JS<Element> = self.node.transmute_copy(); - element.html_element_in_html_document_for_layout() - } - } - } -} - -pub struct LayoutNodeChildrenIterator<'a> { - current_node: Option<LayoutNode<'a>>, -} - -impl<'a> Iterator<LayoutNode<'a>> for LayoutNodeChildrenIterator<'a> { - fn next(&mut self) -> Option<LayoutNode<'a>> { - let node = self.current_node.clone(); - self.current_node = node.clone().and_then(|node| { - node.next_sibling() - }); - node - } -} - -// FIXME: Do this without precomputing a vector of refs. -// Easy for preorder; harder for postorder. -// -// FIXME(pcwalton): Parallelism! Eventually this should just be nuked. -pub struct LayoutTreeIterator<'a> { - nodes: Vec<LayoutNode<'a>>, - index: uint, -} - -impl<'a> LayoutTreeIterator<'a> { - fn new(nodes: Vec<LayoutNode<'a>>) -> LayoutTreeIterator<'a> { - LayoutTreeIterator { - nodes: nodes, - index: 0, - } - } -} - -impl<'a> Iterator<LayoutNode<'a>> for LayoutTreeIterator<'a> { - fn next(&mut self) -> Option<LayoutNode<'a>> { - if self.index >= self.nodes.len() { - None - } else { - let v = self.nodes[self.index].clone(); - self.index += 1; - Some(v) - } - } -} - -/// FIXME(pcwalton): This is super inefficient. -fn gather_layout_nodes<'a>(cur: &LayoutNode<'a>, refs: &mut Vec<LayoutNode<'a>>, postorder: bool) { - if !postorder { - refs.push(cur.clone()); - } - for kid in cur.children() { - gather_layout_nodes(&kid, refs, postorder) - } - if postorder { - refs.push(cur.clone()); - } -} - -/// A wrapper around elements that ensures layout can only ever access safe properties. -pub struct LayoutElement<'le> { - element: &'le Element, -} - -impl<'le> LayoutElement<'le> { - pub fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock> { - let style: &Option<PropertyDeclarationBlock> = unsafe { - let style: &RefCell<Option<PropertyDeclarationBlock>> = self.element.style_attribute.deref(); - // cast to the direct reference to T placed on the head of RefCell<T> - mem::transmute(style) - }; - style - } -} - -impl<'le> TElement for LayoutElement<'le> { - #[inline] - fn get_local_name<'a>(&'a self) -> &'a Atom { - &self.element.local_name - } - - #[inline] - fn get_namespace<'a>(&'a self) -> &'a Namespace { - &self.element.namespace - } - - #[inline] - fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'static str> { - unsafe { self.element.get_attr_val_for_layout(namespace, name) } - } - - fn get_link(&self) -> Option<&'static str> { - // FIXME: This is HTML only. - match self.element.node.type_id_for_layout() { - // http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html# - // selector-link - ElementNodeTypeId(HTMLAnchorElementTypeId) | - ElementNodeTypeId(HTMLAreaElementTypeId) | - ElementNodeTypeId(HTMLLinkElementTypeId) => { - unsafe { self.element.get_attr_val_for_layout(&namespace::Null, "href") } - } - _ => None, - } - } - - fn get_hover_state(&self) -> bool { - unsafe { - self.element.node.get_hover_state_for_layout() - } - } - - #[inline] - fn get_id(&self) -> Option<Atom> { - unsafe { self.element.get_attr_atom_for_layout(&namespace::Null, "id") } - } - - fn get_disabled_state(&self) -> bool { - unsafe { - self.element.node.get_disabled_state_for_layout() - } - } - - fn get_enabled_state(&self) -> bool { - unsafe { - self.element.node.get_enabled_state_for_layout() - } - } -} - -fn get_content(content_list: &content::T) -> String { - match *content_list { - content::Content(ref value) => { - let iter = &mut value.clone().move_iter().peekable(); - match iter.next() { - Some(content::StringContent(content)) => content, - _ => "".to_string(), - } - } - _ => "".to_string(), - } -} - -#[deriving(PartialEq, Clone)] -pub enum PseudoElementType { - Normal, - Before, - After, - BeforeBlock, - AfterBlock, -} - -/// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout -/// node does not allow any parents or siblings of nodes to be accessed, to avoid races. -#[deriving(Clone)] -pub struct ThreadSafeLayoutNode<'ln> { - /// The wrapped node. - node: LayoutNode<'ln>, - - pseudo: PseudoElementType, -} - -impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { - /// 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> { - ThreadSafeLayoutNode { - node: LayoutNode { - node: node.transmute_copy(), - chain: self.node.chain, - }, - pseudo: Normal, - } - } - - /// Returns `None` if this is a pseudo-element. - fn type_id(&self) -> Option<NodeTypeId> { - if self.pseudo == Before || self.pseudo == After { - return None - } - - self.node.type_id() - } - - unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { - self.node.get_jsmanaged() - } - - unsafe fn get<'a>(&'a self) -> &'a Node { // this change. - mem::transmute::<*mut Node,&'a Node>(self.get_jsmanaged().unsafe_get()) - } - - fn first_child(&self) -> Option<ThreadSafeLayoutNode<'ln>> { - if self.pseudo == Before || self.pseudo == After { - return None - } - - if self.has_before_pseudo() { - if self.is_block(Before) && self.pseudo == Normal { - let pseudo_before_node = self.with_pseudo(BeforeBlock); - return Some(pseudo_before_node) - } else if self.pseudo == Normal || self.pseudo == BeforeBlock { - let pseudo_before_node = self.with_pseudo(Before); - return Some(pseudo_before_node) - } - } - - unsafe { - self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node)) - } - } - - fn text(&self) -> String { - if self.pseudo == Before || self.pseudo == After { - let layout_data_ref = self.borrow_layout_data(); - let node_layout_data_wrapper = layout_data_ref.get_ref(); - - if self.pseudo == Before { - let before_style = node_layout_data_wrapper.data.before_style.get_ref(); - return get_content(&before_style.get_box().content) - } else { - let after_style = node_layout_data_wrapper.data.after_style.get_ref(); - return get_content(&after_style.get_box().content) - } - } - - unsafe { - if !self.get().is_text() { - fail!("not text!") - } - let text: JS<Text> = self.get_jsmanaged().transmute_copy(); - (*text.unsafe_get()).characterdata.data.deref().borrow().clone() - } - } -} - - -impl<'ln> ThreadSafeLayoutNode<'ln> { - /// Creates a new `ThreadSafeLayoutNode` from the given `LayoutNode`. - pub fn new<'a>(node: &LayoutNode<'a>) -> ThreadSafeLayoutNode<'a> { - ThreadSafeLayoutNode { - node: node.clone(), - pseudo: Normal, - } - } - - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType) -> ThreadSafeLayoutNode<'ln> { - ThreadSafeLayoutNode { - node: self.node.clone(), - pseudo: pseudo, - } - } - - /// Returns the next sibling of this node. Unsafe and private because this can lead to races. - unsafe fn next_sibling(&self) -> Option<ThreadSafeLayoutNode<'ln>> { - if self.pseudo == Before || self.pseudo == BeforeBlock { - return self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(&node)) - } - - self.get_jsmanaged().next_sibling_ref().map(|node| self.new_with_this_lifetime(&node)) - } - - /// Returns an iterator over this node's children. - pub fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln> { - ThreadSafeLayoutNodeChildrenIterator { - current_node: self.first_child(), - parent_node: Some(self.clone()), - } - } - - /// If this is an element, accesses the element data. Fails if this is not an element node. - #[inline] - pub fn as_element(&self) -> ThreadSafeLayoutElement { - unsafe { - assert!(self.get_jsmanaged().is_element_for_layout()); - let elem: JS<Element> = self.get_jsmanaged().transmute_copy(); - let element = elem.unsafe_get(); - // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on - // implementations. - ThreadSafeLayoutElement { - element: &mut *element, - } - } - } - - pub fn get_pseudo_element_type(&self) -> PseudoElementType { - self.pseudo - } - - pub fn is_block(&self, kind: PseudoElementType) -> bool { - let mut layout_data_ref = self.mutate_layout_data(); - let node_layout_data_wrapper = layout_data_ref.get_mut_ref(); - - let display = match kind { - Before | BeforeBlock => { - let before_style = node_layout_data_wrapper.data.before_style.get_ref(); - before_style.get_box().display - } - After | AfterBlock => { - let after_style = node_layout_data_wrapper.data.after_style.get_ref(); - after_style.get_box().display - } - Normal => { - let after_style = node_layout_data_wrapper.shared_data.style.get_ref(); - after_style.get_box().display - } - }; - - display == display::block - } - - pub fn has_before_pseudo(&self) -> bool { - let layout_data_wrapper = self.borrow_layout_data(); - let layout_data_wrapper_ref = layout_data_wrapper.get_ref(); - layout_data_wrapper_ref.data.before_style.is_some() - } - - pub fn has_after_pseudo(&self) -> bool { - let layout_data_wrapper = self.borrow_layout_data(); - let layout_data_wrapper_ref = layout_data_wrapper.get_ref(); - layout_data_wrapper_ref.data.after_style.is_some() - } - - /// Borrows the layout data immutably. Fails on a conflicting borrow. - #[inline(always)] - pub fn borrow_layout_data<'a>(&'a self) -> Ref<'a,Option<LayoutDataWrapper>> { - unsafe { - mem::transmute(self.get().layout_data.borrow()) - } - } - - /// Borrows the layout data mutably. Fails on a conflicting borrow. - #[inline(always)] - pub fn mutate_layout_data<'a>(&'a self) -> RefMut<'a,Option<LayoutDataWrapper>> { - unsafe { - mem::transmute(self.get().layout_data.borrow_mut()) - } - } - - /// Traverses the tree in postorder. - /// - /// TODO(pcwalton): Offer a parallel version with a compatible API. - pub fn traverse_postorder_mut<T:PostorderNodeMutTraversal>(&mut self, traversal: &mut T) - -> bool { - if traversal.should_prune(self) { - return true - } - - let mut opt_kid = self.first_child(); - loop { - match opt_kid { - None => break, - Some(mut kid) => { - if !kid.traverse_postorder_mut(traversal) { - return false - } - unsafe { - opt_kid = kid.next_sibling() - } - } - } - } - - traversal.process(self) - } - - pub fn is_ignorable_whitespace(&self) -> bool { - match self.type_id() { - Some(TextNodeTypeId) => { - unsafe { - let text: JS<Text> = self.get_jsmanaged().transmute_copy(); - if !is_whitespace((*text.unsafe_get()).characterdata.data.deref().borrow().as_slice()) { - return false - } - - // NB: See the rules for `white-space` here: - // - // http://www.w3.org/TR/CSS21/text.html#propdef-white-space - // - // If you implement other values for this property, you will almost certainly - // want to update this check. - match self.style().get_inheritedtext().white_space { - white_space::normal => true, - _ => false, - } - } - } - _ => false - } - } -} - -pub struct ThreadSafeLayoutNodeChildrenIterator<'a> { - current_node: Option<ThreadSafeLayoutNode<'a>>, - parent_node: Option<ThreadSafeLayoutNode<'a>>, -} - -impl<'a> Iterator<ThreadSafeLayoutNode<'a>> for ThreadSafeLayoutNodeChildrenIterator<'a> { - fn next(&mut self) -> Option<ThreadSafeLayoutNode<'a>> { - let node = self.current_node.clone(); - - match node { - Some(ref node) => { - if node.pseudo == After || node.pseudo == AfterBlock { - return None - } - - match self.parent_node { - Some(ref parent_node) => { - if parent_node.pseudo == Normal { - self.current_node = self.current_node.clone().and_then(|node| { - unsafe { - node.next_sibling() - } - }); - } else { - self.current_node = None; - } - } - None => {} - } - } - None => { - match self.parent_node { - Some(ref parent_node) => { - if parent_node.has_after_pseudo() { - let pseudo_after_node = if parent_node.is_block(After) && parent_node.pseudo == Normal { - let pseudo_after_node = parent_node.with_pseudo(AfterBlock); - Some(pseudo_after_node) - } else if parent_node.pseudo == Normal || parent_node.pseudo == AfterBlock { - let pseudo_after_node = parent_node.with_pseudo(After); - Some(pseudo_after_node) - } else { - None - }; - self.current_node = pseudo_after_node; - return self.current_node.clone() - } - } - None => {} - } - } - } - - node - } -} - -/// A wrapper around elements that ensures layout can only ever access safe properties and cannot -/// race on elements. -pub struct ThreadSafeLayoutElement<'le> { - element: &'le Element, -} - -impl<'le> ThreadSafeLayoutElement<'le> { - #[inline] - pub fn get_attr(&self, namespace: &Namespace, name: &str) -> Option<&'static str> { - unsafe { self.element.get_attr_val_for_layout(namespace, name) } - } -} - -/// A bottom-up, parallelizable traversal. -pub trait PostorderNodeMutTraversal { - /// The operation to perform. Return true to continue or false to stop. - fn process<'a>(&'a mut self, node: &ThreadSafeLayoutNode<'a>) -> bool; - - /// Returns true if this node should be pruned. If this returns true, we skip the operation - /// entirely and do not process any descendant nodes. This is called *before* child nodes are - /// visited. The default implementation never prunes any nodes. - fn should_prune<'a>(&'a self, _node: &ThreadSafeLayoutNode<'a>) -> bool { - false - } -} - -/// Opaque type stored in type-unsafe work queues for parallel layout. -/// Must be transmutable to and from LayoutNode/ThreadSafeLayoutNode. -pub type UnsafeLayoutNode = (uint, uint); - -pub fn layout_node_to_unsafe_layout_node(node: &LayoutNode) -> UnsafeLayoutNode { - unsafe { - let ptr: uint = mem::transmute_copy(node); - (ptr, 0) - } -} - -// FIXME(#3044): This should be updated to use a real lifetime instead of -// faking one. -pub unsafe fn layout_node_from_unsafe_layout_node(node: &UnsafeLayoutNode) -> LayoutNode<'static> { - let (node, _) = *node; - mem::transmute(node) -} |