aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/node.rs
diff options
context:
space:
mode:
authorJack Moffitt <jack@metajack.im>2014-08-28 09:34:23 -0600
committerJack Moffitt <jack@metajack.im>2014-09-08 20:21:42 -0600
commitc6ab60dbfc6da7b4f800c9e40893c8b58413960c (patch)
treed1d74076cf7fa20e4f77ec7cb82cae98b67362cb /src/components/script/dom/node.rs
parentdb2f642c32fc5bed445bb6f2e45b0f6f0b4342cf (diff)
downloadservo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.tar.gz
servo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.zip
Cargoify servo
Diffstat (limited to 'src/components/script/dom/node.rs')
-rw-r--r--src/components/script/dom/node.rs2085
1 files changed, 0 insertions, 2085 deletions
diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs
deleted file mode 100644
index 96ee5f62ba2..00000000000
--- a/src/components/script/dom/node.rs
+++ /dev/null
@@ -1,2085 +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/. */
-
-//! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements.
-
-use dom::attr::Attr;
-use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
-use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
-use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
-use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
-use dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods};
-use dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
-use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast};
-use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast, ElementDerived};
-use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDerived};
-use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast};
-use dom::bindings::codegen::InheritTypes::{HTMLLegendElementDerived, HTMLFieldSetElementDerived};
-use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementDerived;
-use dom::bindings::error::{Fallible, NotFound, HierarchyRequest, Syntax};
-use dom::bindings::global::{GlobalRef, Window};
-use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnrootable};
-use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable};
-use dom::bindings::js::{ResultRootable, OptionalRootable};
-use dom::bindings::trace::Traceable;
-use dom::bindings::utils;
-use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
-use dom::characterdata::CharacterData;
-use dom::comment::Comment;
-use dom::document::{Document, DocumentHelpers, HTMLDocument, NonHTMLDocument};
-use dom::documentfragment::DocumentFragment;
-use dom::documenttype::DocumentType;
-use dom::element::{AttributeHandlers, Element, ElementTypeId};
-use dom::element::{HTMLAnchorElementTypeId, HTMLButtonElementTypeId, ElementHelpers};
-use dom::element::{HTMLInputElementTypeId, HTMLSelectElementTypeId};
-use dom::element::{HTMLTextAreaElementTypeId, HTMLOptGroupElementTypeId};
-use dom::element::{HTMLOptionElementTypeId, HTMLFieldSetElementTypeId};
-use dom::eventtarget::{EventTarget, NodeTargetTypeId};
-use dom::nodelist::{NodeList};
-use dom::processinginstruction::ProcessingInstruction;
-use dom::text::Text;
-use dom::virtualmethods::{VirtualMethods, vtable_for};
-use dom::window::Window;
-use geom::rect::Rect;
-use html::hubbub_html_parser::build_element_from_tag;
-use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC,
- LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress, UntrustedNodeAddress};
-use servo_util::geometry::Au;
-use servo_util::str::{DOMString, null_str_as_empty};
-use style::{parse_selector_list_from_str, matches};
-
-use js::jsapi::{JSContext, JSObject, JSRuntime};
-use js::jsfriendapi;
-use libc;
-use libc::uintptr_t;
-use std::cell::{Cell, RefCell, Ref, RefMut};
-use std::iter::{Map, Filter};
-use std::mem;
-use style;
-use style::ComputedValues;
-use sync::Arc;
-
-use serialize::{Encoder, Encodable};
-
-//
-// The basic Node structure
-//
-
-/// An HTML node.
-#[deriving(Encodable)]
-pub struct Node {
- /// The JavaScript reflector for this node.
- pub eventtarget: EventTarget,
-
- /// The type of node that this is.
- type_id: NodeTypeId,
-
- /// The parent of this node.
- parent_node: Cell<Option<JS<Node>>>,
-
- /// The first child of this node.
- first_child: Cell<Option<JS<Node>>>,
-
- /// The last child of this node.
- last_child: Cell<Option<JS<Node>>>,
-
- /// The next sibling of this node.
- next_sibling: Cell<Option<JS<Node>>>,
-
- /// The previous sibling of this node.
- prev_sibling: Cell<Option<JS<Node>>>,
-
- /// The document that this node belongs to.
- owner_doc: Cell<Option<JS<Document>>>,
-
- /// The live list of children return by .childNodes.
- child_list: Cell<Option<JS<NodeList>>>,
-
- /// A bitfield of flags for node items.
- flags: Traceable<RefCell<NodeFlags>>,
-
- /// Layout information. Only the layout task may touch this data.
- ///
- /// Must be sent back to the layout task to be destroyed when this
- /// node is finalized.
- pub layout_data: LayoutDataRef,
-}
-
-impl<S: Encoder<E>, E> Encodable<S, E> for LayoutDataRef {
- fn encode(&self, _s: &mut S) -> Result<(), E> {
- Ok(())
- }
-}
-
-impl NodeDerived for EventTarget {
- fn is_node(&self) -> bool {
- match self.type_id {
- NodeTargetTypeId(_) => true,
- _ => false
- }
- }
-}
-
-bitflags! {
- #[doc = "Flags for node items."]
- #[deriving(Encodable)]
- flags NodeFlags: u8 {
- #[doc = "Specifies whether this node is in a document."]
- static IsInDoc = 0x01,
- #[doc = "Specifies whether this node is in hover state."]
- static InHoverState = 0x02,
- #[doc = "Specifies whether this node is in disabled state."]
- static InDisabledState = 0x04,
- #[doc = "Specifies whether this node is in enabled state."]
- static InEnabledState = 0x08
- }
-}
-
-impl NodeFlags {
- pub fn new(type_id: NodeTypeId) -> NodeFlags {
- match type_id {
- DocumentNodeTypeId => IsInDoc,
- // The following elements are enabled by default.
- ElementNodeTypeId(HTMLButtonElementTypeId) |
- ElementNodeTypeId(HTMLInputElementTypeId) |
- ElementNodeTypeId(HTMLSelectElementTypeId) |
- ElementNodeTypeId(HTMLTextAreaElementTypeId) |
- ElementNodeTypeId(HTMLOptGroupElementTypeId) |
- ElementNodeTypeId(HTMLOptionElementTypeId) |
- //ElementNodeTypeId(HTMLMenuItemElementTypeId) |
- ElementNodeTypeId(HTMLFieldSetElementTypeId) => InEnabledState,
- _ => NodeFlags::empty(),
- }
- }
-}
-
-#[unsafe_destructor]
-impl Drop for Node {
- fn drop(&mut self) {
- unsafe {
- self.reap_layout_data();
- }
- }
-}
-
-/// suppress observers flag
-/// http://dom.spec.whatwg.org/#concept-node-insert
-/// http://dom.spec.whatwg.org/#concept-node-remove
-enum SuppressObserver {
- Suppressed,
- Unsuppressed
-}
-
-/// Layout data that is shared between the script and layout tasks.
-pub struct SharedLayoutData {
- /// The results of CSS styling for this node.
- pub style: Option<Arc<ComputedValues>>,
-}
-
-/// Encapsulates the abstract layout data.
-pub struct LayoutData {
- chan: Option<LayoutChan>,
- _shared_data: SharedLayoutData,
- _data: *const (),
-}
-
-pub struct LayoutDataRef {
- pub data_cell: RefCell<Option<LayoutData>>,
-}
-
-impl LayoutDataRef {
- pub fn new() -> LayoutDataRef {
- LayoutDataRef {
- data_cell: RefCell::new(None),
- }
- }
-
- /// Returns true if there is layout data present.
- #[inline]
- pub fn is_present(&self) -> bool {
- self.data_cell.borrow().is_some()
- }
-
- /// Take the chan out of the layout data if it is present.
- pub fn take_chan(&self) -> Option<LayoutChan> {
- let mut layout_data = self.data_cell.borrow_mut();
- match *layout_data {
- None => None,
- Some(..) => Some(layout_data.get_mut_ref().chan.take_unwrap()),
- }
- }
-
- /// Borrows the layout data immutably, *asserting that there are no mutators*. Bad things will
- /// happen if you try to mutate the layout data while this is held. This is the only thread-
- /// safe layout data accessor.
- #[inline]
- pub unsafe fn borrow_unchecked(&self) -> *const Option<LayoutData> {
- mem::transmute(&self.data_cell)
- }
-
- /// Borrows the layout data immutably. This function is *not* thread-safe.
- #[inline]
- pub fn borrow<'a>(&'a self) -> Ref<'a,Option<LayoutData>> {
- self.data_cell.borrow()
- }
-
- /// Borrows the layout data mutably. This function is *not* thread-safe.
- ///
- /// FIXME(pcwalton): We should really put this behind a `MutLayoutView` phantom type, to
- /// prevent CSS selector matching from mutably accessing nodes it's not supposed to and racing
- /// on it. This has already resulted in one bug!
- #[inline]
- pub fn borrow_mut<'a>(&'a self) -> RefMut<'a,Option<LayoutData>> {
- self.data_cell.borrow_mut()
- }
-}
-
-/// The different types of nodes.
-#[deriving(PartialEq,Encodable)]
-pub enum NodeTypeId {
- DoctypeNodeTypeId,
- DocumentFragmentNodeTypeId,
- CommentNodeTypeId,
- DocumentNodeTypeId,
- ElementNodeTypeId(ElementTypeId),
- TextNodeTypeId,
- ProcessingInstructionNodeTypeId,
-}
-
-trait PrivateNodeHelpers {
- fn node_inserted(&self);
- fn node_removed(&self, parent_in_doc: bool);
- fn add_child(&self, new_child: &JSRef<Node>, before: Option<JSRef<Node>>);
- fn remove_child(&self, child: &JSRef<Node>);
-}
-
-impl<'a> PrivateNodeHelpers for JSRef<'a, Node> {
- // http://dom.spec.whatwg.org/#node-is-inserted
- fn node_inserted(&self) {
- assert!(self.parent_node().is_some());
- let document = document_from_node(self).root();
- let is_in_doc = self.is_in_doc();
-
- for node in self.traverse_preorder() {
- vtable_for(&node).bind_to_tree(is_in_doc);
- }
-
- let parent = self.parent_node().root();
- parent.map(|parent| vtable_for(&*parent).child_inserted(self));
-
- document.deref().content_changed();
- }
-
- // http://dom.spec.whatwg.org/#node-is-removed
- fn node_removed(&self, parent_in_doc: bool) {
- assert!(self.parent_node().is_none());
- let document = document_from_node(self).root();
-
- for node in self.traverse_preorder() {
- vtable_for(&node).unbind_from_tree(parent_in_doc);
- }
-
- document.deref().content_changed();
- }
-
- //
- // Pointer stitching
- //
-
- /// Adds a new child to the end of this node's list of children.
- ///
- /// Fails unless `new_child` is disconnected from the tree.
- fn add_child(&self, new_child: &JSRef<Node>, before: Option<JSRef<Node>>) {
- let doc = self.owner_doc().root();
- doc.deref().wait_until_safe_to_modify_dom();
-
- assert!(new_child.parent_node().is_none());
- assert!(new_child.prev_sibling().is_none());
- assert!(new_child.next_sibling().is_none());
- match before {
- Some(ref before) => {
- assert!(before.parent_node().root().root_ref() == Some(*self));
- match before.prev_sibling().root() {
- None => {
- assert!(Some(*before) == self.first_child().root().root_ref());
- self.first_child.assign(Some(*new_child));
- },
- Some(ref prev_sibling) => {
- prev_sibling.next_sibling.assign(Some(*new_child));
- new_child.prev_sibling.assign(Some(**prev_sibling));
- },
- }
- before.prev_sibling.assign(Some(*new_child));
- new_child.next_sibling.assign(Some(*before));
- },
- None => {
- match self.last_child().root() {
- None => self.first_child.assign(Some(*new_child)),
- Some(ref last_child) => {
- assert!(last_child.next_sibling().is_none());
- last_child.next_sibling.assign(Some(*new_child));
- new_child.prev_sibling.assign(Some(**last_child));
- }
- }
-
- self.last_child.assign(Some(*new_child));
- },
- }
-
- new_child.parent_node.assign(Some(*self));
- }
-
- /// Removes the given child from this node's list of children.
- ///
- /// Fails unless `child` is a child of this node.
- fn remove_child(&self, child: &JSRef<Node>) {
- let doc = self.owner_doc().root();
- doc.deref().wait_until_safe_to_modify_dom();
-
- assert!(child.parent_node().root().root_ref() == Some(*self));
-
- match child.prev_sibling.get().root() {
- None => {
- self.first_child.assign(child.next_sibling.get());
- }
- Some(ref prev_sibling) => {
- prev_sibling.next_sibling.assign(child.next_sibling.get());
- }
- }
-
- match child.next_sibling.get().root() {
- None => {
- self.last_child.assign(child.prev_sibling.get());
- }
- Some(ref next_sibling) => {
- next_sibling.prev_sibling.assign(child.prev_sibling.get());
- }
- }
-
- child.prev_sibling.set(None);
- child.next_sibling.set(None);
- child.parent_node.set(None);
- }
-}
-
-pub trait NodeHelpers<'m, 'n> {
- fn ancestors(&self) -> AncestorIterator<'n>;
- fn children(&self) -> AbstractNodeChildrenIterator<'n>;
- fn child_elements(&self) -> ChildElementIterator<'m, 'n>;
- fn following_siblings(&self) -> AbstractNodeChildrenIterator<'n>;
- fn is_in_doc(&self) -> bool;
- fn is_inclusive_ancestor_of(&self, parent: &JSRef<Node>) -> bool;
- fn is_parent_of(&self, child: &JSRef<Node>) -> bool;
-
- fn type_id(&self) -> NodeTypeId;
-
- fn parent_node(&self) -> Option<Temporary<Node>>;
- fn first_child(&self) -> Option<Temporary<Node>>;
- fn last_child(&self) -> Option<Temporary<Node>>;
- fn prev_sibling(&self) -> Option<Temporary<Node>>;
- fn next_sibling(&self) -> Option<Temporary<Node>>;
-
- fn owner_doc(&self) -> Temporary<Document>;
- fn set_owner_doc(&self, document: &JSRef<Document>);
- fn is_in_html_doc(&self) -> bool;
-
- fn wait_until_safe_to_modify_dom(&self);
-
- fn is_element(&self) -> bool;
- fn is_document(&self) -> bool;
- fn is_doctype(&self) -> bool;
- fn is_text(&self) -> bool;
- fn is_anchor_element(&self) -> bool;
-
- fn get_hover_state(&self) -> bool;
- fn set_hover_state(&self, state: bool);
-
- fn get_disabled_state(&self) -> bool;
- fn set_disabled_state(&self, state: bool);
-
- fn get_enabled_state(&self) -> bool;
- fn set_enabled_state(&self, state: bool);
-
- fn dump(&self);
- fn dump_indent(&self, indent: uint);
- fn debug_str(&self) -> String;
-
- fn traverse_preorder(&self) -> TreeIterator<'n>;
- fn sequential_traverse_postorder(&self) -> TreeIterator<'n>;
- fn inclusively_following_siblings(&self) -> AbstractNodeChildrenIterator<'n>;
-
- fn to_trusted_node_address(&self) -> TrustedNodeAddress;
-
- fn get_bounding_content_box(&self) -> Rect<Au>;
- fn get_content_boxes(&self) -> Vec<Rect<Au>>;
-
- fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>>;
- fn query_selector_all(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>>;
-
- fn remove_self(&self);
-}
-
-impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> {
- /// Dumps the subtree rooted at this node, for debugging.
- fn dump(&self) {
- self.dump_indent(0);
- }
-
- /// Dumps the node tree, for debugging, with indentation.
- fn dump_indent(&self, indent: uint) {
- let mut s = String::new();
- for _ in range(0, indent) {
- s.push_str(" ");
- }
-
- s.push_str(self.debug_str().as_slice());
- debug!("{:s}", s);
-
- // FIXME: this should have a pure version?
- for kid in self.children() {
- kid.dump_indent(indent + 1u)
- }
- }
-
- /// Returns a string that describes this node.
- fn debug_str(&self) -> String {
- format!("{:?}", self.type_id)
- }
-
- fn is_in_doc(&self) -> bool {
- self.deref().flags.deref().borrow().contains(IsInDoc)
- }
-
- /// Returns the type ID of this node. Fails if this node is borrowed mutably.
- fn type_id(&self) -> NodeTypeId {
- self.deref().type_id
- }
-
- fn parent_node(&self) -> Option<Temporary<Node>> {
- self.deref().parent_node.get().map(|node| Temporary::new(node))
- }
-
- fn first_child(&self) -> Option<Temporary<Node>> {
- self.deref().first_child.get().map(|node| Temporary::new(node))
- }
-
- fn last_child(&self) -> Option<Temporary<Node>> {
- self.deref().last_child.get().map(|node| Temporary::new(node))
- }
-
- /// Returns the previous sibling of this node. Fails if this node is borrowed mutably.
- fn prev_sibling(&self) -> Option<Temporary<Node>> {
- self.deref().prev_sibling.get().map(|node| Temporary::new(node))
- }
-
- /// Returns the next sibling of this node. Fails if this node is borrowed mutably.
- fn next_sibling(&self) -> Option<Temporary<Node>> {
- self.deref().next_sibling.get().map(|node| Temporary::new(node))
- }
-
- #[inline]
- fn is_element(&self) -> bool {
- match self.type_id {
- ElementNodeTypeId(..) => true,
- _ => false
- }
- }
-
- #[inline]
- fn is_document(&self) -> bool {
- self.type_id == DocumentNodeTypeId
- }
-
- #[inline]
- fn is_anchor_element(&self) -> bool {
- self.type_id == ElementNodeTypeId(HTMLAnchorElementTypeId)
- }
-
- #[inline]
- fn is_doctype(&self) -> bool {
- self.type_id == DoctypeNodeTypeId
- }
-
- #[inline]
- fn is_text(&self) -> bool {
- self.type_id == TextNodeTypeId
- }
-
- fn get_hover_state(&self) -> bool {
- self.flags.deref().borrow().contains(InHoverState)
- }
-
- fn set_hover_state(&self, state: bool) {
- if state {
- self.flags.deref().borrow_mut().insert(InHoverState);
- } else {
- self.flags.deref().borrow_mut().remove(InHoverState);
- }
- }
-
- fn get_disabled_state(&self) -> bool {
- self.flags.deref().borrow().contains(InDisabledState)
- }
-
- fn set_disabled_state(&self, state: bool) {
- if state {
- self.flags.deref().borrow_mut().insert(InDisabledState);
- } else {
- self.flags.deref().borrow_mut().remove(InDisabledState);
- }
- }
-
- fn get_enabled_state(&self) -> bool {
- self.flags.deref().borrow().contains(InEnabledState)
- }
-
- fn set_enabled_state(&self, state: bool) {
- if state {
- self.flags.deref().borrow_mut().insert(InEnabledState);
- } else {
- self.flags.deref().borrow_mut().remove(InEnabledState);
- }
- }
-
- /// Iterates over this node and all its descendants, in preorder.
- fn traverse_preorder(&self) -> TreeIterator<'n> {
- let mut nodes = vec!();
- gather_abstract_nodes(self, &mut nodes, false);
- TreeIterator::new(nodes)
- }
-
- /// Iterates over this node and all its descendants, in postorder.
- fn sequential_traverse_postorder(&self) -> TreeIterator<'n> {
- let mut nodes = vec!();
- gather_abstract_nodes(self, &mut nodes, true);
- TreeIterator::new(nodes)
- }
-
- fn inclusively_following_siblings(&self) -> AbstractNodeChildrenIterator<'n> {
- AbstractNodeChildrenIterator {
- current_node: Some(self.clone()),
- }
- }
-
- fn is_inclusive_ancestor_of(&self, parent: &JSRef<Node>) -> bool {
- self == parent || parent.ancestors().any(|ancestor| &ancestor == self)
- }
-
- fn following_siblings(&self) -> AbstractNodeChildrenIterator<'n> {
- AbstractNodeChildrenIterator {
- current_node: self.next_sibling().root().map(|next| next.deref().clone()),
- }
- }
-
- fn is_parent_of(&self, child: &JSRef<Node>) -> bool {
- match child.parent_node() {
- Some(ref parent) if *parent == Temporary::from_rooted(self) => true,
- _ => false
- }
- }
-
- fn to_trusted_node_address(&self) -> TrustedNodeAddress {
- TrustedNodeAddress(self.deref() as *const Node as *const libc::c_void)
- }
-
- fn get_bounding_content_box(&self) -> Rect<Au> {
- let window = window_from_node(self).root();
- let page = window.deref().page();
- let addr = self.to_trusted_node_address();
-
- let ContentBoxResponse(rect) = page.layout_rpc.content_box(addr);
- rect
- }
-
- fn get_content_boxes(&self) -> Vec<Rect<Au>> {
- let window = window_from_node(self).root();
- let page = window.deref().page();
- let addr = self.to_trusted_node_address();
- let ContentBoxesResponse(rects) = page.layout_rpc.content_boxes(addr);
- rects
- }
-
- // http://dom.spec.whatwg.org/#dom-parentnode-queryselector
- fn query_selector(&self, selectors: DOMString) -> Fallible<Option<Temporary<Element>>> {
- // Step 1.
- match parse_selector_list_from_str(selectors.as_slice()) {
- // Step 2.
- Err(()) => return Err(Syntax),
- // Step 3.
- Ok(ref selectors) => {
- let root = self.ancestors().last().unwrap_or(self.clone());
- for node in root.traverse_preorder() {
- if node.is_element() && matches(selectors, &node) {
- let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap();
- return Ok(Some(Temporary::from_rooted(elem)));
- }
- }
- }
- }
- Ok(None)
- }
-
- // http://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
- fn query_selector_all(&self, selectors: DOMString) -> Fallible<Temporary<NodeList>> {
- // Step 1.
- let nodes;
- let root = self.ancestors().last().unwrap_or(self.clone());
- match parse_selector_list_from_str(selectors.as_slice()) {
- // Step 2.
- Err(()) => return Err(Syntax),
- // Step 3.
- Ok(ref selectors) => {
- nodes = root.traverse_preorder().filter(
- |node| node.is_element() && matches(selectors, node)).collect()
- }
- }
- let window = window_from_node(self).root();
- Ok(NodeList::new_simple_list(&window.root_ref(), nodes))
- }
-
- fn ancestors(&self) -> AncestorIterator<'n> {
- AncestorIterator {
- current: self.parent_node.get().map(|node| (*node.root()).clone()),
- }
- }
-
- fn owner_doc(&self) -> Temporary<Document> {
- Temporary::new(self.owner_doc.get().get_ref().clone())
- }
-
- fn set_owner_doc(&self, document: &JSRef<Document>) {
- self.owner_doc.assign(Some(document.clone()));
- }
-
- fn is_in_html_doc(&self) -> bool {
- self.owner_doc().root().is_html_document
- }
-
- fn children(&self) -> AbstractNodeChildrenIterator<'n> {
- AbstractNodeChildrenIterator {
- current_node: self.first_child.get().map(|node| (*node.root()).clone()),
- }
- }
-
- fn child_elements(&self) -> ChildElementIterator<'m, 'n> {
- self.children()
- .filter(|node| {
- node.is_element()
- })
- .map(|node| {
- let elem: &JSRef<Element> = ElementCast::to_ref(&node).unwrap();
- elem.clone()
- })
- }
-
- fn wait_until_safe_to_modify_dom(&self) {
- let document = self.owner_doc().root();
- document.deref().wait_until_safe_to_modify_dom();
- }
-
- fn remove_self(&self) {
- match self.parent_node().root() {
- Some(ref parent) => parent.remove_child(self),
- None => ()
- }
- }
-}
-
-/// If the given untrusted node address represents a valid DOM node in the given runtime,
-/// returns it.
-pub fn from_untrusted_node_address(runtime: *mut JSRuntime, candidate: UntrustedNodeAddress)
- -> Temporary<Node> {
- unsafe {
- let candidate: uintptr_t = mem::transmute(candidate);
- let object: *mut JSObject = jsfriendapi::bindgen::JS_GetAddressableObject(runtime,
- candidate);
- if object.is_null() {
- fail!("Attempted to create a `JS<Node>` from an invalid pointer!")
- }
- let boxed_node: *const Node = utils::unwrap(object);
- Temporary::new(JS::from_raw(boxed_node))
- }
-}
-
-pub trait LayoutNodeHelpers {
- unsafe fn type_id_for_layout(&self) -> NodeTypeId;
-
- unsafe fn parent_node_ref(&self) -> Option<JS<Node>>;
- unsafe fn first_child_ref(&self) -> Option<JS<Node>>;
- unsafe fn last_child_ref(&self) -> Option<JS<Node>>;
- unsafe fn prev_sibling_ref(&self) -> Option<JS<Node>>;
- unsafe fn next_sibling_ref(&self) -> Option<JS<Node>>;
-
- unsafe fn owner_doc_for_layout(&self) -> JS<Document>;
-
- unsafe fn is_element_for_layout(&self) -> bool;
-}
-
-impl LayoutNodeHelpers for JS<Node> {
- #[inline]
- unsafe fn type_id_for_layout(&self) -> NodeTypeId {
- (*self.unsafe_get()).type_id
- }
-
- #[inline]
- unsafe fn is_element_for_layout(&self) -> bool {
- (*self.unsafe_get()).is_element()
- }
-
- #[inline]
- unsafe fn parent_node_ref(&self) -> Option<JS<Node>> {
- (*self.unsafe_get()).parent_node.get()
- }
-
- #[inline]
- unsafe fn first_child_ref(&self) -> Option<JS<Node>> {
- (*self.unsafe_get()).first_child.get()
- }
-
- #[inline]
- unsafe fn last_child_ref(&self) -> Option<JS<Node>> {
- (*self.unsafe_get()).last_child.get()
- }
-
- #[inline]
- unsafe fn prev_sibling_ref(&self) -> Option<JS<Node>> {
- (*self.unsafe_get()).prev_sibling.get()
- }
-
- #[inline]
- unsafe fn next_sibling_ref(&self) -> Option<JS<Node>> {
- (*self.unsafe_get()).next_sibling.get()
- }
-
- #[inline]
- unsafe fn owner_doc_for_layout(&self) -> JS<Document> {
- (*self.unsafe_get()).owner_doc.get().unwrap()
- }
-}
-
-pub trait RawLayoutNodeHelpers {
- unsafe fn get_hover_state_for_layout(&self) -> bool;
- unsafe fn get_disabled_state_for_layout(&self) -> bool;
- unsafe fn get_enabled_state_for_layout(&self) -> bool;
- fn type_id_for_layout(&self) -> NodeTypeId;
-}
-
-impl RawLayoutNodeHelpers for Node {
- unsafe fn get_hover_state_for_layout(&self) -> bool {
- (*self.unsafe_get_flags()).contains(InHoverState)
- }
- unsafe fn get_disabled_state_for_layout(&self) -> bool {
- (*self.unsafe_get_flags()).contains(InDisabledState)
- }
- unsafe fn get_enabled_state_for_layout(&self) -> bool {
- (*self.unsafe_get_flags()).contains(InEnabledState)
- }
-
- fn type_id_for_layout(&self) -> NodeTypeId {
- self.type_id
- }
-}
-
-
-//
-// Iteration and traversal
-//
-
-pub type ChildElementIterator<'a, 'b> = Map<'a, JSRef<'b, Node>,
- JSRef<'b, Element>,
- Filter<'a, JSRef<'b, Node>, AbstractNodeChildrenIterator<'b>>>;
-
-pub struct AbstractNodeChildrenIterator<'a> {
- current_node: Option<JSRef<'a, Node>>,
-}
-
-impl<'a> Iterator<JSRef<'a, Node>> for AbstractNodeChildrenIterator<'a> {
- fn next(&mut self) -> Option<JSRef<'a, Node>> {
- let node = self.current_node.clone();
- self.current_node = node.clone().and_then(|node| {
- node.next_sibling().map(|node| (*node.root()).clone())
- });
- node
- }
-}
-
-pub struct AncestorIterator<'a> {
- current: Option<JSRef<'a, Node>>,
-}
-
-impl<'a> Iterator<JSRef<'a, Node>> for AncestorIterator<'a> {
- fn next(&mut self) -> Option<JSRef<'a, Node>> {
- if self.current.is_none() {
- return None;
- }
-
- // FIXME: Do we need two clones here?
- let x = self.current.get_ref().clone();
- self.current = x.parent_node().map(|node| (*node.root()).clone());
- Some(x)
- }
-}
-
-// FIXME: Do this without precomputing a vector of refs.
-// Easy for preorder; harder for postorder.
-pub struct TreeIterator<'a> {
- nodes: Vec<JSRef<'a, Node>>,
- index: uint,
-}
-
-impl<'a> TreeIterator<'a> {
- fn new(nodes: Vec<JSRef<'a, Node>>) -> TreeIterator<'a> {
- TreeIterator {
- nodes: nodes,
- index: 0,
- }
- }
-}
-
-impl<'a> Iterator<JSRef<'a, Node>> for TreeIterator<'a> {
- fn next(&mut self) -> Option<JSRef<'a, Node>> {
- if self.index >= self.nodes.len() {
- None
- } else {
- let v = self.nodes[self.index];
- let v = v.clone();
- self.index += 1;
- Some(v)
- }
- }
-}
-
-pub struct NodeIterator {
- pub start_node: JS<Node>,
- pub current_node: Option<JS<Node>>,
- pub depth: uint,
- include_start: bool,
- include_descendants_of_void: bool
-}
-
-impl NodeIterator {
- pub fn new<'a>(start_node: &JSRef<'a, Node>,
- include_start: bool,
- include_descendants_of_void: bool) -> NodeIterator {
- NodeIterator {
- start_node: JS::from_rooted(start_node),
- current_node: None,
- depth: 0,
- include_start: include_start,
- include_descendants_of_void: include_descendants_of_void
- }
- }
-
- fn next_child<'b>(&self, node: &JSRef<'b, Node>) -> Option<JSRef<'b, Node>> {
- if !self.include_descendants_of_void && node.is_element() {
- let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
- if elem.deref().is_void() {
- None
- } else {
- node.first_child().map(|child| (*child.root()).clone())
- }
- } else {
- node.first_child().map(|child| (*child.root()).clone())
- }
- }
-}
-
-impl<'a> Iterator<JSRef<'a, Node>> for NodeIterator {
- fn next(&mut self) -> Option<JSRef<'a, Node>> {
- self.current_node = match self.current_node.as_ref().map(|node| node.root()) {
- None => {
- if self.include_start {
- Some(self.start_node)
- } else {
- self.next_child(&*self.start_node.root())
- .map(|child| JS::from_rooted(&child))
- }
- },
- Some(node) => {
- match self.next_child(&*node) {
- Some(child) => {
- self.depth += 1;
- Some(JS::from_rooted(&child))
- },
- None if JS::from_rooted(&*node) == self.start_node => None,
- None => {
- match node.deref().next_sibling().root() {
- Some(sibling) => Some(JS::from_rooted(&*sibling)),
- None => {
- let mut candidate = node.deref().clone();
- while candidate.next_sibling().is_none() {
- candidate = (*candidate.parent_node()
- .expect("Got to root without reaching start node")
- .root()).clone();
- self.depth -= 1;
- if JS::from_rooted(&candidate) == self.start_node {
- break;
- }
- }
- if JS::from_rooted(&candidate) != self.start_node {
- candidate.next_sibling().map(|node| JS::from_rooted(node.root().deref()))
- } else {
- None
- }
- }
- }
- }
- }
- }
- };
- self.current_node.map(|node| (*node.root()).clone())
- }
-}
-
-fn gather_abstract_nodes<'a>(cur: &JSRef<'a, Node>, refs: &mut Vec<JSRef<'a, Node>>, postorder: bool) {
- if !postorder {
- refs.push(cur.clone());
- }
- for kid in cur.children() {
- gather_abstract_nodes(&kid, refs, postorder)
- }
- if postorder {
- refs.push(cur.clone());
- }
-}
-
-/// Specifies whether children must be recursively cloned or not.
-#[deriving(PartialEq)]
-pub enum CloneChildrenFlag {
- CloneChildren,
- DoNotCloneChildren
-}
-
-fn as_uintptr<T>(t: &T) -> uintptr_t { t as *const T as uintptr_t }
-
-impl Node {
- pub fn reflect_node<N: Reflectable+NodeBase>
- (node: Box<N>,
- document: &JSRef<Document>,
- wrap_fn: extern "Rust" fn(*mut JSContext, &GlobalRef, Box<N>) -> Temporary<N>)
- -> Temporary<N> {
- let window = document.window.root();
- reflect_dom_object(node, &Window(*window), wrap_fn)
- }
-
- pub fn new_inherited(type_id: NodeTypeId, doc: &JSRef<Document>) -> Node {
- Node::new_(type_id, Some(doc.clone()))
- }
-
- pub fn new_without_doc(type_id: NodeTypeId) -> Node {
- Node::new_(type_id, None)
- }
-
- fn new_(type_id: NodeTypeId, doc: Option<JSRef<Document>>) -> Node {
- Node {
- eventtarget: EventTarget::new_inherited(NodeTargetTypeId(type_id)),
- type_id: type_id,
-
- parent_node: Cell::new(None),
- first_child: Cell::new(None),
- last_child: Cell::new(None),
- next_sibling: Cell::new(None),
- prev_sibling: Cell::new(None),
- owner_doc: Cell::new(doc.unrooted()),
- child_list: Cell::new(None),
-
- flags: Traceable::new(RefCell::new(NodeFlags::new(type_id))),
-
- layout_data: LayoutDataRef::new(),
- }
- }
-
- // http://dom.spec.whatwg.org/#concept-node-adopt
- pub fn adopt(node: &JSRef<Node>, document: &JSRef<Document>) {
- // Step 1.
- match node.parent_node().root() {
- Some(parent) => {
- Node::remove(node, &*parent, Unsuppressed);
- }
- None => (),
- }
-
- // Step 2.
- let node_doc = document_from_node(node).root();
- if &*node_doc != document {
- for descendant in node.traverse_preorder() {
- descendant.set_owner_doc(document);
- }
- }
-
- // Step 3.
- // If node is an element, it is _affected by a base URL change_.
- }
-
- // http://dom.spec.whatwg.org/#concept-node-pre-insert
- fn pre_insert(node: &JSRef<Node>, parent: &JSRef<Node>, child: Option<JSRef<Node>>)
- -> Fallible<Temporary<Node>> {
- // Step 1.
- match parent.type_id() {
- DocumentNodeTypeId |
- DocumentFragmentNodeTypeId |
- ElementNodeTypeId(..) => (),
- _ => return Err(HierarchyRequest)
- }
-
- // Step 2.
- if node.is_inclusive_ancestor_of(parent) {
- return Err(HierarchyRequest);
- }
-
- // Step 3.
- match child {
- Some(ref child) if !parent.is_parent_of(child) => return Err(NotFound),
- _ => ()
- }
-
- // Step 4-5.
- match node.type_id() {
- TextNodeTypeId => {
- match node.parent_node().root() {
- Some(ref parent) if parent.is_document() => return Err(HierarchyRequest),
- _ => ()
- }
- }
- DoctypeNodeTypeId => {
- match node.parent_node().root() {
- Some(ref parent) if !parent.is_document() => return Err(HierarchyRequest),
- _ => ()
- }
- }
- DocumentFragmentNodeTypeId |
- ElementNodeTypeId(_) |
- ProcessingInstructionNodeTypeId |
- CommentNodeTypeId => (),
- DocumentNodeTypeId => return Err(HierarchyRequest)
- }
-
- // Step 6.
- match parent.type_id() {
- DocumentNodeTypeId => {
- match node.type_id() {
- // Step 6.1
- DocumentFragmentNodeTypeId => {
- // Step 6.1.1(b)
- if node.children().any(|c| c.is_text()) {
- return Err(HierarchyRequest);
- }
- match node.child_elements().count() {
- 0 => (),
- // Step 6.1.2
- 1 => {
- // FIXME: change to empty() when https://github.com/mozilla/rust/issues/11218
- // will be fixed
- if parent.child_elements().count() > 0 {
- return Err(HierarchyRequest);
- }
- match child {
- Some(ref child) => {
- if child.inclusively_following_siblings()
- .any(|child| child.is_doctype()) {
- return Err(HierarchyRequest)
- }
- }
- _ => (),
- }
- },
- // Step 6.1.1(a)
- _ => return Err(HierarchyRequest),
- }
- },
- // Step 6.2
- ElementNodeTypeId(_) => {
- // FIXME: change to empty() when https://github.com/mozilla/rust/issues/11218
- // will be fixed
- if parent.child_elements().count() > 0 {
- return Err(HierarchyRequest);
- }
- match child {
- Some(ref child) => {
- if child.inclusively_following_siblings()
- .any(|child| child.is_doctype()) {
- return Err(HierarchyRequest)
- }
- }
- _ => (),
- }
- },
- // Step 6.3
- DoctypeNodeTypeId => {
- if parent.children().any(|c| c.is_doctype()) {
- return Err(HierarchyRequest);
- }
- match child {
- Some(ref child) => {
- if parent.children()
- .take_while(|c| c != child)
- .any(|c| c.is_element()) {
- return Err(HierarchyRequest);
- }
- },
- None => {
- // FIXME: change to empty() when https://github.com/mozilla/rust/issues/11218
- // will be fixed
- if parent.child_elements().count() > 0 {
- return Err(HierarchyRequest);
- }
- },
- }
- },
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId |
- CommentNodeTypeId => (),
- DocumentNodeTypeId => unreachable!(),
- }
- },
- _ => (),
- }
-
- // Step 7-8.
- let referenceChild = match child {
- Some(ref child) if child == node => node.next_sibling().map(|node| (*node.root()).clone()),
- _ => child
- };
-
- // Step 9.
- let document = document_from_node(parent).root();
- Node::adopt(node, &*document);
-
- // Step 10.
- Node::insert(node, parent, referenceChild, Unsuppressed);
-
- // Step 11.
- return Ok(Temporary::from_rooted(node))
- }
-
- // http://dom.spec.whatwg.org/#concept-node-insert
- fn insert(node: &JSRef<Node>,
- parent: &JSRef<Node>,
- child: Option<JSRef<Node>>,
- suppress_observers: SuppressObserver) {
- // XXX assert owner_doc
- // Step 1-3: ranges.
- // Step 4.
- let mut nodes = match node.type_id() {
- DocumentFragmentNodeTypeId => node.children().collect(),
- _ => vec!(node.clone()),
- };
-
- // Step 5: DocumentFragment, mutation records.
- // Step 6: DocumentFragment.
- match node.type_id() {
- DocumentFragmentNodeTypeId => {
- for c in node.children() {
- Node::remove(&c, node, Suppressed);
- }
- },
- _ => (),
- }
-
- // Step 7: mutation records.
- // Step 8.
- for node in nodes.mut_iter() {
- parent.add_child(node, child);
- let is_in_doc = parent.is_in_doc();
- for kid in node.traverse_preorder() {
- if is_in_doc {
- kid.flags.deref().borrow_mut().insert(IsInDoc);
- } else {
- kid.flags.deref().borrow_mut().remove(IsInDoc);
- }
- }
- }
-
- // Step 9.
- match suppress_observers {
- Unsuppressed => {
- for node in nodes.iter() {
- node.node_inserted();
- }
- }
- Suppressed => ()
- }
- }
-
- // http://dom.spec.whatwg.org/#concept-node-replace-all
- fn replace_all(node: Option<JSRef<Node>>, parent: &JSRef<Node>) {
-
- // Step 1.
- match node {
- Some(ref node) => {
- let document = document_from_node(parent).root();
- Node::adopt(node, &*document);
- }
- None => (),
- }
-
- // Step 2.
- let removedNodes: Vec<JSRef<Node>> = parent.children().collect();
-
- // Step 3.
- let addedNodes = match node {
- None => vec!(),
- Some(ref node) => match node.type_id() {
- DocumentFragmentNodeTypeId => node.children().collect(),
- _ => vec!(node.clone()),
- },
- };
-
- // Step 4.
- for child in parent.children() {
- Node::remove(&child, parent, Suppressed);
- }
-
- // Step 5.
- match node {
- Some(ref node) => Node::insert(node, parent, None, Suppressed),
- None => (),
- }
-
- // Step 6: mutation records.
-
- // Step 7.
- let parent_in_doc = parent.is_in_doc();
- for removedNode in removedNodes.iter() {
- removedNode.node_removed(parent_in_doc);
- }
- for addedNode in addedNodes.iter() {
- addedNode.node_inserted();
- }
- }
-
- // http://dom.spec.whatwg.org/#concept-node-pre-remove
- fn pre_remove(child: &JSRef<Node>, parent: &JSRef<Node>) -> Fallible<Temporary<Node>> {
- // Step 1.
- match child.parent_node() {
- Some(ref node) if *node != Temporary::from_rooted(parent) => return Err(NotFound),
- _ => ()
- }
-
- // Step 2.
- Node::remove(child, parent, Unsuppressed);
-
- // Step 3.
- Ok(Temporary::from_rooted(child))
- }
-
- // http://dom.spec.whatwg.org/#concept-node-remove
- fn remove(node: &JSRef<Node>, parent: &JSRef<Node>, suppress_observers: SuppressObserver) {
- assert!(node.parent_node().map_or(false, |node_parent| node_parent == Temporary::from_rooted(parent)));
-
- // Step 1-5: ranges.
- // Step 6-7: mutation observers.
- // Step 8.
- parent.remove_child(node);
-
- node.deref().flags.deref().borrow_mut().remove(IsInDoc);
-
- // Step 9.
- match suppress_observers {
- Suppressed => (),
- Unsuppressed => node.node_removed(parent.is_in_doc()),
- }
- }
-
- // http://dom.spec.whatwg.org/#concept-node-clone
- pub fn clone(node: &JSRef<Node>, maybe_doc: Option<&JSRef<Document>>,
- clone_children: CloneChildrenFlag) -> Temporary<Node> {
-
- // Step 1.
- let document = match maybe_doc {
- Some(doc) => JS::from_rooted(doc).root(),
- None => node.owner_doc().root()
- };
-
- // Step 2.
- // XXXabinader: clone() for each node as trait?
- let copy: Root<Node> = match node.type_id() {
- DoctypeNodeTypeId => {
- let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap();
- let doctype = doctype.deref();
- let doctype = DocumentType::new(doctype.name.clone(),
- Some(doctype.public_id.clone()),
- Some(doctype.system_id.clone()), &*document);
- NodeCast::from_temporary(doctype)
- },
- DocumentFragmentNodeTypeId => {
- let doc_fragment = DocumentFragment::new(&*document);
- NodeCast::from_temporary(doc_fragment)
- },
- CommentNodeTypeId => {
- let comment: &JSRef<Comment> = CommentCast::to_ref(node).unwrap();
- let comment = comment.deref();
- let comment = Comment::new(comment.characterdata.data.deref().borrow().clone(), &*document);
- NodeCast::from_temporary(comment)
- },
- DocumentNodeTypeId => {
- let document: &JSRef<Document> = DocumentCast::to_ref(node).unwrap();
- let is_html_doc = match document.is_html_document {
- true => HTMLDocument,
- false => NonHTMLDocument
- };
- let window = document.window.root();
- let document = Document::new(&*window, Some(document.url().clone()),
- is_html_doc, None);
- NodeCast::from_temporary(document)
- },
- ElementNodeTypeId(..) => {
- let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
- let element = element.deref();
- let element = build_element_from_tag(element.local_name.as_slice().to_string(),
- element.namespace.clone(), &*document);
- NodeCast::from_temporary(element)
- },
- TextNodeTypeId => {
- let text: &JSRef<Text> = TextCast::to_ref(node).unwrap();
- let text = text.deref();
- let text = Text::new(text.characterdata.data.deref().borrow().clone(), &*document);
- NodeCast::from_temporary(text)
- },
- ProcessingInstructionNodeTypeId => {
- let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
- let pi = pi.deref();
- let pi = ProcessingInstruction::new(pi.target.clone(),
- pi.characterdata.data.deref().borrow().clone(), &*document);
- NodeCast::from_temporary(pi)
- },
- }.root();
-
- // Step 3.
- let document = if copy.is_document() {
- let doc: &JSRef<Document> = DocumentCast::to_ref(&*copy).unwrap();
- JS::from_rooted(doc).root()
- } else {
- JS::from_rooted(&*document).root()
- };
- assert!(&*copy.owner_doc().root() == &*document);
-
- // Step 4 (some data already copied in step 2).
- match node.type_id() {
- DocumentNodeTypeId => {
- let node_doc: &JSRef<Document> = DocumentCast::to_ref(node).unwrap();
- let copy_doc: &JSRef<Document> = DocumentCast::to_ref(&*copy).unwrap();
- copy_doc.set_encoding_name(node_doc.encoding_name.deref().borrow().clone());
- copy_doc.set_quirks_mode(node_doc.quirks_mode());
- },
- ElementNodeTypeId(..) => {
- let node_elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
- let copy_elem: &JSRef<Element> = ElementCast::to_ref(&*copy).unwrap();
-
- // FIXME: https://github.com/mozilla/servo/issues/1737
- let window = document.deref().window.root();
- for attr in node_elem.deref().attrs.borrow().iter().map(|attr| attr.root()) {
- copy_elem.deref().attrs.borrow_mut().push_unrooted(
- &Attr::new(&*window,
- attr.local_name().clone(), attr.deref().value().clone(),
- attr.deref().name.clone(), attr.deref().namespace.clone(),
- attr.deref().prefix.clone(), copy_elem));
- }
- },
- _ => ()
- }
-
- // Step 5: cloning steps.
-
- // Step 6.
- if clone_children == CloneChildren {
- for ref child in node.children() {
- let child_copy = Node::clone(&*child, Some(&*document), clone_children).root();
- let _inserted_node = Node::pre_insert(&*child_copy, &*copy, None);
- }
- }
-
- // Step 7.
- Temporary::from_rooted(&*copy)
- }
-
- /// Sends layout data, if any, back to the layout task to be destroyed.
- unsafe fn reap_layout_data(&mut self) {
- if self.layout_data.is_present() {
- let layout_data = mem::replace(&mut self.layout_data, LayoutDataRef::new());
- let layout_chan = layout_data.take_chan();
- match layout_chan {
- None => {}
- Some(chan) => {
- let LayoutChan(chan) = chan;
- chan.send(ReapLayoutDataMsg(layout_data))
- },
- }
- }
- }
-
- pub unsafe fn unsafe_get_flags(&self) -> *const NodeFlags {
- mem::transmute(&self.flags)
- }
-
- pub fn collect_text_contents<'a, T: Iterator<JSRef<'a, Node>>>(mut iterator: T) -> String {
- let mut content = String::new();
- for node in iterator {
- let text: Option<&JSRef<Text>> = TextCast::to_ref(&node);
- match text {
- Some(text) => content.push_str(text.characterdata.data.borrow().as_slice()),
- None => (),
- }
- }
- content
- }
-}
-
-impl<'a> NodeMethods for JSRef<'a, Node> {
- // http://dom.spec.whatwg.org/#dom-node-nodetype
- fn NodeType(&self) -> u16 {
- match self.type_id {
- ElementNodeTypeId(_) => NodeConstants::ELEMENT_NODE,
- TextNodeTypeId => NodeConstants::TEXT_NODE,
- ProcessingInstructionNodeTypeId => NodeConstants::PROCESSING_INSTRUCTION_NODE,
- CommentNodeTypeId => NodeConstants::COMMENT_NODE,
- DocumentNodeTypeId => NodeConstants::DOCUMENT_NODE,
- DoctypeNodeTypeId => NodeConstants::DOCUMENT_TYPE_NODE,
- DocumentFragmentNodeTypeId => NodeConstants::DOCUMENT_FRAGMENT_NODE,
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-nodename
- fn NodeName(&self) -> DOMString {
- match self.type_id {
- ElementNodeTypeId(..) => {
- let elem: &JSRef<Element> = ElementCast::to_ref(self).unwrap();
- elem.TagName()
- }
- TextNodeTypeId => "#text".to_string(),
- ProcessingInstructionNodeTypeId => {
- let processing_instruction: &JSRef<ProcessingInstruction> =
- ProcessingInstructionCast::to_ref(self).unwrap();
- processing_instruction.Target()
- }
- CommentNodeTypeId => "#comment".to_string(),
- DoctypeNodeTypeId => {
- let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(self).unwrap();
- doctype.deref().name.clone()
- },
- DocumentFragmentNodeTypeId => "#document-fragment".to_string(),
- DocumentNodeTypeId => "#document".to_string()
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-baseuri
- fn GetBaseURI(&self) -> Option<DOMString> {
- // FIXME (#1824) implement.
- None
- }
-
- // http://dom.spec.whatwg.org/#dom-node-ownerdocument
- fn GetOwnerDocument(&self) -> Option<Temporary<Document>> {
- match self.type_id {
- ElementNodeTypeId(..) |
- CommentNodeTypeId |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId |
- DoctypeNodeTypeId |
- DocumentFragmentNodeTypeId => Some(self.owner_doc()),
- DocumentNodeTypeId => None
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-parentnode
- fn GetParentNode(&self) -> Option<Temporary<Node>> {
- self.parent_node.get().map(|node| Temporary::new(node))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-parentelement
- fn GetParentElement(&self) -> Option<Temporary<Element>> {
- self.parent_node.get()
- .and_then(|parent| {
- let parent = parent.root();
- ElementCast::to_ref(&*parent).map(|elem| {
- Temporary::from_rooted(elem)
- })
- })
- }
-
- // http://dom.spec.whatwg.org/#dom-node-haschildnodes
- fn HasChildNodes(&self) -> bool {
- self.first_child.get().is_some()
- }
-
- // http://dom.spec.whatwg.org/#dom-node-childnodes
- fn ChildNodes(&self) -> Temporary<NodeList> {
- match self.child_list.get() {
- None => (),
- Some(ref list) => return Temporary::new(list.clone()),
- }
-
- let doc = self.owner_doc().root();
- let window = doc.deref().window.root();
- let child_list = NodeList::new_child_list(&*window, self);
- self.child_list.assign(Some(child_list));
- Temporary::new(self.child_list.get().get_ref().clone())
- }
-
- // http://dom.spec.whatwg.org/#dom-node-firstchild
- fn GetFirstChild(&self) -> Option<Temporary<Node>> {
- self.first_child.get().map(|node| Temporary::new(node))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-lastchild
- fn GetLastChild(&self) -> Option<Temporary<Node>> {
- self.last_child.get().map(|node| Temporary::new(node))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-previoussibling
- fn GetPreviousSibling(&self) -> Option<Temporary<Node>> {
- self.prev_sibling.get().map(|node| Temporary::new(node))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-nextsibling
- fn GetNextSibling(&self) -> Option<Temporary<Node>> {
- self.next_sibling.get().map(|node| Temporary::new(node))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-nodevalue
- fn GetNodeValue(&self) -> Option<DOMString> {
- match self.type_id {
- CommentNodeTypeId |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId => {
- let chardata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap();
- Some(chardata.Data())
- }
- _ => {
- None
- }
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-nodevalue
- fn SetNodeValue(&self, val: Option<DOMString>) {
- match self.type_id {
- CommentNodeTypeId |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId => {
- self.SetTextContent(val)
- }
- _ => {}
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-textcontent
- fn GetTextContent(&self) -> Option<DOMString> {
- match self.type_id {
- DocumentFragmentNodeTypeId |
- ElementNodeTypeId(..) => {
- let content = Node::collect_text_contents(self.traverse_preorder());
- Some(content)
- }
- CommentNodeTypeId |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId => {
- let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap();
- Some(characterdata.Data())
- }
- DoctypeNodeTypeId |
- DocumentNodeTypeId => {
- None
- }
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-textcontent
- fn SetTextContent(&self, value: Option<DOMString>) {
- let value = null_str_as_empty(&value);
- match self.type_id {
- DocumentFragmentNodeTypeId |
- ElementNodeTypeId(..) => {
- // Step 1-2.
- let node = if value.len() == 0 {
- None
- } else {
- let document = self.owner_doc().root();
- Some(NodeCast::from_temporary(document.deref().CreateTextNode(value)))
- }.root();
-
- // Step 3.
- Node::replace_all(node.root_ref(), self);
- }
- CommentNodeTypeId |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId => {
- self.wait_until_safe_to_modify_dom();
-
- let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(self).unwrap();
- *characterdata.data.deref().borrow_mut() = value;
-
- // Notify the document that the content of this node is different
- let document = self.owner_doc().root();
- document.deref().content_changed();
- }
- DoctypeNodeTypeId |
- DocumentNodeTypeId => {}
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-insertbefore
- fn InsertBefore(&self, node: &JSRef<Node>, child: Option<JSRef<Node>>) -> Fallible<Temporary<Node>> {
- Node::pre_insert(node, self, child)
- }
-
- // http://dom.spec.whatwg.org/#dom-node-appendchild
- fn AppendChild(&self, node: &JSRef<Node>) -> Fallible<Temporary<Node>> {
- Node::pre_insert(node, self, None)
- }
-
- // http://dom.spec.whatwg.org/#concept-node-replace
- fn ReplaceChild(&self, node: &JSRef<Node>, child: &JSRef<Node>) -> Fallible<Temporary<Node>> {
-
- // Step 1.
- match self.type_id {
- DocumentNodeTypeId |
- DocumentFragmentNodeTypeId |
- ElementNodeTypeId(..) => (),
- _ => return Err(HierarchyRequest)
- }
-
- // Step 2.
- if node.is_inclusive_ancestor_of(self) {
- return Err(HierarchyRequest);
- }
-
- // Step 3.
- if !self.is_parent_of(child) {
- return Err(NotFound);
- }
-
- // Step 4-5.
- match node.type_id() {
- TextNodeTypeId if self.is_document() => return Err(HierarchyRequest),
- DoctypeNodeTypeId if !self.is_document() => return Err(HierarchyRequest),
- DocumentFragmentNodeTypeId |
- DoctypeNodeTypeId |
- ElementNodeTypeId(..) |
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId |
- CommentNodeTypeId => (),
- DocumentNodeTypeId => return Err(HierarchyRequest)
- }
-
- // Step 6.
- match self.type_id {
- DocumentNodeTypeId => {
- match node.type_id() {
- // Step 6.1
- DocumentFragmentNodeTypeId => {
- // Step 6.1.1(b)
- if node.children().any(|c| c.is_text()) {
- return Err(HierarchyRequest);
- }
- match node.child_elements().count() {
- 0 => (),
- // Step 6.1.2
- 1 => {
- if self.child_elements().any(|c| NodeCast::from_ref(&c) != child) {
- return Err(HierarchyRequest);
- }
- if child.following_siblings()
- .any(|child| child.is_doctype()) {
- return Err(HierarchyRequest);
- }
- },
- // Step 6.1.1(a)
- _ => return Err(HierarchyRequest)
- }
- },
- // Step 6.2
- ElementNodeTypeId(..) => {
- if self.child_elements().any(|c| NodeCast::from_ref(&c) != child) {
- return Err(HierarchyRequest);
- }
- if child.following_siblings()
- .any(|child| child.is_doctype()) {
- return Err(HierarchyRequest);
- }
- },
- // Step 6.3
- DoctypeNodeTypeId => {
- if self.children().any(|c| c.is_doctype() && &c != child) {
- return Err(HierarchyRequest);
- }
- if self.children()
- .take_while(|c| c != child)
- .any(|c| c.is_element()) {
- return Err(HierarchyRequest);
- }
- },
- TextNodeTypeId |
- ProcessingInstructionNodeTypeId |
- CommentNodeTypeId => (),
- DocumentNodeTypeId => unreachable!()
- }
- },
- _ => ()
- }
-
- // Ok if not caught by previous error checks.
- if *node == *child {
- return Ok(Temporary::from_rooted(child));
- }
-
- // Step 7-8.
- let next_sibling = child.next_sibling().map(|node| (*node.root()).clone());
- let reference_child = match next_sibling {
- Some(ref sibling) if sibling == node => node.next_sibling().map(|node| (*node.root()).clone()),
- _ => next_sibling
- };
-
- // Step 9.
- let document = document_from_node(self).root();
- Node::adopt(node, &*document);
-
- {
- // Step 10.
- Node::remove(child, self, Suppressed);
-
- // Step 11.
- Node::insert(node, self, reference_child, Suppressed);
- }
-
- // Step 12-14.
- // Step 13: mutation records.
- child.node_removed(self.is_in_doc());
- if node.type_id() == DocumentFragmentNodeTypeId {
- for child_node in node.children() {
- child_node.node_inserted();
- }
- } else {
- node.node_inserted();
- }
-
- // Step 15.
- Ok(Temporary::from_rooted(child))
- }
-
- // http://dom.spec.whatwg.org/#dom-node-removechild
- fn RemoveChild(&self, node: &JSRef<Node>)
- -> Fallible<Temporary<Node>> {
- Node::pre_remove(node, self)
- }
-
- // http://dom.spec.whatwg.org/#dom-node-normalize
- fn Normalize(&self) {
- let mut prev_text = None;
- for child in self.children() {
- if child.is_text() {
- let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(&child).unwrap();
- if characterdata.Length() == 0 {
- self.remove_child(&child);
- } else {
- match prev_text {
- Some(ref mut text_node) => {
- let prev_characterdata: &mut JSRef<CharacterData> = CharacterDataCast::to_mut_ref(text_node).unwrap();
- let _ = prev_characterdata.AppendData(characterdata.Data());
- self.remove_child(&child);
- },
- None => prev_text = Some(child)
- }
- }
- } else {
- child.Normalize();
- prev_text = None;
- }
-
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-clonenode
- fn CloneNode(&self, deep: bool) -> Temporary<Node> {
- match deep {
- true => Node::clone(self, None, CloneChildren),
- false => Node::clone(self, None, DoNotCloneChildren)
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-isequalnode
- fn IsEqualNode(&self, maybe_node: Option<JSRef<Node>>) -> bool {
- fn is_equal_doctype(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
- let doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap();
- let other_doctype: &JSRef<DocumentType> = DocumentTypeCast::to_ref(other).unwrap();
- (doctype.deref().name == other_doctype.deref().name) &&
- (doctype.deref().public_id == other_doctype.deref().public_id) &&
- (doctype.deref().system_id == other_doctype.deref().system_id)
- }
- fn is_equal_element(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
- let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
- let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap();
- // FIXME: namespace prefix
- let element = element.deref();
- let other_element = other_element.deref();
- (element.namespace == other_element.namespace) &&
- (element.local_name == other_element.local_name) &&
- (element.attrs.borrow().len() == other_element.attrs.borrow().len())
- }
- fn is_equal_processinginstruction(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
- let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
- let other_pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(other).unwrap();
- (pi.deref().target == other_pi.deref().target) &&
- (*pi.deref().characterdata.data.deref().borrow() == *other_pi.deref().characterdata.data.deref().borrow())
- }
- fn is_equal_characterdata(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
- let characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(node).unwrap();
- let other_characterdata: &JSRef<CharacterData> = CharacterDataCast::to_ref(other).unwrap();
- *characterdata.deref().data.deref().borrow() == *other_characterdata.deref().data.deref().borrow()
- }
- fn is_equal_element_attrs(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
- let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
- let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap();
- let element = element.deref();
- let other_element = other_element.deref();
- assert!(element.attrs.borrow().len() == other_element.attrs.borrow().len());
- element.attrs.borrow().iter().map(|attr| attr.root()).all(|attr| {
- other_element.attrs.borrow().iter().map(|attr| attr.root()).any(|other_attr| {
- (attr.namespace == other_attr.namespace) &&
- (attr.local_name() == other_attr.local_name()) &&
- (attr.deref().value().as_slice() == other_attr.deref().value().as_slice())
- })
- })
- }
- fn is_equal_node(this: &JSRef<Node>, node: &JSRef<Node>) -> bool {
- // Step 2.
- if this.type_id() != node.type_id() {
- return false;
- }
-
- match node.type_id() {
- // Step 3.
- DoctypeNodeTypeId if !is_equal_doctype(this, node) => return false,
- ElementNodeTypeId(..) if !is_equal_element(this, node) => return false,
- ProcessingInstructionNodeTypeId if !is_equal_processinginstruction(this, node) => return false,
- TextNodeTypeId |
- CommentNodeTypeId if !is_equal_characterdata(this, node) => return false,
- // Step 4.
- ElementNodeTypeId(..) if !is_equal_element_attrs(this, node) => return false,
- _ => ()
- }
-
- // Step 5.
- if this.children().count() != node.children().count() {
- return false;
- }
-
- // Step 6.
- this.children().zip(node.children()).all(|(ref child, ref other_child)| {
- is_equal_node(child, other_child)
- })
- }
- match maybe_node {
- // Step 1.
- None => false,
- // Step 2-6.
- Some(ref node) => is_equal_node(self, node)
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-comparedocumentposition
- fn CompareDocumentPosition(&self, other: &JSRef<Node>) -> u16 {
- if self == other {
- // step 2.
- 0
- } else {
- let mut lastself = self.clone();
- let mut lastother = other.clone();
- for ancestor in self.ancestors() {
- if &ancestor == other {
- // step 4.
- return NodeConstants::DOCUMENT_POSITION_CONTAINS +
- NodeConstants::DOCUMENT_POSITION_PRECEDING;
- }
- lastself = ancestor.clone();
- }
- for ancestor in other.ancestors() {
- if &ancestor == self {
- // step 5.
- return NodeConstants::DOCUMENT_POSITION_CONTAINED_BY +
- NodeConstants::DOCUMENT_POSITION_FOLLOWING;
- }
- lastother = ancestor.clone();
- }
-
- if lastself != lastother {
- let abstract_uint: uintptr_t = as_uintptr(&*self);
- let other_uint: uintptr_t = as_uintptr(&*other);
-
- let random = if abstract_uint < other_uint {
- NodeConstants::DOCUMENT_POSITION_FOLLOWING
- } else {
- NodeConstants::DOCUMENT_POSITION_PRECEDING
- };
- // step 3.
- return random +
- NodeConstants::DOCUMENT_POSITION_DISCONNECTED +
- NodeConstants::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
- }
-
- for child in lastself.traverse_preorder() {
- if &child == other {
- // step 6.
- return NodeConstants::DOCUMENT_POSITION_PRECEDING;
- }
- if &child == self {
- // step 7.
- return NodeConstants::DOCUMENT_POSITION_FOLLOWING;
- }
- }
- unreachable!()
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-contains
- fn Contains(&self, maybe_other: Option<JSRef<Node>>) -> bool {
- match maybe_other {
- None => false,
- Some(ref other) => self.is_inclusive_ancestor_of(other)
- }
- }
-
- // http://dom.spec.whatwg.org/#dom-node-lookupprefix
- fn LookupPrefix(&self, _prefix: Option<DOMString>) -> Option<DOMString> {
- // FIXME (#1826) implement.
- None
- }
-
- // http://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri
- fn LookupNamespaceURI(&self, _namespace: Option<DOMString>) -> Option<DOMString> {
- // FIXME (#1826) implement.
- None
- }
-
- // http://dom.spec.whatwg.org/#dom-node-isdefaultnamespace
- fn IsDefaultNamespace(&self, _namespace: Option<DOMString>) -> bool {
- // FIXME (#1826) implement.
- false
- }
-}
-
-
-impl Reflectable for Node {
- fn reflector<'a>(&'a self) -> &'a Reflector {
- self.eventtarget.reflector()
- }
-}
-
-pub fn document_from_node<T: NodeBase>(derived: &JSRef<T>) -> Temporary<Document> {
- let node: &JSRef<Node> = NodeCast::from_ref(derived);
- node.owner_doc()
-}
-
-pub fn window_from_node<T: NodeBase>(derived: &JSRef<T>) -> Temporary<Window> {
- let document = document_from_node(derived).root();
- Temporary::new(document.deref().window.clone())
-}
-
-impl<'a> VirtualMethods for JSRef<'a, Node> {
- fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
- let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
- Some(eventtarget as &VirtualMethods)
- }
-}
-
-impl<'a> style::TNode<JSRef<'a, Element>> for JSRef<'a, Node> {
- fn parent_node(&self) -> Option<JSRef<'a, Node>> {
- (self as &NodeHelpers).parent_node().map(|node| *node.root())
- }
-
- fn prev_sibling(&self) -> Option<JSRef<'a, Node>> {
- (self as &NodeHelpers).prev_sibling().map(|node| *node.root())
- }
-
- fn next_sibling(&self) -> Option<JSRef<'a, Node>> {
- (self as &NodeHelpers).next_sibling().map(|node| *node.root())
- }
-
- fn is_document(&self) -> bool {
- (self as &NodeHelpers).is_document()
- }
-
- fn is_element(&self) -> bool {
- (self as &NodeHelpers).is_element()
- }
-
- fn as_element(&self) -> JSRef<'a, Element> {
- let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
- assert!(elem.is_some());
- *elem.unwrap()
- }
-
- fn match_attr(&self, attr: &style::AttrSelector, test: |&str| -> bool) -> bool {
- let name = {
- if self.is_html_element_in_html_document() {
- attr.lower_name.as_slice()
- } else {
- attr.name.as_slice()
- }
- };
- match attr.namespace {
- style::SpecificNamespace(ref ns) => {
- self.as_element().get_attribute(ns.clone(), name).root()
- .map_or(false, |attr| test(attr.deref().Value().as_slice()))
- },
- // FIXME: https://github.com/mozilla/servo/issues/1558
- style::AnyNamespace => false,
- }
- }
-
- fn is_html_element_in_html_document(&self) -> bool {
- let elem: Option<&JSRef<'a, Element>> = ElementCast::to_ref(self);
- assert!(elem.is_some());
- let elem: &ElementHelpers = elem.unwrap() as &ElementHelpers;
- elem.html_element_in_html_document()
- }
-}
-
-pub trait DisabledStateHelpers {
- fn check_ancestors_disabled_state_for_form_control(&self);
- fn check_parent_disabled_state_for_option(&self);
- fn check_disabled_attribute(&self);
-}
-
-impl<'a> DisabledStateHelpers for JSRef<'a, Node> {
- fn check_ancestors_disabled_state_for_form_control(&self) {
- if self.get_disabled_state() { return; }
- for ancestor in self.ancestors().filter(|ancestor| ancestor.is_htmlfieldsetelement()) {
- if !ancestor.get_disabled_state() { continue; }
- if ancestor.is_parent_of(self) {
- self.set_disabled_state(true);
- self.set_enabled_state(false);
- return;
- }
- match ancestor.children().find(|child| child.is_htmllegendelement()) {
- Some(ref legend) => {
- // XXXabinader: should we save previous ancestor to avoid this iteration?
- if self.ancestors().any(|ancestor| ancestor == *legend) { continue; }
- },
- None => ()
- }
- self.set_disabled_state(true);
- self.set_enabled_state(false);
- return;
- }
- }
-
- fn check_parent_disabled_state_for_option(&self) {
- if self.get_disabled_state() { return; }
- match self.parent_node().root() {
- Some(ref parent) if parent.is_htmloptgroupelement() && parent.get_disabled_state() => {
- self.set_disabled_state(true);
- self.set_enabled_state(false);
- },
- _ => ()
- }
- }
-
- fn check_disabled_attribute(&self) {
- let elem: &JSRef<'a, Element> = ElementCast::to_ref(self).unwrap();
- let has_disabled_attrib = elem.has_attribute("disabled");
- self.set_disabled_state(has_disabled_attrib);
- self.set_enabled_state(!has_disabled_attrib);
- }
-}