diff options
author | bors-servo <release+servo@mozilla.com> | 2014-05-03 14:25:22 -0400 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-05-03 14:25:22 -0400 |
commit | 731e66ff132e41cdc49bc5324c0e15be19c46ec2 (patch) | |
tree | ccce9b42e8a6c54245e53620082efe0b9840eae1 /src/components/script/dom/htmlcollection.rs | |
parent | 4051a8096d7ba7e7f9c86e76d0b4bffd83e85805 (diff) | |
parent | 91278da9dd55582401154e07f9eea34425a332c2 (diff) | |
download | servo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.tar.gz servo-731e66ff132e41cdc49bc5324c0e15be19c46ec2.zip |
auto merge of #2101 : jdm/servo/newroot_rebase, r=Ms2ger
As described in #1764, this strategy uses the following properties:
* DOM members are `JS<T>` types. These cannot be used with being explicitly rooted, but they are required for compiler-derived trace hooks.
* Methods that take DOM type arguments receive `&[mut] JSRef<T>`. These are rooted value references that are cloneable but cannot escape.
* Methods that return DOM values use `Unrooted<T>`. These are values that may or may not be rooted elsewhere, but callers must root them in order to interact with them in any way. One unsoundness hole exists - `Unrooted` values must be rooted ASAP, or there exists the danger that JSAPI calls could be made that could cause the underlying JS value to be GCed.
* All methods are implemented on `JSRef<T>`, enforcing the requirement that all DOM values are rooted for the duration of a method call (with a few exceptions for layout-related code, which cannot root values and therefore interacts with `JS<T>` and `&T` values - this is safe under the assumption that layout code interacts with DOM nodes that are in the tree, therefore rooted, and does not run concurrently with content code)
Diffstat (limited to 'src/components/script/dom/htmlcollection.rs')
-rw-r--r-- | src/components/script/dom/htmlcollection.rs | 120 |
1 files changed, 72 insertions, 48 deletions
diff --git a/src/components/script/dom/htmlcollection.rs b/src/components/script/dom/htmlcollection.rs index 79b35487634..82b0d54693f 100644 --- a/src/components/script/dom/htmlcollection.rs +++ b/src/components/script/dom/htmlcollection.rs @@ -4,7 +4,7 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, NodeCast}; use dom::bindings::codegen::BindingDeclarations::HTMLCollectionBinding; -use dom::bindings::js::JS; +use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::element::{Element, AttributeHandlers}; use dom::node::{Node, NodeHelpers}; @@ -15,7 +15,7 @@ use servo_util::str::{DOMString, split_html_space_chars}; use serialize::{Encoder, Encodable}; pub trait CollectionFilter { - fn filter(&self, elem: &JS<Element>, root: &JS<Node>) -> bool; + fn filter(&self, elem: &JSRef<Element>, root: &JSRef<Node>) -> bool; } impl<S: Encoder<E>, E> Encodable<S, E> for ~CollectionFilter { @@ -38,33 +38,33 @@ pub struct HTMLCollection { } impl HTMLCollection { - pub fn new_inherited(window: JS<Window>, collection: CollectionTypeId) -> HTMLCollection { + pub fn new_inherited(window: &JSRef<Window>, collection: CollectionTypeId) -> HTMLCollection { HTMLCollection { collection: collection, reflector_: Reflector::new(), - window: window, + window: window.unrooted(), } } - pub fn new(window: &JS<Window>, collection: CollectionTypeId) -> JS<HTMLCollection> { - reflect_dom_object(~HTMLCollection::new_inherited(window.clone(), collection), + pub fn new(window: &JSRef<Window>, collection: CollectionTypeId) -> Temporary<HTMLCollection> { + reflect_dom_object(~HTMLCollection::new_inherited(window, collection), window, HTMLCollectionBinding::Wrap) } } impl HTMLCollection { - pub fn create(window: &JS<Window>, root: &JS<Node>, filter: ~CollectionFilter) -> JS<HTMLCollection> { - HTMLCollection::new(window, Live(root.clone(), filter)) + pub fn create(window: &JSRef<Window>, root: &JSRef<Node>, filter: ~CollectionFilter) -> Temporary<HTMLCollection> { + HTMLCollection::new(window, Live(root.unrooted(), filter)) } - pub fn by_tag_name(window: &JS<Window>, root: &JS<Node>, tag: DOMString) - -> JS<HTMLCollection> { + pub fn by_tag_name(window: &JSRef<Window>, root: &JSRef<Node>, tag: DOMString) + -> Temporary<HTMLCollection> { struct TagNameFilter { tag: DOMString } impl CollectionFilter for TagNameFilter { - fn filter(&self, elem: &JS<Element>, _root: &JS<Node>) -> bool { - elem.get().local_name == self.tag + fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool { + elem.deref().local_name == self.tag } } let filter = TagNameFilter { @@ -73,15 +73,15 @@ impl HTMLCollection { HTMLCollection::create(window, root, ~filter) } - pub fn by_tag_name_ns(window: &JS<Window>, root: &JS<Node>, tag: DOMString, - namespace: Namespace) -> JS<HTMLCollection> { + pub fn by_tag_name_ns(window: &JSRef<Window>, root: &JSRef<Node>, tag: DOMString, + namespace: Namespace) -> Temporary<HTMLCollection> { struct TagNameNSFilter { tag: DOMString, namespace: Namespace } impl CollectionFilter for TagNameNSFilter { - fn filter(&self, elem: &JS<Element>, _root: &JS<Node>) -> bool { - elem.get().namespace == self.namespace && elem.get().local_name == self.tag + fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool { + elem.deref().namespace == self.namespace && elem.deref().local_name == self.tag } } let filter = TagNameNSFilter { @@ -91,13 +91,13 @@ impl HTMLCollection { HTMLCollection::create(window, root, ~filter) } - pub fn by_class_name(window: &JS<Window>, root: &JS<Node>, classes: DOMString) - -> JS<HTMLCollection> { + pub fn by_class_name(window: &JSRef<Window>, root: &JSRef<Node>, classes: DOMString) + -> Temporary<HTMLCollection> { struct ClassNameFilter { classes: Vec<DOMString> } impl CollectionFilter for ClassNameFilter { - fn filter(&self, elem: &JS<Element>, _root: &JS<Node>) -> bool { + fn filter(&self, elem: &JSRef<Element>, _root: &JSRef<Node>) -> bool { self.classes.iter().all(|class| elem.has_class(*class)) } } @@ -107,46 +107,65 @@ impl HTMLCollection { HTMLCollection::create(window, root, ~filter) } - pub fn children(window: &JS<Window>, root: &JS<Node>) -> JS<HTMLCollection> { + pub fn children(window: &JSRef<Window>, root: &JSRef<Node>) -> Temporary<HTMLCollection> { struct ElementChildFilter; impl CollectionFilter for ElementChildFilter { - fn filter(&self, elem: &JS<Element>, root: &JS<Node>) -> bool { - root.is_parent_of(&NodeCast::from(elem)) + fn filter(&self, elem: &JSRef<Element>, root: &JSRef<Node>) -> bool { + root.is_parent_of(NodeCast::from_ref(elem)) } } HTMLCollection::create(window, root, ~ElementChildFilter) } } -impl HTMLCollection { +pub trait HTMLCollectionMethods { + fn Length(&self) -> u32; + fn Item(&self, index: u32) -> Option<Temporary<Element>>; + fn NamedItem(&self, key: DOMString) -> Option<Temporary<Element>>; + fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<Element>>; + fn NamedGetter(&self, maybe_name: Option<DOMString>, found: &mut bool) -> Option<Temporary<Element>>; +} + +impl<'a> HTMLCollectionMethods for JSRef<'a, HTMLCollection> { // http://dom.spec.whatwg.org/#dom-htmlcollection-length - pub fn Length(&self) -> u32 { + fn Length(&self) -> u32 { match self.collection { Static(ref elems) => elems.len() as u32, - Live(ref root, ref filter) => root.traverse_preorder() - .count(|child| { - let elem: Option<JS<Element>> = ElementCast::to(&child); - elem.map_or(false, |elem| filter.filter(&elem, root)) - }) as u32 + Live(ref root, ref filter) => { + let root = root.root(); + root.deref().traverse_preorder() + .count(|child| { + let elem: Option<&JSRef<Element>> = ElementCast::to_ref(&child); + elem.map_or(false, |elem| filter.filter(elem, &*root)) + }) as u32 + } } } // http://dom.spec.whatwg.org/#dom-htmlcollection-item - pub fn Item(&self, index: u32) -> Option<JS<Element>> { + fn Item(&self, index: u32) -> Option<Temporary<Element>> { match self.collection { Static(ref elems) => elems .as_slice() .get(index as uint) - .map(|elem| elem.clone()), - Live(ref root, ref filter) => root.traverse_preorder() - .filter_map(|node| ElementCast::to(&node)) - .filter(|elem| filter.filter(elem, root)) - .nth(index as uint).clone() + .map(|elem| Temporary::new(elem.clone())), + Live(ref root, ref filter) => { + let root = root.root(); + root.deref().traverse_preorder() + .filter_map(|node| { + let elem: Option<&JSRef<Element>> = ElementCast::to_ref(&node); + elem.filtered(|&elem| filter.filter(elem, &*root)) + .map(|elem| elem.clone()) + }) + .nth(index as uint) + .clone() + .map(|elem| Temporary::from_rooted(&elem)) + } } } // http://dom.spec.whatwg.org/#dom-htmlcollection-nameditem - pub fn NamedItem(&self, key: DOMString) -> Option<JS<Element>> { + fn NamedItem(&self, key: DOMString) -> Option<Temporary<Element>> { // Step 1. if key.is_empty() { return None; @@ -155,29 +174,34 @@ impl HTMLCollection { // Step 2. match self.collection { Static(ref elems) => elems.iter() + .map(|elem| elem.root()) .find(|elem| { elem.get_string_attribute("name") == key || elem.get_string_attribute("id") == key }) - .map(|maybe_elem| maybe_elem.clone()), - Live(ref root, ref filter) => root.traverse_preorder() - .filter_map(|node| ElementCast::to(&node)) - .filter(|elem| filter.filter(elem, root)) - .find(|elem| { - elem.get_string_attribute("name") == key || - elem.get_string_attribute("id") == key }) - .map(|maybe_elem| maybe_elem.clone()) + .map(|maybe_elem| Temporary::from_rooted(&*maybe_elem)), + Live(ref root, ref filter) => { + let root = root.root(); + root.deref().traverse_preorder() + .filter_map(|node| { + let elem: Option<&JSRef<Element>> = ElementCast::to_ref(&node); + elem.filtered(|&elem| filter.filter(elem, &*root)) + .map(|elem| elem.clone()) + }) + .find(|elem| { + elem.get_string_attribute("name") == key || + elem.get_string_attribute("id") == key }) + .map(|maybe_elem| Temporary::from_rooted(&maybe_elem)) + } } } -} -impl HTMLCollection { - pub fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<JS<Element>> { + fn IndexedGetter(&self, index: u32, found: &mut bool) -> Option<Temporary<Element>> { let maybe_elem = self.Item(index); *found = maybe_elem.is_some(); maybe_elem } - pub fn NamedGetter(&self, maybe_name: Option<DOMString>, found: &mut bool) -> Option<JS<Element>> { + fn NamedGetter(&self, maybe_name: Option<DOMString>, found: &mut bool) -> Option<Temporary<Element>> { match maybe_name { Some(name) => { let maybe_elem = self.NamedItem(name); |