diff options
Diffstat (limited to 'components/script/dom/node.rs')
-rw-r--r-- | components/script/dom/node.rs | 211 |
1 files changed, 177 insertions, 34 deletions
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ee1451a0137..ddea136c9f3 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -4,6 +4,7 @@ //! The core DOM types. Defines the basic DOM hierarchy as well as all the HTML elements. +use document_loader::DocumentLoader; use dom::attr::{Attr, AttrHelpers}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; @@ -157,6 +158,9 @@ bitflags! { const CLICK_IN_PROGRESS = 0x100, #[doc = "Specifies whether this node has the focus."] const IN_FOCUS_STATE = 0x200, + #[doc = "Specifies whether this node is focusable and whether it is supposed \ + to be reachable with using sequential focus navigation."] + const SEQUENTIALLY_FOCUSABLE = 0x400, } } @@ -173,7 +177,8 @@ impl NodeFlags { NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement)) | NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) | //NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMenuItemElement)) | - NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => IN_ENABLED_STATE | dirty, + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => + IN_ENABLED_STATE | dirty, _ => dirty, } } @@ -244,7 +249,7 @@ impl LayoutDataRef { #[inline] #[allow(unsafe_code)] pub unsafe fn borrow_unchecked(&self) -> *const Option<LayoutData> { - mem::transmute(&self.data_cell) + self.data_cell.as_unsafe_cell().get() as *const _ } /// Borrows the layout data immutably. This function is *not* thread-safe. @@ -422,6 +427,9 @@ pub trait NodeHelpers { fn child_elements(self) -> ChildElementIterator; fn following_siblings(self) -> NodeSiblingIterator; fn preceding_siblings(self) -> ReverseSiblingIterator; + fn following_nodes(self, root: JSRef<Node>) -> FollowingNodeIterator; + fn preceding_nodes(self, root: JSRef<Node>) -> PrecedingNodeIterator; + fn descending_last_children(self) -> LastChildIterator; 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; @@ -629,7 +637,7 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { fn set_hover_state(self, state: bool) { self.set_flag(IN_HOVER_STATE, state); - self.dirty(NodeDamage::OtherNodeDamage); + self.dirty(NodeDamage::NodeStyleDamaged); } fn get_focus_state(self) -> bool { @@ -638,7 +646,7 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { fn set_focus_state(self, state: bool) { self.set_flag(IN_FOCUS_STATE, state); - self.dirty(NodeDamage::OtherNodeDamage); + self.dirty(NodeDamage::NodeStyleDamaged); } fn get_disabled_state(self) -> bool { @@ -781,6 +789,26 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { } } + fn following_nodes(self, root: JSRef<Node>) -> FollowingNodeIterator { + FollowingNodeIterator { + current: Some(Temporary::from_rooted(self)), + root: Temporary::from_rooted(root), + } + } + + fn preceding_nodes(self, root: JSRef<Node>) -> PrecedingNodeIterator { + PrecedingNodeIterator { + current: Some(Temporary::from_rooted(self)), + root: Temporary::from_rooted(root), + } + } + + fn descending_last_children(self) -> LastChildIterator { + LastChildIterator { + current: self.GetLastChild(), + } + } + fn is_parent_of(self, child: JSRef<Node>) -> bool { match child.parent_node.get().root() { Some(ref parent) => parent.r() == self, @@ -913,15 +941,11 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { // https://dom.spec.whatwg.org/#dom-parentnode-queryselectorall #[allow(unsafe_code)] fn query_selector_all(self, selectors: DOMString) -> Fallible<Temporary<NodeList>> { - let mut nodes = RootedVec::new(); - for node in try!(unsafe { self.query_selector_iter(selectors) }) { - nodes.push(JS::from_rooted(node)); - } let window = window_from_node(self).root(); - Ok(NodeList::new_simple_list(window.r(), &nodes)) + let iter = try!(unsafe { self.query_selector_iter(selectors) }); + Ok(NodeList::new_simple_list(window.r(), iter)) } - fn ancestors(self) -> AncestorIterator { AncestorIterator { current: self.GetParentNode() @@ -976,20 +1000,17 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { fn get_unique_id(self) -> String { // FIXME(https://github.com/rust-lang/rust/issues/23338) - let id = self.unique_id.borrow(); - id.clone() - } - - fn summarize(self) -> NodeInfo { if self.unique_id.borrow().is_empty() { let mut unique_id = self.unique_id.borrow_mut(); *unique_id = uuid::Uuid::new_v4().to_simple_string(); } + let id = self.unique_id.borrow(); + id.clone() + } - // FIXME(https://github.com/rust-lang/rust/issues/23338) - let unique_id = self.unique_id.borrow(); + fn summarize(self) -> NodeInfo { NodeInfo { - uniqueId: unique_id.clone(), + uniqueId: self.get_unique_id(), baseURI: self.GetBaseURI().unwrap_or("".to_owned()), parent: self.GetParentNode().root().map(|node| node.r().get_unique_id()).unwrap_or("".to_owned()), nodeType: self.NodeType(), @@ -1238,6 +1259,114 @@ impl Iterator for ReverseSiblingIterator { } } +pub struct FollowingNodeIterator { + current: Option<Temporary<Node>>, + root: Temporary<Node>, +} + +impl Iterator for FollowingNodeIterator { + type Item = Temporary<Node>; + + // https://dom.spec.whatwg.org/#concept-tree-following + fn next(&mut self) -> Option<Temporary<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + + let node = current.root(); + if let Some(first_child) = node.r().GetFirstChild() { + self.current = Some(first_child); + return node.r().GetFirstChild() + } + + if self.root == current { + self.current = None; + return None; + } + + if let Some(next_sibling) = node.r().GetNextSibling() { + self.current = Some(next_sibling); + return node.r().GetNextSibling() + } + + for ancestor in node.r().inclusive_ancestors() { + if self.root == ancestor { + break; + } + if let Some(next_sibling) = ancestor.root().r().GetNextSibling() { + self.current = Some(next_sibling); + return ancestor.root().r().GetNextSibling() + } + } + self.current = None; + return None + } +} + +pub struct PrecedingNodeIterator { + current: Option<Temporary<Node>>, + root: Temporary<Node>, +} + +impl Iterator for PrecedingNodeIterator { + type Item = Temporary<Node>; + + // https://dom.spec.whatwg.org/#concept-tree-preceding + fn next(&mut self) -> Option<Temporary<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }; + + if self.root == current { + self.current = None; + return None + } + + let node = current.root(); + if let Some(previous_sibling) = node.r().GetPreviousSibling() { + if self.root == previous_sibling { + self.current = None; + return None + } + + if let Some(last_child) = previous_sibling.root().r().descending_last_children().last() { + self.current = Some(last_child); + return previous_sibling.root().r().descending_last_children().last() + } + + self.current = Some(previous_sibling); + return node.r().GetPreviousSibling() + }; + + if let Some(parent_node) = node.r().GetParentNode() { + self.current = Some(parent_node); + return node.r().GetParentNode() + } + + self.current = None; + return None + } +} + +pub struct LastChildIterator { + current: Option<Temporary<Node>>, +} + +impl Iterator for LastChildIterator { + type Item = Temporary<Node>; + + fn next(&mut self) -> Option<Temporary<Node>> { + let current = match self.current.take() { + None => return None, + Some(current) => current, + }.root(); + self.current = current.r().GetLastChild(); + Some(Temporary::from_rooted(current.r())) + } +} + pub struct AncestorIterator { current: Option<Temporary<Node>>, } @@ -1300,7 +1429,6 @@ impl Iterator for TreeIterator { } } - /// Specifies whether children must be recursively cloned or not. #[derive(Copy, Clone, PartialEq)] pub enum CloneChildrenFlag { @@ -1707,9 +1835,10 @@ impl Node { false => IsHTMLDocument::NonHTMLDocument, }; let window = document.window().root(); + let loader = DocumentLoader::new(&*document.loader()); let document = Document::new(window.r(), Some(document.url()), is_html_doc, None, - None, DocumentSource::NotFromParser); + None, DocumentSource::NotFromParser, loader); NodeCast::from_temporary(document) }, NodeTypeId::Element(..) => { @@ -1803,13 +1932,20 @@ impl<'a> NodeMethods for JSRef<'a, Node> { // https://dom.spec.whatwg.org/#dom-node-nodetype fn NodeType(self) -> u16 { match self.type_id { - NodeTypeId::CharacterData(CharacterDataTypeId::Text) => NodeConstants::TEXT_NODE, - NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => NodeConstants::PROCESSING_INSTRUCTION_NODE, - NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => NodeConstants::COMMENT_NODE, - NodeTypeId::Document => NodeConstants::DOCUMENT_NODE, - NodeTypeId::DocumentType => NodeConstants::DOCUMENT_TYPE_NODE, - NodeTypeId::DocumentFragment => NodeConstants::DOCUMENT_FRAGMENT_NODE, - NodeTypeId::Element(_) => NodeConstants::ELEMENT_NODE, + NodeTypeId::CharacterData(CharacterDataTypeId::Text) => + NodeConstants::TEXT_NODE, + NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => + NodeConstants::PROCESSING_INSTRUCTION_NODE, + NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => + NodeConstants::COMMENT_NODE, + NodeTypeId::Document => + NodeConstants::DOCUMENT_NODE, + NodeTypeId::DocumentType => + NodeConstants::DOCUMENT_TYPE_NODE, + NodeTypeId::DocumentFragment => + NodeConstants::DOCUMENT_FRAGMENT_NODE, + NodeTypeId::Element(_) => + NodeConstants::ELEMENT_NODE, } } @@ -2002,7 +2138,8 @@ impl<'a> NodeMethods for JSRef<'a, Node> { // Step 4-5. match node.type_id() { - NodeTypeId::CharacterData(CharacterDataTypeId::Text) if self.is_document() => return Err(HierarchyRequest), + NodeTypeId::CharacterData(CharacterDataTypeId::Text) if self.is_document() => + return Err(HierarchyRequest), NodeTypeId::DocumentType if !self.is_document() => return Err(HierarchyRequest), NodeTypeId::DocumentFragment | NodeTypeId::DocumentType | @@ -2153,7 +2290,8 @@ impl<'a> NodeMethods for JSRef<'a, Node> { match prev_text { Some(ref text_node) => { let text_node = text_node.clone().root(); - let prev_characterdata: JSRef<CharacterData> = CharacterDataCast::from_ref(text_node.r()); + let prev_characterdata: JSRef<CharacterData> = + CharacterDataCast::from_ref(text_node.r()); let _ = prev_characterdata.AppendData(characterdata.Data()); self.remove_child(child.r()); }, @@ -2231,13 +2369,18 @@ impl<'a> NodeMethods for JSRef<'a, Node> { match node.type_id() { // Step 3. - NodeTypeId::DocumentType if !is_equal_doctype(this, node) => return false, - NodeTypeId::Element(..) if !is_equal_element(this, node) => return false, - NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) if !is_equal_processinginstruction(this, node) => return false, + NodeTypeId::DocumentType + if !is_equal_doctype(this, node) => return false, + NodeTypeId::Element(..) + if !is_equal_element(this, node) => return false, + NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) + if !is_equal_processinginstruction(this, node) => return false, NodeTypeId::CharacterData(CharacterDataTypeId::Text) | - NodeTypeId::CharacterData(CharacterDataTypeId::Comment) if !is_equal_characterdata(this, node) => return false, + NodeTypeId::CharacterData(CharacterDataTypeId::Comment) + if !is_equal_characterdata(this, node) => return false, // Step 4. - NodeTypeId::Element(..) if !is_equal_element_attrs(this, node) => return false, + NodeTypeId::Element(..) + if !is_equal_element_attrs(this, node) => return false, _ => () } |