diff --git a/src/components/main/layout/wrapper.rs b/src/components/main/layout/wrapper.rs index d779845c5b5..4aa10c3ba63 100644 --- a/src/components/main/layout/wrapper.rs +++ b/src/components/main/layout/wrapper.rs @@ -37,10 +37,11 @@ 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}; +use script::dom::element::{HTMLLinkElementTypeId, LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::htmliframeelement::HTMLIFrameElement; -use script::dom::htmlimageelement::HTMLImageElement; -use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId, LayoutNodeHelpers}; +use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; +use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId}; +use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers}; use script::dom::text::Text; use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_util::namespace; @@ -95,7 +96,7 @@ pub trait TLayoutNode { fail!("not an image!") } let image_element: JS = self.get_jsmanaged().transmute_copy(); - (*image_element.unsafe_get()).image().as_ref().map(|url| (*url).clone()) + image_element.image().as_ref().map(|url| (*url).clone()) } } @@ -163,7 +164,9 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> { } fn type_id(&self) -> Option { - Some(self.node.type_id_for_layout()) + unsafe { + Some(self.node.type_id_for_layout()) + } } unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS { @@ -172,7 +175,7 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> { fn first_child(&self) -> Option> { unsafe { - self.get().first_child_ref().map(|node| self.new_with_this_lifetime(node)) + self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(node)) } } @@ -221,19 +224,19 @@ impl<'ln> LayoutNode<'ln> { impl<'ln> TNode> for LayoutNode<'ln> { fn parent_node(&self) -> Option> { unsafe { - self.get().parent_node_ref().map(|node| self.new_with_this_lifetime(node)) + self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(node)) } } fn prev_sibling(&self) -> Option> { unsafe { - self.get().prev_sibling_ref().map(|node| self.new_with_this_lifetime(node)) + self.node.prev_sibling_ref().map(|node| self.new_with_this_lifetime(node)) } } fn next_sibling(&self) -> Option> { unsafe { - self.get().next_sibling_ref().map(|node| self.new_with_this_lifetime(node)) + self.node.next_sibling_ref().map(|node| self.new_with_this_lifetime(node)) } } @@ -241,6 +244,7 @@ impl<'ln> TNode> for LayoutNode<'ln> { #[inline] fn as_element(&self) -> LayoutElement<'ln> { unsafe { + assert!(self.node.is_element_for_layout()); let elem: JS = self.node.transmute_copy(); let element = &*elem.unsafe_get(); LayoutElement { @@ -258,9 +262,9 @@ impl<'ln> TNode> for LayoutNode<'ln> { } fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool { - let element = self.as_element(); let name = unsafe { - if element.element.html_element_in_html_document_for_layout() { + let element: JS = self.node.transmute_copy(); + if element.html_element_in_html_document_for_layout() { attr.lower_name.as_slice() } else { attr.name.as_slice() @@ -268,6 +272,7 @@ impl<'ln> TNode> for LayoutNode<'ln> { }; match attr.namespace { SpecificNamespace(ref ns) => { + let element = self.as_element(); element.get_attr(ns, name) .map_or(false, |attr| test(attr)) }, @@ -459,7 +464,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { } unsafe { - self.get().first_child_ref().map(|node| self.new_with_this_lifetime(node)) + self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(node)) } } @@ -509,10 +514,10 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { /// Returns the next sibling of this node. Unsafe and private because this can lead to races. unsafe fn next_sibling(&self) -> Option> { if self.pseudo == Before || self.pseudo == BeforeBlock { - return (*self.get_jsmanaged().unsafe_get()).first_child_ref().map(|node| self.new_with_this_lifetime(node)) + return self.get_jsmanaged().first_child_ref().map(|node| self.new_with_this_lifetime(node)) } - (*self.get_jsmanaged().unsafe_get()).next_sibling_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. @@ -527,7 +532,8 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { #[inline] pub fn as_element(&self) -> ThreadSafeLayoutElement { unsafe { - let elem: JS = self.node.get_jsmanaged().transmute_copy(); + assert!(self.get_jsmanaged().is_element_for_layout()); + let elem: JS = self.get_jsmanaged().transmute_copy(); let element = elem.unsafe_get(); // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // implementations. diff --git a/src/components/script/dom/document.rs b/src/components/script/dom/document.rs index e9f237999a7..24c1d6eae89 100644 --- a/src/components/script/dom/document.rs +++ b/src/components/script/dom/document.rs @@ -76,8 +76,115 @@ impl DocumentDerived for EventTarget { } } +pub trait DocumentHelpers { + fn url<'a>(&'a self) -> &'a Url; + fn quirks_mode(&self) -> QuirksMode; + fn set_quirks_mode(&mut self, mode: QuirksMode); + fn set_encoding_name(&mut self, name: DOMString); + fn content_changed(&self); + fn damage_and_reflow(&self, damage: DocumentDamageLevel); + fn wait_until_safe_to_modify_dom(&self); + fn unregister_named_element(&mut self, to_unregister: &JSRef, id: DOMString); + fn register_named_element(&mut self, element: &JSRef, id: DOMString); +} + +impl<'a> DocumentHelpers for JSRef<'a, Document> { + fn url<'a>(&'a self) -> &'a Url { + &*self.url + } + + fn quirks_mode(&self) -> QuirksMode { + *self.quirks_mode + } + + fn set_quirks_mode(&mut self, mode: QuirksMode) { + *self.quirks_mode = mode; + } + + fn set_encoding_name(&mut self, name: DOMString) { + self.encoding_name = name; + } + + fn content_changed(&self) { + self.damage_and_reflow(ContentChangedDocumentDamage); + } + + fn damage_and_reflow(&self, damage: DocumentDamageLevel) { + let roots = RootCollection::new(); + self.window.root(&roots).damage_and_reflow(damage); + } + + fn wait_until_safe_to_modify_dom(&self) { + let roots = RootCollection::new(); + self.window.root(&roots).wait_until_safe_to_modify_dom(); + } + + + /// Remove any existing association between the provided id and any elements in this document. + fn unregister_named_element(&mut self, + to_unregister: &JSRef, + id: DOMString) { + let roots = RootCollection::new(); + let mut is_empty = false; + match self.idmap.find_mut(&id) { + None => {}, + Some(elements) => { + let position = elements.iter() + .map(|elem| elem.root(&roots)) + .position(|element| &*element == to_unregister) + .expect("This element should be in registered."); + elements.remove(position); + is_empty = elements.is_empty(); + } + } + if is_empty { + self.idmap.remove(&id); + } + } + + /// Associate an element present in this document with the provided id. + fn register_named_element(&mut self, + element: &JSRef, + id: DOMString) { + let roots = RootCollection::new(); + assert!({ + let node: &JSRef = NodeCast::from_ref(element); + node.is_in_doc() + }); + + // FIXME https://github.com/mozilla/rust/issues/13195 + // Use mangle() when it exists again. + let root = self.GetDocumentElement().expect("The element is in the document, so there must be a document element.").root(&roots); + match self.idmap.find_mut(&id) { + Some(elements) => { + let new_node: &JSRef = NodeCast::from_ref(element); + let mut head : uint = 0u; + let root: &JSRef = NodeCast::from_ref(&*root); + for node in root.traverse_preorder(&roots) { + let elem: Option<&JSRef> = ElementCast::to_ref(&node); + match elem { + Some(elem) => { + if elements.get(head) == &elem.unrooted() { + head = head + 1; + } + if new_node == &node || head == elements.len() { + break; + } + } + None => {} + } + } + elements.insert(head, element.unrooted()); + return; + }, + None => (), + } + self.idmap.insert(id, vec!(element.unrooted())); + } +} + impl Document { - pub fn reflect_document(document: ~Document, + pub fn reflect_document(document: ~Document, window: &JSRef, wrap_fn: extern "Rust" fn(*JSContext, &JSRef, ~Document) -> JS) -> Unrooted { @@ -88,7 +195,7 @@ impl Document { let mut doc_alias = raw_doc.clone(); let node: &mut JSRef = NodeCast::from_mut_ref(&mut doc_alias); - node.get_mut().set_owner_doc(&*raw_doc); + node.set_owner_doc(&*raw_doc); Unrooted::new_rooted(&*raw_doc) } @@ -131,100 +238,6 @@ impl Document { let document = Document::new_inherited(window.unrooted(), url, doctype, content_type); Document::reflect_document(~document, window, DocumentBinding::Wrap) } - - pub fn url<'a>(&'a self) -> &'a Url { - &*self.url - } - - pub fn quirks_mode(&self) -> QuirksMode { - *self.quirks_mode - } - - pub fn set_quirks_mode(&mut self, mode: QuirksMode) { - *self.quirks_mode = mode; - } - - pub fn set_encoding_name(&mut self, name: DOMString) { - self.encoding_name = name; - } - - pub fn content_changed(&self) { - self.damage_and_reflow(ContentChangedDocumentDamage); - } - - pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) { - let roots = RootCollection::new(); - self.window.root(&roots).damage_and_reflow(damage); - } - - pub fn wait_until_safe_to_modify_dom(&self) { - let roots = RootCollection::new(); - self.window.root(&roots).wait_until_safe_to_modify_dom(); - } - - - /// Remove any existing association between the provided id and any elements in this document. - pub fn unregister_named_element(&mut self, - to_unregister: &JSRef, - id: DOMString) { - let roots = RootCollection::new(); - let mut is_empty = false; - match self.idmap.find_mut(&id) { - None => {}, - Some(elements) => { - let position = elements.iter() - .map(|elem| elem.root(&roots)) - .position(|element| &*element == to_unregister) - .expect("This element should be in registered."); - elements.remove(position); - is_empty = elements.is_empty(); - } - } - if is_empty { - self.idmap.remove(&id); - } - } - - /// Associate an element present in this document with the provided id. - pub fn register_named_element(&mut self, - abstract_self: &JSRef, - element: &JSRef, - id: DOMString) { - let roots = RootCollection::new(); - assert!({ - let node: &JSRef = NodeCast::from_ref(element); - node.is_in_doc() - }); - - // FIXME https://github.com/mozilla/rust/issues/13195 - // Use mangle() when it exists again. - let root = abstract_self.GetDocumentElement().expect("The element is in the document, so there must be a document element.").root(&roots); - match self.idmap.find_mut(&id) { - Some(elements) => { - let new_node: &JSRef = NodeCast::from_ref(element); - let mut head : uint = 0u; - let root: &JSRef = NodeCast::from_ref(&*root); - for node in root.traverse_preorder(&roots) { - let elem: Option<&JSRef> = ElementCast::to_ref(&node); - match elem { - Some(elem) => { - if elements.get(head) == &elem.unrooted() { - head = head + 1; - } - if new_node == &node || head == elements.len() { - break; - } - } - None => {} - } - } - elements.insert(head, element.unrooted()); - return; - }, - None => (), - } - self.idmap.insert(id, vec!(element.unrooted())); - } } impl Reflectable for Document { @@ -237,12 +250,12 @@ impl Reflectable for Document { } } -trait DocumentHelpers { +trait PrivateDocumentHelpers { fn createNodeList(&self, callback: |node: &JSRef| -> bool) -> Unrooted; fn get_html_element(&self) -> Option>; } -impl<'a> DocumentHelpers for JSRef<'a, Document> { +impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> { fn createNodeList(&self, callback: |node: &JSRef| -> bool) -> Unrooted { let roots = RootCollection::new(); let window = self.window.root(&roots); @@ -354,7 +367,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { // http://dom.spec.whatwg.org/#dom-document-doctype fn GetDoctype(&self) -> Option> { - self.node.children().find(|child| { + let node: &JSRef = NodeCast::from_ref(self); + node.children().find(|child| { child.is_doctype() }).map(|node| { let doctype: &JSRef = DocumentTypeCast::to_ref(&node).unwrap(); @@ -364,7 +378,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { // http://dom.spec.whatwg.org/#dom-document-documentelement fn GetDocumentElement(&self) -> Option> { - self.node.child_elements().next().map(|elem| Unrooted::new_rooted(&elem)) + let node: &JSRef = NodeCast::from_ref(self); + node.child_elements().next().map(|elem| Unrooted::new_rooted(&elem)) } // http://dom.spec.whatwg.org/#dom-document-getelementsbytagname @@ -544,7 +559,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { root.traverse_preorder(&roots) .find(|node| node.type_id() == ElementNodeTypeId(HTMLTitleElementTypeId)) .map(|title_elem| { - for child in title_elem.deref().children() { + for child in title_elem.children() { if child.is_text() { let text: &JSRef = TextCast::to_ref(&child).unwrap(); title.push_str(text.get().characterdata.data.as_slice()); @@ -633,8 +648,9 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { // Step 1. match new_body { - Some(ref node) => { - match node.get().element.node.type_id { + Some(ref htmlelem) => { + let node: &JSRef = NodeCast::from_ref(htmlelem); + match node.type_id() { ElementNodeTypeId(HTMLBodyElementTypeId) | ElementNodeTypeId(HTMLFrameSetElementTypeId) => {} _ => return Err(HierarchyRequest) } @@ -676,7 +692,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { let roots = RootCollection::new(); self.createNodeList(|node| { - if !node.get().is_element() { + if !node.is_element() { return false; } diff --git a/src/components/script/dom/element.rs b/src/components/script/dom/element.rs index 200ed604777..9e8be904788 100644 --- a/src/components/script/dom/element.rs +++ b/src/components/script/dom/element.rs @@ -15,12 +15,12 @@ use dom::bindings::error::{ErrorResult, Fallible, NamespaceError, InvalidCharact use dom::bindings::utils::{QName, Name, InvalidXMLName, xml_name_type}; use dom::clientrect::ClientRect; use dom::clientrectlist::ClientRectList; -use dom::document::Document; +use dom::document::{Document, DocumentHelpers}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlcollection::HTMLCollection; use dom::htmlserializer::serialize; use dom::node::{ElementNodeTypeId, Node, NodeHelpers, NodeIterator, document_from_node}; -use dom::node::window_from_node; +use dom::node::{window_from_node, LayoutNodeHelpers}; use dom::virtualmethods::{VirtualMethods, vtable_for}; use layout_interface::ContentChangedDocumentDamage; use layout_interface::MatchSelectorsDocumentDamage; @@ -157,36 +157,51 @@ impl Element { let element = Element::new_inherited(ElementTypeId, local_name, namespace, prefix, document.unrooted()); Node::reflect_node(~element, document, ElementBinding::Wrap) } +} - pub fn html_element_in_html_document(&self) -> bool { - let roots = RootCollection::new(); - self.namespace == namespace::HTML && - self.node.owner_doc().root(&roots).is_html_document +pub trait RawLayoutElementHelpers { + unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) -> Option<&'static str>; +} + +impl RawLayoutElementHelpers for Element { + #[inline] + unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) + -> Option<&'static str> { + self.attrs.iter().find(|attr: & &JS| { + let attr = attr.unsafe_get(); + name == (*attr).local_name && (*attr).namespace == *namespace + }).map(|attr| { + let attr = attr.unsafe_get(); + cast::transmute((*attr).value.as_slice()) + }) } } -impl Element { - pub unsafe fn html_element_in_html_document_for_layout(&self) -> bool { - if self.namespace != namespace::HTML { +pub trait LayoutElementHelpers { + unsafe fn html_element_in_html_document_for_layout(&self) -> bool; +} + +impl LayoutElementHelpers for JS { + unsafe fn html_element_in_html_document_for_layout(&self) -> bool { + if (*self.unsafe_get()).namespace != namespace::HTML { return false } - let owner_doc: *JS = self.node.owner_doc_for_layout(); - let owner_doc: **Document = owner_doc as **Document; - (**owner_doc).is_html_document + let node: JS = self.transmute_copy(); + let owner_doc = node.owner_doc_for_layout().unsafe_get(); + (*owner_doc).is_html_document } +} - #[inline] - pub unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) - -> Option<&'static str> { - self.attrs.iter().find(|attr: & &JS| { - // unsafely avoid a borrow because this is accessed by many tasks - // during parallel layout - let attr: ***Attr = cast::transmute(attr); - name == (***attr).local_name && (***attr).namespace == *namespace - }).map(|attr| { - let attr: **Attr = cast::transmute(attr); - cast::transmute((**attr).value.as_slice()) - }) +pub trait ElementHelpers { + fn html_element_in_html_document(&self) -> bool; +} + +impl<'a> ElementHelpers for JSRef<'a, Element> { + fn html_element_in_html_document(&self) -> bool { + let roots = RootCollection::new(); + let is_html = self.namespace == namespace::HTML; + let node: &JSRef = NodeCast::from_ref(self); + is_html && node.owner_doc().root(&roots).is_html_document } } @@ -214,7 +229,7 @@ pub trait AttributeHandlers { impl<'a> AttributeHandlers for JSRef<'a, Element> { fn get_attribute(&self, namespace: Namespace, name: &str) -> Option> { let roots = RootCollection::new(); - if self.get().html_element_in_html_document() { + if self.html_element_in_html_document() { self.get().attrs.iter().map(|attr| attr.root(&roots)).find(|attr| { name.to_ascii_lower() == attr.local_name && attr.namespace == namespace }).map(|x| Unrooted::new_rooted(&*x)) @@ -248,7 +263,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> { node.wait_until_safe_to_modify_dom(); let position: |&JSRef| -> bool = - if self.get().html_element_in_html_document() { + if self.html_element_in_html_document() { |attr| attr.get().local_name.eq_ignore_ascii_case(local_name) } else { |attr| attr.get().local_name == local_name @@ -453,7 +468,10 @@ impl<'a> ElementMethods for JSRef<'a, Element> { Some(ref list) => return Unrooted::new(list.clone()), } - let doc = self.node.owner_doc().root(&roots); + let doc = { + let node: &JSRef = NodeCast::from_ref(self); + node.owner_doc() + }.root(&roots); let window = doc.deref().window.root(&roots); let list = AttrList::new(&*window, self); self.attr_list.assign(Some(list)); @@ -463,7 +481,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-getattribute fn GetAttribute(&self, name: DOMString) -> Option { let roots = RootCollection::new(); - let name = if self.get().html_element_in_html_document() { + let name = if self.html_element_in_html_document() { name.to_ascii_lower() } else { name @@ -488,7 +506,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { value: DOMString) -> ErrorResult { { let node: &JSRef = NodeCast::from_ref(self); - node.get().wait_until_safe_to_modify_dom(); + node.wait_until_safe_to_modify_dom(); } // Step 1. @@ -498,7 +516,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { } // Step 2. - let name = if self.get().html_element_in_html_document() { + let name = if self.html_element_in_html_document() { name.to_ascii_lower() } else { name @@ -518,7 +536,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { value: DOMString) -> ErrorResult { { let node: &JSRef = NodeCast::from_ref(self); - node.get().wait_until_safe_to_modify_dom(); + node.wait_until_safe_to_modify_dom(); } // Step 1. @@ -707,15 +725,14 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { match name.as_slice() { "style" => { let doc = document_from_node(self).root(&roots); - let base_url = doc.get().url().clone(); + let base_url = doc.deref().url().clone(); self.get_mut().style_attribute = Some(style::parse_style_attribute(value, &base_url)) } "id" => { let node: &JSRef = NodeCast::from_ref(self); if node.is_in_doc() { let mut doc = document_from_node(self).root(&roots); - let doc_alias = (*doc).clone(); - doc.register_named_element(&doc_alias, self, value.clone()); + doc.register_named_element(self, value.clone()); } } _ => () @@ -758,8 +775,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { match self.get_attribute(Null, "id").root(&roots) { Some(attr) => { let mut doc = document_from_node(self).root(&roots); - let doc_alias = (*doc).clone(); - doc.register_named_element(&doc_alias, self, attr.deref().Value()); + doc.register_named_element(self, attr.deref().Value()); } _ => () } diff --git a/src/components/script/dom/htmlbuttonelement.rs b/src/components/script/dom/htmlbuttonelement.rs index 2b2b04aca35..f37d9926032 100644 --- a/src/components/script/dom/htmlbuttonelement.rs +++ b/src/components/script/dom/htmlbuttonelement.rs @@ -11,7 +11,7 @@ use dom::element::HTMLButtonElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlformelement::HTMLFormElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::validitystate::ValidityState; use servo_util::str::DOMString; @@ -168,8 +168,8 @@ impl<'a> HTMLButtonElementMethods for JSRef<'a, HTMLButtonElement> { fn Validity(&self) -> Unrooted { let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - ValidityState::new(&*doc.deref().window.root(&roots)) + let window = window_from_node(self).root(&roots); + ValidityState::new(&*window) } fn SetValidity(&mut self, _validity: JS) { diff --git a/src/components/script/dom/htmlfieldsetelement.rs b/src/components/script/dom/htmlfieldsetelement.rs index ef42eb59990..8da6d36b803 100644 --- a/src/components/script/dom/htmlfieldsetelement.rs +++ b/src/components/script/dom/htmlfieldsetelement.rs @@ -107,8 +107,7 @@ impl<'a> HTMLFieldSetElementMethods for JSRef<'a, HTMLFieldSetElement> { fn Validity(&self) -> Unrooted { let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); + let window = window_from_node(self).root(&roots); ValidityState::new(&*window) } diff --git a/src/components/script/dom/htmlformelement.rs b/src/components/script/dom/htmlformelement.rs index f045c1437c3..d69cbcf3a48 100644 --- a/src/components/script/dom/htmlformelement.rs +++ b/src/components/script/dom/htmlformelement.rs @@ -11,7 +11,7 @@ use dom::element::{Element, HTMLFormElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlcollection::{HTMLCollection, Static}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use servo_util::str::DOMString; #[deriving(Encodable)] @@ -144,8 +144,7 @@ impl<'a> HTMLFormElementMethods for JSRef<'a, HTMLFormElement> { fn Elements(&self) -> Unrooted { // FIXME: https://github.com/mozilla/servo/issues/1844 let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); + let window = window_from_node(self).root(&roots); HTMLCollection::new(&*window, Static(vec!())) } diff --git a/src/components/script/dom/htmliframeelement.rs b/src/components/script/dom/htmliframeelement.rs index ee675390183..aa6fc3ceaf3 100644 --- a/src/components/script/dom/htmliframeelement.rs +++ b/src/components/script/dom/htmliframeelement.rs @@ -54,12 +54,17 @@ pub struct IFrameSize { pub subpage_id: SubpageId, } -impl HTMLIFrameElement { - pub fn is_sandboxed(&self) -> bool { +pub trait HTMLIFrameElementHelpers { + fn is_sandboxed(&self) -> bool; + fn set_frame(&mut self, frame: Url); +} + +impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> { + fn is_sandboxed(&self) -> bool { self.sandbox.is_some() } - pub fn set_frame(&mut self, frame: Url) { + fn set_frame(&mut self, frame: Url) { *self.frame = Some(frame); } } diff --git a/src/components/script/dom/htmlimageelement.rs b/src/components/script/dom/htmlimageelement.rs index 39c854c1c05..423f49a8f14 100644 --- a/src/components/script/dom/htmlimageelement.rs +++ b/src/components/script/dom/htmlimageelement.rs @@ -35,29 +35,18 @@ impl HTMLImageElementDerived for EventTarget { } } -impl HTMLImageElement { - pub fn new_inherited(localName: DOMString, document: JS) -> HTMLImageElement { - HTMLImageElement { - htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document), - image: Untraceable::new(None), - } - } - - pub fn new(localName: DOMString, document: &JSRef) -> Unrooted { - let element = HTMLImageElement::new_inherited(localName, document.unrooted()); - Node::reflect_node(~element, document, HTMLImageElementBinding::Wrap) - } - - pub fn image<'a>(&'a self) -> &'a Option { - &*self.image - } +trait PrivateHTMLImageElementHelpers { + fn update_image(&mut self, value: Option, url: Option); +} +impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { /// Makes the local `image` member match the status of the `src` attribute and starts /// prefetching the image. This method must be called after `src` is changed. fn update_image(&mut self, value: Option, url: Option) { let roots = RootCollection::new(); - let elem = &mut self.htmlelement.element; - let document = elem.node.owner_doc().root(&roots); + let self_alias = self.clone(); + let node_alias: &JSRef = NodeCast::from_ref(&self_alias); + let document = node_alias.owner_doc().root(&roots); let window = document.deref().window.root(&roots); let image_cache = &window.image_cache_task; match value { @@ -79,6 +68,30 @@ impl HTMLImageElement { } } +impl HTMLImageElement { + pub fn new_inherited(localName: DOMString, document: JS) -> HTMLImageElement { + HTMLImageElement { + htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document), + image: Untraceable::new(None), + } + } + + pub fn new(localName: DOMString, document: &JSRef) -> Unrooted { + let element = HTMLImageElement::new_inherited(localName, document.unrooted()); + Node::reflect_node(~element, document, HTMLImageElementBinding::Wrap) + } +} + +pub trait LayoutHTMLImageElementHelpers { + unsafe fn image<'a>(&'a self) -> &'a Option; +} + +impl LayoutHTMLImageElementHelpers for JS { + unsafe fn image<'a>(&'a self) -> &'a Option { + &*(*self.unsafe_get()).image + } +} + pub trait HTMLImageElementMethods { fn Alt(&self) -> DOMString; fn SetAlt(&mut self, alt: DOMString); @@ -271,7 +284,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLImageElement> { if "src" == name { let window = window_from_node(self).root(&roots); let url = Some(window.get().get_url()); - self.get_mut().update_image(Some(value), url); + self.update_image(Some(value), url); } } @@ -282,7 +295,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLImageElement> { } if "src" == name { - self.get_mut().update_image(None, None); + self.update_image(None, None); } } } diff --git a/src/components/script/dom/htmlmapelement.rs b/src/components/script/dom/htmlmapelement.rs index dbc55463351..7c6e4b59151 100644 --- a/src/components/script/dom/htmlmapelement.rs +++ b/src/components/script/dom/htmlmapelement.rs @@ -11,7 +11,7 @@ use dom::element::HTMLMapElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlcollection::{HTMLCollection, Static}; use dom::htmlelement::HTMLElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use servo_util::str::DOMString; #[deriving(Encodable)] @@ -59,8 +59,7 @@ impl<'a> HTMLMapElementMethods for JSRef<'a, HTMLMapElement> { fn Areas(&self) -> Unrooted { let roots = RootCollection::new(); // FIXME: https://github.com/mozilla/servo/issues/1845 - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); + let window = window_from_node(self).root(&roots); HTMLCollection::new(&*window, Static(vec!())) } } diff --git a/src/components/script/dom/htmlobjectelement.rs b/src/components/script/dom/htmlobjectelement.rs index 7fcc3c0a5da..085bd492b11 100644 --- a/src/components/script/dom/htmlobjectelement.rs +++ b/src/components/script/dom/htmlobjectelement.rs @@ -191,9 +191,8 @@ impl<'a> HTMLObjectElementMethods for JSRef<'a, HTMLObjectElement> { fn Validity(&self) -> Unrooted { let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); - ValidityState::new(&window.root_ref()) + let window = window_from_node(self).root(&roots); + ValidityState::new(&*window) } fn ValidationMessage(&self) -> DOMString { diff --git a/src/components/script/dom/htmloutputelement.rs b/src/components/script/dom/htmloutputelement.rs index c7262b23de0..605bb2eeab2 100644 --- a/src/components/script/dom/htmloutputelement.rs +++ b/src/components/script/dom/htmloutputelement.rs @@ -11,7 +11,7 @@ use dom::element::HTMLOutputElementTypeId; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlformelement::HTMLFormElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::validitystate::ValidityState; use servo_util::str::DOMString; @@ -103,8 +103,7 @@ impl<'a> HTMLOutputElementMethods for JSRef<'a, HTMLOutputElement> { fn Validity(&self) -> Unrooted { let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); + let window = window_from_node(self).root(&roots); ValidityState::new(&*window) } diff --git a/src/components/script/dom/htmlselectelement.rs b/src/components/script/dom/htmlselectelement.rs index 6aa15a1e982..ed99506f01d 100644 --- a/src/components/script/dom/htmlselectelement.rs +++ b/src/components/script/dom/htmlselectelement.rs @@ -12,7 +12,7 @@ use dom::element::{Element, HTMLSelectElementTypeId}; use dom::eventtarget::{EventTarget, NodeTargetTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlformelement::HTMLFormElement; -use dom::node::{Node, ElementNodeTypeId}; +use dom::node::{Node, ElementNodeTypeId, window_from_node}; use dom::htmloptionelement::HTMLOptionElement; use dom::validitystate::ValidityState; use servo_util::str::DOMString; @@ -193,8 +193,7 @@ impl<'a> HTMLSelectElementMethods for JSRef<'a, HTMLSelectElement> { fn Validity(&self) -> Unrooted { let roots = RootCollection::new(); - let doc = self.htmlelement.element.node.owner_doc().root(&roots); - let window = doc.deref().window.root(&roots); + let window = window_from_node(self).root(&roots); ValidityState::new(&*window) } diff --git a/src/components/script/dom/node.rs b/src/components/script/dom/node.rs index aa444865bdb..99daa05e1a5 100644 --- a/src/components/script/dom/node.rs +++ b/src/components/script/dom/node.rs @@ -6,7 +6,7 @@ use dom::attr::Attr; use dom::bindings::codegen::InheritTypes::{CommentCast, DocumentCast, DocumentTypeCast}; -use dom::bindings::codegen::InheritTypes::{ElementCast, TextCast, NodeCast}; +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::BindingDeclarations::NodeBinding::NodeConstants; @@ -18,7 +18,7 @@ use dom::bindings::error::{ErrorResult, Fallible, NotFound, HierarchyRequest}; use dom::bindings::utils; use dom::characterdata::{CharacterData, CharacterDataMethods}; use dom::comment::Comment; -use dom::document::{Document, DocumentMethods, HTMLDocument, NonHTMLDocument}; +use dom::document::{Document, DocumentMethods, DocumentHelpers, HTMLDocument, NonHTMLDocument}; use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::element::{Element, ElementMethods, ElementTypeId, HTMLAnchorElementTypeId}; @@ -224,6 +224,174 @@ pub enum NodeTypeId { ProcessingInstructionNodeTypeId, } +trait PrivateNodeHelpers { + fn set_parent_node(&mut self, new_parent_node: Option>); + fn set_first_child(&mut self, new_first_child: Option>); + fn set_last_child(&mut self, new_last_child: Option>); + fn set_prev_sibling(&mut self, new_prev_sibling: Option>); + fn set_next_sibling(&mut self, new_next_sibling: Option>); + + fn node_inserted(&self); + fn node_removed(&self); + fn add_child(&mut self, new_child: &mut JSRef, before: Option>); + fn remove_child(&mut self, child: &mut JSRef); +} + +impl<'a> PrivateNodeHelpers for JSRef<'a, Node> { + // http://dom.spec.whatwg.org/#node-is-inserted + fn node_inserted(&self) { + let roots = RootCollection::new(); + assert!(self.parent_node().is_some()); + let document = document_from_node(self).root(&roots); + + if self.is_in_doc() { + for node in self.traverse_preorder(&roots) { + vtable_for(&node).bind_to_tree(); + } + } + + self.parent_node().root(&roots) + .map(|parent| vtable_for(&*parent).child_inserted(self)); + + document.deref().content_changed(); + } + + // http://dom.spec.whatwg.org/#node-is-removed + fn node_removed(&self) { + let roots = RootCollection::new(); + assert!(self.parent_node().is_none()); + let document = document_from_node(self).root(&roots); + + for node in self.traverse_preorder(&roots) { + // XXX how about if the node wasn't in the tree in the first place? + vtable_for(&node).unbind_from_tree(); + } + + 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(&mut self, new_child: &mut JSRef, mut before: Option>) { + let roots = RootCollection::new(); + 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 mut before) => { + // XXX Should assert that parent is self. + assert!(before.parent_node().is_some()); + match before.prev_sibling() { + None => { + // XXX Should assert that before is the first child of + // self. + self.set_first_child(Some(new_child.clone())); + }, + Some(prev_sibling) => { + let mut prev_sibling = prev_sibling.root(&roots); + prev_sibling.set_next_sibling(Some(new_child.clone())); + new_child.set_prev_sibling(Some((*prev_sibling).clone())); + }, + } + before.set_prev_sibling(Some(new_child.clone())); + new_child.set_next_sibling(Some(before.clone())); + }, + None => { + match self.last_child().map(|child| child.root(&roots)) { + None => self.set_first_child(Some(new_child.clone())), + Some(mut last_child) => { + assert!(last_child.next_sibling().is_none()); + last_child.set_next_sibling(Some(new_child.clone())); + new_child.set_prev_sibling(Some((*last_child).clone())); + } + } + + self.set_last_child(Some(new_child.clone())); + }, + } + + new_child.set_parent_node(Some(self.clone())); + } + + /// Removes the given child from this node's list of children. + /// + /// Fails unless `child` is a child of this node. (FIXME: This is not yet checked.) + fn remove_child(&mut self, child: &mut JSRef) { + let roots = RootCollection::new(); + assert!(child.parent_node.is_some()); + + match child.prev_sibling.root(&roots) { + None => { + let next_sibling = child.next_sibling.as_ref().map(|next| next.root(&roots)); + self.set_first_child(next_sibling.root_ref()); + } + Some(ref mut prev_sibling) => { + let next_sibling = child.next_sibling.as_ref().map(|next| next.root(&roots)); + prev_sibling.set_next_sibling(next_sibling.root_ref()); + } + } + + match child.next_sibling.root(&roots) { + None => { + let prev_sibling = child.prev_sibling.as_ref().map(|prev| prev.root(&roots)); + self.set_last_child(prev_sibling.root_ref()); + } + Some(ref mut next_sibling) => { + let prev_sibling = child.prev_sibling.as_ref().map(|prev| prev.root(&roots)); + next_sibling.set_prev_sibling(prev_sibling.root_ref()); + } + } + + child.set_prev_sibling(None); + child.set_next_sibling(None); + child.set_parent_node(None); + } + + // + // Low-level pointer stitching + // + + fn set_parent_node(&mut self, new_parent_node: Option>) { + let roots = RootCollection::new(); + let doc = self.owner_doc().root(&roots); + doc.deref().wait_until_safe_to_modify_dom(); + self.parent_node.assign(new_parent_node); + } + + fn set_first_child(&mut self, new_first_child: Option>) { + let roots = RootCollection::new(); + let doc = self.owner_doc().root(&roots); + doc.deref().wait_until_safe_to_modify_dom(); + self.first_child.assign(new_first_child); + } + + fn set_last_child(&mut self, new_last_child: Option>) { + let roots = RootCollection::new(); + let doc = self.owner_doc().root(&roots); + doc.deref().wait_until_safe_to_modify_dom(); + self.last_child.assign(new_last_child); + } + + fn set_prev_sibling(&mut self, new_prev_sibling: Option>) { + let roots = RootCollection::new(); + let doc = self.owner_doc().root(&roots); + doc.deref().wait_until_safe_to_modify_dom(); + self.prev_sibling.assign(new_prev_sibling); + } + + fn set_next_sibling(&mut self, new_next_sibling: Option>) { + let roots = RootCollection::new(); + let doc = self.owner_doc().root(&roots); + doc.deref().wait_until_safe_to_modify_dom(); + self.next_sibling.assign(new_next_sibling); + } +} + pub trait NodeHelpers { fn ancestors(&self) -> AncestorIterator; fn children(&self) -> AbstractNodeChildrenIterator; @@ -241,17 +409,17 @@ pub trait NodeHelpers { fn prev_sibling(&self) -> Option>; fn next_sibling(&self) -> Option>; + fn owner_doc(&self) -> Unrooted; + fn set_owner_doc(&mut self, document: &JSRef); + + 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 node_inserted(&self); - fn node_removed(&self); - fn add_child(&mut self, new_child: &mut JSRef, before: Option>); - fn remove_child(&mut self, child: &mut JSRef); - fn get_hover_state(&self) -> bool; fn set_hover_state(&mut self, state: bool); @@ -296,19 +464,6 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { format!("{:?}", self.type_id()) } - /// Iterates over all ancestors of this node. - fn ancestors(&self) -> AncestorIterator { - self.get().ancestors() - } - - fn children(&self) -> AbstractNodeChildrenIterator { - self.get().children() - } - - fn child_elements(&self) -> ChildElementIterator { - self.get().child_elements() - } - fn is_in_doc(&self) -> bool { self.get().flags.is_in_doc() } @@ -342,7 +497,10 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { #[inline] fn is_element(&self) -> bool { - self.get().is_element() + match self.type_id { + ElementNodeTypeId(..) => true, + _ => false + } } #[inline] @@ -363,7 +521,10 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { #[inline] fn is_doctype(&self) -> bool { - self.get().is_doctype() + match self.type_id { + DoctypeNodeTypeId => true, + _ => false + } } #[inline] @@ -376,127 +537,12 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { } } - // http://dom.spec.whatwg.org/#node-is-inserted - fn node_inserted(&self) { - let roots = RootCollection::new(); - assert!(self.parent_node().is_some()); - let document = document_from_node(self).root(&roots); - - if self.is_in_doc() { - for node in self.traverse_preorder(&roots) { - vtable_for(&node).bind_to_tree(); - } - } - - self.parent_node().root(&roots) - .map(|parent| vtable_for(&*parent).child_inserted(self)); - document.get().content_changed(); - } - - // http://dom.spec.whatwg.org/#node-is-removed - fn node_removed(&self) { - let roots = RootCollection::new(); - assert!(self.parent_node().is_none()); - let document = document_from_node(self).root(&roots); - - for node in self.traverse_preorder(&roots) { - // XXX how about if the node wasn't in the tree in the first place? - vtable_for(&node).unbind_from_tree(); - } - - document.get().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(&mut self, new_child: &mut JSRef, mut before: Option>) { - let roots = RootCollection::new(); - 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 mut before) => { - // XXX Should assert that parent is self. - assert!(before.parent_node().is_some()); - match before.prev_sibling() { - None => { - // XXX Should assert that before is the first child of - // self. - self.get_mut().set_first_child(Some(new_child.clone())); - }, - Some(prev_sibling) => { - let mut prev_sibling = prev_sibling.root(&roots); - prev_sibling.get_mut().set_next_sibling(Some(new_child.clone())); - new_child.get_mut().set_prev_sibling(Some((*prev_sibling).clone())); - }, - } - before.get_mut().set_prev_sibling(Some(new_child.clone())); - new_child.get_mut().set_next_sibling(Some(before.clone())); - }, - None => { - match self.last_child().map(|child| child.root(&roots)) { - None => self.get_mut().set_first_child(Some(new_child.clone())), - Some(mut last_child) => { - assert!(last_child.next_sibling().is_none()); - last_child.get_mut().set_next_sibling(Some(new_child.clone())); - new_child.get_mut().set_prev_sibling(Some((*last_child).clone())); - } - } - - self.get_mut().set_last_child(Some(new_child.clone())); - }, - } - - new_child.get_mut().set_parent_node(Some(self.clone())); - } - - /// Removes the given child from this node's list of children. - /// - /// Fails unless `child` is a child of this node. (FIXME: This is not yet checked.) - fn remove_child(&mut self, child: &mut JSRef) { - let roots = RootCollection::new(); - let this_node = self.get_mut(); - let child_node = child.get_mut(); - assert!(child_node.parent_node.is_some()); - - match child_node.prev_sibling.root(&roots) { - None => { - let next_sibling = child_node.next_sibling.as_ref().map(|next| next.root(&roots)); - this_node.set_first_child(next_sibling.root_ref()); - } - Some(ref mut prev_sibling) => { - let next_sibling = child_node.next_sibling.as_ref().map(|next| next.root(&roots)); - prev_sibling.set_next_sibling(next_sibling.root_ref()); - } - } - - match child_node.next_sibling.root(&roots) { - None => { - let prev_sibling = child_node.prev_sibling.as_ref().map(|prev| prev.root(&roots)); - this_node.set_last_child(prev_sibling.root_ref()); - } - Some(ref mut next_sibling) => { - let prev_sibling = child_node.prev_sibling.as_ref().map(|prev| prev.root(&roots)); - next_sibling.set_prev_sibling(prev_sibling.root_ref()); - } - } - - child_node.set_prev_sibling(None); - child_node.set_next_sibling(None); - child_node.set_parent_node(None); - } - fn get_hover_state(&self) -> bool { - self.get().flags.get_in_hover_state() + self.flags.get_in_hover_state() } fn set_hover_state(&mut self, state: bool) { - self.get_mut().flags.set_is_in_hover_state(state); + self.flags.set_is_in_hover_state(state); } /// Iterates over this node and all its descendants, in preorder. @@ -563,6 +609,48 @@ impl<'a> NodeHelpers for JSRef<'a, Node> { let ContentBoxesResponse(rects) = page.query_layout(ContentBoxesQuery(addr, chan), port); rects } + + fn ancestors(&self) -> AncestorIterator { + let roots = RootCollection::new(); + AncestorIterator { + current: self.parent_node.clone().map(|node| (*node.root(&roots)).clone()), + roots: roots, + } + } + + fn owner_doc(&self) -> Unrooted { + Unrooted::new(self.owner_doc.get_ref().clone()) + } + + fn set_owner_doc(&mut self, document: &JSRef) { + self.owner_doc = Some(document.unrooted()); + } + + fn children(&self) -> AbstractNodeChildrenIterator { + let roots = RootCollection::new(); + AbstractNodeChildrenIterator { + current_node: self.first_child.clone().map(|node| (*node.root(&roots)).clone()), + roots: roots, + } + } + + fn child_elements(&self) -> ChildElementIterator { + self.children() + .filter(|node| { + node.is_element() + }) + .map(|node| { + let elem: &JSRef = ElementCast::to_ref(&node).unwrap(); + elem.clone() + }) + } + + fn wait_until_safe_to_modify_dom(&self) { + let roots = RootCollection::new(); + let document = self.owner_doc().root(&roots); + document.deref().wait_until_safe_to_modify_dom(); + } + } /// If the given untrusted node address represents a valid DOM node in the given runtime, @@ -582,19 +670,69 @@ pub fn from_untrusted_node_address(runtime: *JSRuntime, candidate: UntrustedNode } pub trait LayoutNodeHelpers { - fn type_id_for_layout(&self) -> NodeTypeId; + unsafe fn type_id_for_layout(&self) -> NodeTypeId; + + unsafe fn parent_node_ref<'a>(&'a self) -> Option<&'a JS>; + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS>; + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS>; + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS>; + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS>; + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS; + + unsafe fn is_element_for_layout(&self) -> bool; } impl LayoutNodeHelpers for JS { - fn type_id_for_layout(&self) -> NodeTypeId { - unsafe { - let node: **Node = cast::transmute::<*JS, - **Node>(self); - (**node).type_id - } + unsafe fn type_id_for_layout(&self) -> NodeTypeId { + (*self.unsafe_get()).type_id + } + + unsafe fn is_element_for_layout(&self) -> bool { + (*self.unsafe_get()).is_element() + } + + #[inline] + unsafe fn parent_node_ref<'a>(&'a self) -> Option<&'a JS> { + (*self.unsafe_get()).parent_node.as_ref() + } + + #[inline] + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS> { + (*self.unsafe_get()).first_child.as_ref() + } + + #[inline] + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS> { + (*self.unsafe_get()).last_child.as_ref() + } + + #[inline] + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS> { + (*self.unsafe_get()).prev_sibling.as_ref() + } + + #[inline] + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS> { + (*self.unsafe_get()).next_sibling.as_ref() + } + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS { + (*self.unsafe_get()).owner_doc.get_ref() } } +pub trait RawLayoutNodeHelpers { + unsafe fn get_hover_state_for_layout(&self) -> bool; +} + +impl RawLayoutNodeHelpers for Node { + unsafe fn get_hover_state_for_layout(&self) -> bool { + self.flags.get_in_hover_state() + } +} + + // // Iteration and traversal // @@ -689,7 +827,7 @@ impl<'a> NodeIterator<'a> { } fn next_child<'b>(&self, node: &JSRef<'b, Node>) -> Option> { - if !self.include_descendants_of_void && node.get().is_element() { + if !self.include_descendants_of_void && node.is_element() { let elem: &JSRef = ElementCast::to_ref(node).unwrap(); if elem.get().is_void() { None @@ -771,65 +909,6 @@ pub enum CloneChildrenFlag { fn as_uintptr(t: &T) -> uintptr_t { t as *T as uintptr_t } impl Node { - pub fn ancestors(&self) -> AncestorIterator { - let roots = RootCollection::new(); - AncestorIterator { - current: self.parent_node.clone().map(|node| (*node.root(&roots)).clone()), - roots: roots, - } - } - - pub fn is_element(&self) -> bool { - match self.type_id { - ElementNodeTypeId(..) => true, - _ => false - } - } - - pub fn is_doctype(&self) -> bool { - match self.type_id { - DoctypeNodeTypeId => true, - _ => false - } - } - - pub fn owner_doc(&self) -> Unrooted { - Unrooted::new(self.owner_doc.get_ref().clone()) - } - - pub fn owner_doc_for_layout<'a>(&'a self) -> &'a JS { - self.owner_doc.get_ref() - } - - pub fn set_owner_doc(&mut self, document: &JSRef) { - self.owner_doc = Some(document.unrooted()); - } - - pub fn children(&self) -> AbstractNodeChildrenIterator { - let roots = RootCollection::new(); - AbstractNodeChildrenIterator { - current_node: self.first_child.clone().map(|node| (*node.root(&roots)).clone()), - roots: roots, - } - } - - pub fn child_elements(&self) -> ChildElementIterator { - self.children() - .filter(|node| { - node.is_element() - }) - .map(|node| { - let elem: &JSRef = ElementCast::to_ref(&node).unwrap(); - elem.clone() - }) - } - - pub fn wait_until_safe_to_modify_dom(&self) { - let roots = RootCollection::new(); - let document = self.owner_doc().root(&roots); - document.get().wait_until_safe_to_modify_dom(); - } - pub fn reflect_node (node: ~N, document: &JSRef, @@ -873,21 +952,6 @@ impl Node { } } - /// Sends layout data, if any, back to the script task to be destroyed. - pub 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)) - }, - } - } - } - // http://dom.spec.whatwg.org/#concept-node-adopt pub fn adopt(node: &mut JSRef, document: &JSRef) { let roots = RootCollection::new(); @@ -903,7 +967,7 @@ impl Node { let node_doc = document_from_node(node).root(&roots); if &*node_doc != document { for mut descendant in node.traverse_preorder(&roots) { - descendant.get_mut().set_owner_doc(document); + descendant.set_owner_doc(document); } } @@ -976,7 +1040,7 @@ impl Node { } match child { Some(ref child) if child.inclusively_following_siblings() - .any(|child| child.deref().is_doctype()) => { + .any(|child| child.is_doctype()) => { return Err(HierarchyRequest); } _ => (), @@ -995,7 +1059,7 @@ impl Node { } match child { Some(ref child) if child.inclusively_following_siblings() - .any(|child| child.deref().is_doctype()) => { + .any(|child| child.is_doctype()) => { return Err(HierarchyRequest); } _ => (), @@ -1003,14 +1067,14 @@ impl Node { }, // Step 6.3 DoctypeNodeTypeId => { - if parent.children().any(|c| c.deref().is_doctype()) { + 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.deref().is_element()) { + .any(|c| c.is_element()) { return Err(HierarchyRequest); } }, @@ -1092,7 +1156,7 @@ impl Node { } // http://dom.spec.whatwg.org/#concept-node-replace-all - pub fn replace_all(mut node: Option>, parent: &mut JSRef) { + fn replace_all(mut node: Option>, parent: &mut JSRef) { let roots = RootCollection::new(); // Step 1. @@ -1178,7 +1242,7 @@ impl Node { // Step 1. let mut document = match maybe_doc { Some(doc) => doc.unrooted().root(&roots), - None => node.get().owner_doc().root(&roots) + None => node.owner_doc().root(&roots) }; // Step 2. @@ -1204,7 +1268,6 @@ impl Node { }, DocumentNodeTypeId => { let document: &JSRef = DocumentCast::to_ref(node).unwrap(); - let document = document.get(); let is_html_doc = match document.is_html_document { true => HTMLDocument, false => NonHTMLDocument @@ -1242,15 +1305,13 @@ impl Node { } else { document.unrooted().root(&roots) }; - assert!(&*copy.get().owner_doc().root(&roots) == &*document); + assert!(&*copy.owner_doc().root(&roots) == &*document); // Step 4 (some data already copied in step 2). match node.get().type_id { DocumentNodeTypeId => { let node_doc: &JSRef = DocumentCast::to_ref(node).unwrap(); - let node_doc = node_doc.get(); let copy_doc: &mut JSRef = DocumentCast::to_mut_ref(&mut *copy).unwrap(); - let copy_doc = copy_doc.get_mut(); copy_doc.set_encoding_name(node_doc.encoding_name.clone()); copy_doc.set_quirks_mode(node_doc.quirks_mode()); }, @@ -1281,7 +1342,7 @@ impl Node { // Step 6. if clone_children == CloneChildren { - for ref child in node.get().children() { + for ref child in node.children() { let mut child_copy = Node::clone(&*child, Some(&*document), clone_children).root(&roots); let _inserted_node = Node::pre_insert(&mut *child_copy, &mut *copy, None); } @@ -1291,81 +1352,19 @@ impl Node { Unrooted::new_rooted(&*copy) } - // - // Low-level pointer stitching - // - - pub fn set_parent_node(&mut self, new_parent_node: Option>) { - let roots = RootCollection::new(); - let doc = self.owner_doc().root(&roots); - doc.get().wait_until_safe_to_modify_dom(); - self.parent_node.assign(new_parent_node); - } - - pub fn set_first_child(&mut self, new_first_child: Option>) { - let roots = RootCollection::new(); - let doc = self.owner_doc().root(&roots); - doc.get().wait_until_safe_to_modify_dom(); - self.first_child.assign(new_first_child); - } - - pub fn set_last_child(&mut self, new_last_child: Option>) { - let roots = RootCollection::new(); - let doc = self.owner_doc().root(&roots); - doc.get().wait_until_safe_to_modify_dom(); - self.last_child.assign(new_last_child); - } - - pub fn set_prev_sibling(&mut self, new_prev_sibling: Option>) { - let roots = RootCollection::new(); - let doc = self.owner_doc().root(&roots); - doc.get().wait_until_safe_to_modify_dom(); - self.prev_sibling.assign(new_prev_sibling); - } - - pub fn set_next_sibling(&mut self, new_next_sibling: Option>) { - let roots = RootCollection::new(); - let doc = self.owner_doc().root(&roots); - doc.get().wait_until_safe_to_modify_dom(); - self.next_sibling.assign(new_next_sibling); - } - - pub fn get_hover_state(&self) -> bool { - self.flags.get_in_hover_state() - } - - pub fn set_hover_state(&mut self, state: bool) { - self.flags.set_is_in_hover_state(state); - } - - #[inline] - pub fn parent_node_ref<'a>(&'a self) -> Option<&'a JS> { - self.parent_node.as_ref() - } - - #[inline] - pub fn first_child_ref<'a>(&'a self) -> Option<&'a JS> { - self.first_child.as_ref() - } - - #[inline] - pub fn last_child_ref<'a>(&'a self) -> Option<&'a JS> { - self.last_child.as_ref() - } - - #[inline] - pub fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS> { - self.prev_sibling.as_ref() - } - - #[inline] - pub fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS> { - self.next_sibling.as_ref() - } - - pub unsafe fn get_hover_state_for_layout(&self) -> bool { - let unsafe_this: *Node = cast::transmute::<&Node,*Node>(self); - (*unsafe_this).flags.get_in_hover_state() + /// Sends layout data, if any, back to the script 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)) + }, + } + } } } @@ -1486,7 +1485,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { Some(ref list) => return Unrooted::new(list.clone()), } - let doc = self.deref().owner_doc().root(&roots); + let doc = self.owner_doc().root(&roots); let window = doc.deref().window.root(&roots); let child_list = NodeList::new_child_list(&*window, self); self.child_list.assign(Some(child_list)); @@ -1600,7 +1599,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { // Notify the document that the content of this node is different let document = self.owner_doc().root(&roots); - document.get().content_changed(); + document.deref().content_changed(); } DoctypeNodeTypeId | DocumentNodeTypeId => {} @@ -1671,7 +1670,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { return Err(HierarchyRequest); } if child.following_siblings() - .any(|child| child.deref().is_doctype()) { + .any(|child| child.is_doctype()) { return Err(HierarchyRequest); } }, @@ -1685,18 +1684,18 @@ impl<'a> NodeMethods for JSRef<'a, Node> { return Err(HierarchyRequest); } if child.following_siblings() - .any(|child| child.deref().is_doctype()) { + .any(|child| child.is_doctype()) { return Err(HierarchyRequest); } }, // Step 6.3 DoctypeNodeTypeId => { - if self.children().any(|c| c.deref().is_doctype() && &c != child) { + if self.children().any(|c| c.is_doctype() && &c != child) { return Err(HierarchyRequest); } if self.children() .take_while(|c| c != child) - .any(|c| c.deref().is_element()) { + .any(|c| c.is_element()) { return Err(HierarchyRequest); } }, diff --git a/src/components/script/html/hubbub_html_parser.rs b/src/components/script/html/hubbub_html_parser.rs index f9a4f641ffc..9326ed6cb15 100644 --- a/src/components/script/html/hubbub_html_parser.rs +++ b/src/components/script/html/hubbub_html_parser.rs @@ -7,11 +7,11 @@ use dom::bindings::codegen::InheritTypes::{NodeBase, NodeCast, TextCast, Element use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast; use dom::bindings::js::{JS, JSRef, RootCollection, Unrooted, OptionalRootable, Root}; use dom::bindings::utils::Reflectable; -use dom::document::Document; +use dom::document::{Document, DocumentHelpers}; use dom::element::{AttributeHandlers, HTMLLinkElementTypeId, HTMLIFrameElementTypeId}; use dom::htmlelement::HTMLElement; use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6}; -use dom::htmliframeelement::IFrameSize; +use dom::htmliframeelement::{IFrameSize, HTMLIFrameElementHelpers}; use dom::htmlformelement::HTMLFormElement; use dom::node::{ElementNodeTypeId, NodeHelpers, NodeMethods}; use dom::types::*; @@ -364,7 +364,11 @@ pub fn parse_html(page: &Page, }; // Spawn additional parsing, network loads, etc. from tag and attrs - match element.get().node.type_id { + let type_id = { + let node: &JSRef = NodeCast::from_ref(&*element); + node.type_id() + }; + match type_id { // Handle CSS style sheets from elements ElementNodeTypeId(HTMLLinkElementTypeId) => { match (rel, href) { @@ -384,10 +388,10 @@ pub fn parse_html(page: &Page, let iframe_chan = discovery_chan.clone(); let iframe_element: &mut JSRef = HTMLIFrameElementCast::to_mut_ref(&mut *element).unwrap(); - let sandboxed = iframe_element.get().is_sandboxed(); + let sandboxed = iframe_element.is_sandboxed(); for src in src_opt.iter() { let iframe_url = parse_url(*src, Some(url2.clone())); - iframe_element.get_mut().set_frame(iframe_url.clone()); + iframe_element.set_frame(iframe_url.clone()); // Subpage Id let subpage_id = *next_subpage_id.borrow(); @@ -463,14 +467,14 @@ pub fn parse_html(page: &Page, // NOTE: tmp vars are workaround for lifetime issues. Both required. let mut tmp_borrow = doc_cell.borrow_mut(); let tmp = &mut *tmp_borrow; - tmp.get_mut().set_quirks_mode(mode); + tmp.set_quirks_mode(mode); }, encoding_change: |encname| { debug!("encoding change"); // NOTE: tmp vars are workaround for lifetime issues. Both required. let mut tmp_borrow = doc_cell.borrow_mut(); let tmp = &mut *tmp_borrow; - tmp.get_mut().set_encoding_name(encname); + tmp.set_encoding_name(encname); }, complete_script: |script| { unsafe { diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index 600f28794a1..d82dace6d99 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -12,7 +12,7 @@ use dom::bindings::js::{JS, JSRef, RootCollection, Unrooted, OptionalAssignable} use dom::bindings::js::OptionalRootable; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::{Reflectable, GlobalStaticData, wrap_for_same_compartment}; -use dom::document::{Document, HTMLDocument, DocumentMethods}; +use dom::document::{Document, HTMLDocument, DocumentMethods, DocumentHelpers}; use dom::element::{Element, AttributeHandlers}; use dom::event::{Event_, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent}; use dom::event::{Event, EventMethods}; @@ -949,7 +949,7 @@ impl ScriptTask { } // Kick off the initial reflow of the page. - document.get().content_changed(); + document.content_changed(); let fragment = url.fragment.as_ref().map(|ref fragment| fragment.to_owned());