diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/main/layout/wrapper.rs | 36 | ||||
-rw-r--r-- | src/components/script/dom/document.rs | 172 | ||||
-rw-r--r-- | src/components/script/dom/element.rs | 88 | ||||
-rw-r--r-- | src/components/script/dom/htmlbuttonelement.rs | 6 | ||||
-rw-r--r-- | src/components/script/dom/htmlfieldsetelement.rs | 3 | ||||
-rw-r--r-- | src/components/script/dom/htmlformelement.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/htmliframeelement.rs | 11 | ||||
-rw-r--r-- | src/components/script/dom/htmlimageelement.rs | 53 | ||||
-rw-r--r-- | src/components/script/dom/htmlmapelement.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/htmlobjectelement.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/htmloutputelement.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/htmlselectelement.rs | 5 | ||||
-rw-r--r-- | src/components/script/dom/node.rs | 627 | ||||
-rw-r--r-- | src/components/script/html/hubbub_html_parser.rs | 18 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 4 |
15 files changed, 548 insertions, 495 deletions
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<HTMLImageElement> = 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<NodeTypeId> { - Some(self.node.type_id_for_layout()) + unsafe { + Some(self.node.type_id_for_layout()) + } } unsafe fn get_jsmanaged<'a>(&'a self) -> &'a JS<Node> { @@ -172,7 +175,7 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> { fn first_child(&self) -> Option<LayoutNode<'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)) } } @@ -221,19 +224,19 @@ impl<'ln> LayoutNode<'ln> { impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> { fn parent_node(&self) -> Option<LayoutNode<'ln>> { 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<LayoutNode<'ln>> { 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<LayoutNode<'ln>> { 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<LayoutElement<'ln>> for LayoutNode<'ln> { #[inline] fn as_element(&self) -> LayoutElement<'ln> { unsafe { + assert!(self.node.is_element_for_layout()); let elem: JS<Element> = self.node.transmute_copy(); let element = &*elem.unsafe_get(); LayoutElement { @@ -258,9 +262,9 @@ impl<'ln> TNode<LayoutElement<'ln>> 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<Element> = 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<LayoutElement<'ln>> 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<ThreadSafeLayoutNode<'ln>> { 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<Element> = self.node.get_jsmanaged().transmute_copy(); + assert!(self.get_jsmanaged().is_element_for_layout()); + let elem: JS<Element> = self.get_jsmanaged().transmute_copy(); let element = elem.unsafe_get(); // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // implementations. 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,97 +76,54 @@ impl DocumentDerived for EventTarget { } } -impl Document { - pub fn reflect_document(document: ~Document, - window: &JSRef<Window>, - wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~Document) -> JS<Document>) - -> Unrooted<Document> { - let roots = RootCollection::new(); - assert!(document.reflector().get_jsobject().is_null()); - let mut raw_doc = reflect_dom_object(document, window, wrap_fn).root(&roots); - assert!(raw_doc.reflector().get_jsobject().is_not_null()); - - let mut doc_alias = raw_doc.clone(); - let node: &mut JSRef<Node> = NodeCast::from_mut_ref(&mut doc_alias); - node.get_mut().set_owner_doc(&*raw_doc); - Unrooted::new_rooted(&*raw_doc) - } - - pub fn new_inherited(window: JS<Window>, - url: Option<Url>, - is_html_document: IsHTMLDocument, - content_type: Option<DOMString>) -> Document { - let url = url.unwrap_or_else(|| from_str("about:blank").unwrap()); - - Document { - node: Node::new_without_doc(DocumentNodeTypeId), - reflector_: Reflector::new(), - window: window, - idmap: HashMap::new(), - implementation: None, - content_type: match content_type { - Some(string) => string.clone(), - None => match is_html_document { - // http://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument - HTMLDocument => ~"text/html", - // http://dom.spec.whatwg.org/#concept-document-content-type - NonHTMLDocument => ~"application/xml" - } - }, - url: Untraceable::new(url), - // http://dom.spec.whatwg.org/#concept-document-quirks - quirks_mode: Untraceable::new(NoQuirks), - // http://dom.spec.whatwg.org/#concept-document-encoding - encoding_name: ~"utf-8", - is_html_document: is_html_document == HTMLDocument, - } - } - - // http://dom.spec.whatwg.org/#dom-document - pub fn Constructor(owner: &JSRef<Window>) -> Fallible<Unrooted<Document>> { - Ok(Document::new(owner, None, NonHTMLDocument, None)) - } - - pub fn new(window: &JSRef<Window>, url: Option<Url>, doctype: IsHTMLDocument, content_type: Option<DOMString>) -> Unrooted<Document> { - let document = Document::new_inherited(window.unrooted(), url, doctype, content_type); - Document::reflect_document(~document, window, DocumentBinding::Wrap) - } +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<Element>, id: DOMString); + fn register_named_element(&mut self, element: &JSRef<Element>, id: DOMString); +} - pub fn url<'a>(&'a self) -> &'a Url { +impl<'a> DocumentHelpers for JSRef<'a, Document> { + fn url<'a>(&'a self) -> &'a Url { &*self.url } - pub fn quirks_mode(&self) -> QuirksMode { + fn quirks_mode(&self) -> QuirksMode { *self.quirks_mode } - pub fn set_quirks_mode(&mut self, mode: QuirksMode) { + fn set_quirks_mode(&mut self, mode: QuirksMode) { *self.quirks_mode = mode; } - pub fn set_encoding_name(&mut self, name: DOMString) { + fn set_encoding_name(&mut self, name: DOMString) { self.encoding_name = name; } - pub fn content_changed(&self) { + fn content_changed(&self) { self.damage_and_reflow(ContentChangedDocumentDamage); } - pub fn damage_and_reflow(&self, damage: DocumentDamageLevel) { + 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) { + 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<Element>, - id: DOMString) { + fn unregister_named_element(&mut self, + to_unregister: &JSRef<Element>, + id: DOMString) { let roots = RootCollection::new(); let mut is_empty = false; match self.idmap.find_mut(&id) { @@ -186,10 +143,9 @@ impl Document { } /// Associate an element present in this document with the provided id. - pub fn register_named_element(&mut self, - abstract_self: &JSRef<Document>, - element: &JSRef<Element>, - id: DOMString) { + fn register_named_element(&mut self, + element: &JSRef<Element>, + id: DOMString) { let roots = RootCollection::new(); assert!({ let node: &JSRef<Node> = NodeCast::from_ref(element); @@ -198,7 +154,7 @@ impl Document { // 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); + 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<Node> = NodeCast::from_ref(element); @@ -227,6 +183,63 @@ impl Document { } } +impl Document { + pub fn reflect_document(document: ~Document, + window: &JSRef<Window>, + wrap_fn: extern "Rust" fn(*JSContext, &JSRef<Window>, ~Document) -> JS<Document>) + -> Unrooted<Document> { + let roots = RootCollection::new(); + assert!(document.reflector().get_jsobject().is_null()); + let mut raw_doc = reflect_dom_object(document, window, wrap_fn).root(&roots); + assert!(raw_doc.reflector().get_jsobject().is_not_null()); + + let mut doc_alias = raw_doc.clone(); + let node: &mut JSRef<Node> = NodeCast::from_mut_ref(&mut doc_alias); + node.set_owner_doc(&*raw_doc); + Unrooted::new_rooted(&*raw_doc) + } + + pub fn new_inherited(window: JS<Window>, + url: Option<Url>, + is_html_document: IsHTMLDocument, + content_type: Option<DOMString>) -> Document { + let url = url.unwrap_or_else(|| from_str("about:blank").unwrap()); + + Document { + node: Node::new_without_doc(DocumentNodeTypeId), + reflector_: Reflector::new(), + window: window, + idmap: HashMap::new(), + implementation: None, + content_type: match content_type { + Some(string) => string.clone(), + None => match is_html_document { + // http://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument + HTMLDocument => ~"text/html", + // http://dom.spec.whatwg.org/#concept-document-content-type + NonHTMLDocument => ~"application/xml" + } + }, + url: Untraceable::new(url), + // http://dom.spec.whatwg.org/#concept-document-quirks + quirks_mode: Untraceable::new(NoQuirks), + // http://dom.spec.whatwg.org/#concept-document-encoding + encoding_name: ~"utf-8", + is_html_document: is_html_document == HTMLDocument, + } + } + + // http://dom.spec.whatwg.org/#dom-document + pub fn Constructor(owner: &JSRef<Window>) -> Fallible<Unrooted<Document>> { + Ok(Document::new(owner, None, NonHTMLDocument, None)) + } + + pub fn new(window: &JSRef<Window>, url: Option<Url>, doctype: IsHTMLDocument, content_type: Option<DOMString>) -> Unrooted<Document> { + let document = Document::new_inherited(window.unrooted(), url, doctype, content_type); + Document::reflect_document(~document, window, DocumentBinding::Wrap) + } +} + impl Reflectable for Document { fn reflector<'a>(&'a self) -> &'a Reflector { self.node.reflector() @@ -237,12 +250,12 @@ impl Reflectable for Document { } } -trait DocumentHelpers { +trait PrivateDocumentHelpers { fn createNodeList(&self, callback: |node: &JSRef<Node>| -> bool) -> Unrooted<NodeList>; fn get_html_element(&self) -> Option<Unrooted<HTMLHtmlElement>>; } -impl<'a> DocumentHelpers for JSRef<'a, Document> { +impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> { fn createNodeList(&self, callback: |node: &JSRef<Node>| -> bool) -> Unrooted<NodeList> { 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<Unrooted<DocumentType>> { - self.node.children().find(|child| { + let node: &JSRef<Node> = NodeCast::from_ref(self); + node.children().find(|child| { child.is_doctype() }).map(|node| { let doctype: &JSRef<DocumentType> = 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<Unrooted<Element>> { - self.node.child_elements().next().map(|elem| Unrooted::new_rooted(&elem)) + let node: &JSRef<Node> = 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<Text> = 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<Node> = 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<Attr>| { + 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<Element> { + unsafe fn html_element_in_html_document_for_layout(&self) -> bool { + if (*self.unsafe_get()).namespace != namespace::HTML { return false } - let owner_doc: *JS<Document> = self.node.owner_doc_for_layout(); - let owner_doc: **Document = owner_doc as **Document; - (**owner_doc).is_html_document + let node: JS<Node> = 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<Attr>| { - // 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<Node> = 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<Unrooted<Attr>> { 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<Attr>| -> 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<Node> = 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<DOMString> { 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<Node> = 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<Node> = 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<Node> = 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<ValidityState> { 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<ValidityState>) { 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<ValidityState> { 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<HTMLCollection> { // 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<Document>) -> HTMLImageElement { - HTMLImageElement { - htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document), - image: Untraceable::new(None), - } - } - - pub fn new(localName: DOMString, document: &JSRef<Document>) -> Unrooted<HTMLImageElement> { - let element = HTMLImageElement::new_inherited(localName, document.unrooted()); - Node::reflect_node(~element, document, HTMLImageElementBinding::Wrap) - } - - pub fn image<'a>(&'a self) -> &'a Option<Url> { - &*self.image - } +trait PrivateHTMLImageElementHelpers { + fn update_image(&mut self, value: Option<DOMString>, url: Option<Url>); +} +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<DOMString>, url: Option<Url>) { 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<Node> = 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<Document>) -> HTMLImageElement { + HTMLImageElement { + htmlelement: HTMLElement::new_inherited(HTMLImageElementTypeId, localName, document), + image: Untraceable::new(None), + } + } + + pub fn new(localName: DOMString, document: &JSRef<Document>) -> Unrooted<HTMLImageElement> { + 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<Url>; +} + +impl LayoutHTMLImageElementHelpers for JS<HTMLImageElement> { + unsafe fn image<'a>(&'a self) -> &'a Option<Url> { + &*(*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<HTMLCollection> { 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<ValidityState> { 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<ValidityState> { 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<ValidityState> { 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<JSRef<Node>>); + fn set_first_child(&mut self, new_first_child: Option<JSRef<Node>>); + fn set_last_child(&mut self, new_last_child: Option<JSRef<Node>>); + fn set_prev_sibling(&mut self, new_prev_sibling: Option<JSRef<Node>>); + fn set_next_sibling(&mut self, new_next_sibling: Option<JSRef<Node>>); + + fn node_inserted(&self); + fn node_removed(&self); + fn add_child(&mut self, new_child: &mut JSRef<Node>, before: Option<JSRef<Node>>); + fn remove_child(&mut self, child: &mut JSRef<Node>); +} + +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<Node>, mut before: Option<JSRef<Node>>) { + 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<Node>) { + 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<JSRef<Node>>) { + 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<JSRef<Node>>) { + 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<JSRef<Node>>) { + 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<JSRef<Node>>) { + 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<JSRef<Node>>) { + 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<Unrooted<Node>>; fn next_sibling(&self) -> Option<Unrooted<Node>>; + fn owner_doc(&self) -> Unrooted<Document>; + fn set_owner_doc(&mut self, document: &JSRef<Document>); + + 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<Node>, before: Option<JSRef<Node>>); - fn remove_child(&mut self, child: &mut JSRef<Node>); - 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<Node>, mut before: Option<JSRef<Node>>) { - 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<Node>) { - 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<Document> { + Unrooted::new(self.owner_doc.get_ref().clone()) + } + + fn set_owner_doc(&mut self, document: &JSRef<Document>) { + 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<Element> = 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<Node>>; + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>>; + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS<Document>; + + unsafe fn is_element_for_layout(&self) -> bool; } impl LayoutNodeHelpers for JS<Node> { - fn type_id_for_layout(&self) -> NodeTypeId { - unsafe { - let node: **Node = cast::transmute::<*JS<Node>, - **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<Node>> { + (*self.unsafe_get()).parent_node.as_ref() + } + + #[inline] + unsafe fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).first_child.as_ref() + } + + #[inline] + unsafe fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).last_child.as_ref() + } + + #[inline] + unsafe fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).prev_sibling.as_ref() + } + + #[inline] + unsafe fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { + (*self.unsafe_get()).next_sibling.as_ref() + } + + unsafe fn owner_doc_for_layout<'a>(&'a self) -> &'a JS<Document> { + (*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<JSRef<Node>> { - if !self.include_descendants_of_void && node.get().is_element() { + if !self.include_descendants_of_void && node.is_element() { let elem: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); if elem.get().is_void() { None @@ -771,65 +909,6 @@ pub enum CloneChildrenFlag { fn as_uintptr<T>(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<Document> { - Unrooted::new(self.owner_doc.get_ref().clone()) - } - - pub fn owner_doc_for_layout<'a>(&'a self) -> &'a JS<Document> { - self.owner_doc.get_ref() - } - - pub fn set_owner_doc(&mut self, document: &JSRef<Document>) { - 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<Element> = 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<N: Reflectable+NodeBase> (node: ~N, document: &JSRef<Document>, @@ -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<Node>, document: &JSRef<Document>) { 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<JSRef<Node>>, parent: &mut JSRef<Node>) { + fn replace_all(mut node: Option<JSRef<Node>>, parent: &mut JSRef<Node>) { 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<Document> = 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<Document> = DocumentCast::to_ref(node).unwrap(); - let node_doc = node_doc.get(); let copy_doc: &mut JSRef<Document> = 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<JSRef<Node>>) { - 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<JSRef<Node>>) { - 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<JSRef<Node>>) { - 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<JSRef<Node>>) { - 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<JSRef<Node>>) { - 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<Node>> { - self.parent_node.as_ref() - } - - #[inline] - pub fn first_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.first_child.as_ref() - } - - #[inline] - pub fn last_child_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.last_child.as_ref() - } - - #[inline] - pub fn prev_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - self.prev_sibling.as_ref() - } - - #[inline] - pub fn next_sibling_ref<'a>(&'a self) -> Option<&'a JS<Node>> { - 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<Node> = NodeCast::from_ref(&*element); + node.type_id() + }; + match type_id { // Handle CSS style sheets from <link> 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<HTMLIFrameElement> = 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()); |