Use Cell/RefCell for interior mutability of Element.

This commit is contained in:
Tetsuharu OHZEKI 2014-05-28 05:15:00 +09:00
parent 6d9dcd087a
commit b0239b5a5a
3 changed files with 31 additions and 24 deletions

View file

@ -31,6 +31,7 @@ use servo_util::str::{DOMString, null_str_as_empty_ref, split_html_space_chars};
use std::ascii::StrAsciiExt; use std::ascii::StrAsciiExt;
use std::cast; use std::cast;
use std::cell::{Cell, RefCell};
#[deriving(Encodable)] #[deriving(Encodable)]
pub struct Element { pub struct Element {
@ -38,9 +39,9 @@ pub struct Element {
pub local_name: DOMString, // TODO: This should be an atom, not a DOMString. pub local_name: DOMString, // TODO: This should be an atom, not a DOMString.
pub namespace: Namespace, pub namespace: Namespace,
pub prefix: Option<DOMString>, pub prefix: Option<DOMString>,
pub attrs: Vec<JS<Attr>>, pub attrs: RefCell<Vec<JS<Attr>>>,
pub style_attribute: Option<style::PropertyDeclarationBlock>, pub style_attribute: Option<style::PropertyDeclarationBlock>,
pub attr_list: Option<JS<AttrList>> pub attr_list: Cell<Option<JS<AttrList>>>
} }
impl ElementDerived for EventTarget { impl ElementDerived for EventTarget {
@ -147,8 +148,8 @@ impl Element {
local_name: local_name, local_name: local_name,
namespace: namespace, namespace: namespace,
prefix: prefix, prefix: prefix,
attrs: vec!(), attrs: RefCell::new(vec!()),
attr_list: None, attr_list: Cell::new(None),
style_attribute: None, style_attribute: None,
} }
} }
@ -167,7 +168,9 @@ impl RawLayoutElementHelpers for Element {
#[inline] #[inline]
unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str) unsafe fn get_attr_val_for_layout(&self, namespace: &Namespace, name: &str)
-> Option<&'static str> { -> Option<&'static str> {
self.attrs.iter().find(|attr: & &JS<Attr>| { // cast to point to T in RefCell<T> directly
let attrs: *Vec<JS<Attr>> = cast::transmute(&self.attrs);
(*attrs).iter().find(|attr: & &JS<Attr>| {
let attr = attr.unsafe_get(); let attr = attr.unsafe_get();
name == (*attr).local_name && (*attr).namespace == *namespace name == (*attr).local_name && (*attr).namespace == *namespace
}).map(|attr| { }).map(|attr| {
@ -232,7 +235,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
let element: &Element = self.deref(); let element: &Element = self.deref();
let is_html_element = self.html_element_in_html_document(); let is_html_element = self.html_element_in_html_document();
element.attrs.iter().map(|attr| attr.root()).find(|attr| { element.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| {
let same_name = if is_html_element { let same_name = if is_html_element {
name.to_ascii_lower() == attr.local_name name.to_ascii_lower() == attr.local_name
} else { } else {
@ -284,7 +287,7 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString, fn do_set_attribute(&mut self, local_name: DOMString, value: DOMString,
name: DOMString, namespace: Namespace, name: DOMString, namespace: Namespace,
prefix: Option<DOMString>, cb: |&JSRef<Attr>| -> bool) { prefix: Option<DOMString>, cb: |&JSRef<Attr>| -> bool) {
let idx = self.deref().attrs.iter() let idx = self.deref().attrs.borrow().iter()
.map(|attr| attr.root()) .map(|attr| attr.root())
.position(|attr| cb(&*attr)); .position(|attr| cb(&*attr));
let (idx, set_type) = match idx { let (idx, set_type) = match idx {
@ -293,18 +296,18 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
let window = window_from_node(self).root(); let window = window_from_node(self).root();
let attr = Attr::new(&*window, local_name.clone(), value.clone(), let attr = Attr::new(&*window, local_name.clone(), value.clone(),
name, namespace.clone(), prefix, self); name, namespace.clone(), prefix, self);
self.deref_mut().attrs.push_unrooted(&attr); self.deref().attrs.borrow_mut().push_unrooted(&attr);
(self.deref().attrs.len() - 1, FirstSetAttr) (self.deref().attrs.borrow().len() - 1, FirstSetAttr)
} }
}; };
self.deref_mut().attrs.get(idx).root().set_value(set_type, value); self.deref().attrs.borrow().get(idx).root().set_value(set_type, value);
} }
fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult { fn remove_attribute(&mut self, namespace: Namespace, name: DOMString) -> ErrorResult {
let (_, local_name) = get_attribute_parts(name.clone()); let (_, local_name) = get_attribute_parts(name.clone());
let idx = self.deref().attrs.iter().map(|attr| attr.root()).position(|attr| { let idx = self.deref().attrs.borrow().iter().map(|attr| attr.root()).position(|attr| {
attr.local_name == local_name attr.local_name == local_name
}); });
@ -317,12 +320,12 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
} }
if namespace == namespace::Null { if namespace == namespace::Null {
let removed_raw_value = self.deref().attrs.get(idx).root().Value(); let removed_raw_value = self.deref().attrs.borrow().get(idx).root().Value();
vtable_for(NodeCast::from_mut_ref(self)) vtable_for(NodeCast::from_mut_ref(self))
.before_remove_attr(local_name.clone(), removed_raw_value); .before_remove_attr(local_name.clone(), removed_raw_value);
} }
self.deref_mut().attrs.remove(idx); self.deref().attrs.borrow_mut().remove(idx);
} }
}; };
@ -469,7 +472,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
// http://dom.spec.whatwg.org/#dom-element-attributes // http://dom.spec.whatwg.org/#dom-element-attributes
fn Attributes(&mut self) -> Temporary<AttrList> { fn Attributes(&mut self) -> Temporary<AttrList> {
match self.attr_list { match self.attr_list.get() {
None => (), None => (),
Some(ref list) => return Temporary::new(list.clone()), Some(ref list) => return Temporary::new(list.clone()),
} }
@ -481,7 +484,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> {
let window = doc.deref().window.root(); let window = doc.deref().window.root();
let list = AttrList::new(&*window, self); let list = AttrList::new(&*window, self);
self.attr_list.assign(Some(list)); self.attr_list.assign(Some(list));
Temporary::new(self.attr_list.get_ref().clone()) Temporary::new(self.attr_list.get().get_ref().clone())
} }
// http://dom.spec.whatwg.org/#dom-element-getattribute // http://dom.spec.whatwg.org/#dom-element-getattribute

View file

@ -106,7 +106,7 @@ fn serialize_doctype(doctype: &JSRef<DocumentType>, html: &mut StrBuf) {
fn serialize_elem(elem: &JSRef<Element>, open_elements: &mut Vec<~str>, html: &mut StrBuf) { fn serialize_elem(elem: &JSRef<Element>, open_elements: &mut Vec<~str>, html: &mut StrBuf) {
html.push_char('<'); html.push_char('<');
html.push_str(elem.deref().local_name); html.push_str(elem.deref().local_name);
for attr in elem.deref().attrs.iter() { for attr in elem.deref().attrs.borrow().iter() {
let attr = attr.root(); let attr = attr.root();
serialize_attr(&*attr, html); serialize_attr(&*attr, html);
}; };

View file

@ -1297,8 +1297,8 @@ impl Node {
// FIXME: https://github.com/mozilla/servo/issues/1737 // FIXME: https://github.com/mozilla/servo/issues/1737
copy_elem.namespace = node_elem.namespace.clone(); copy_elem.namespace = node_elem.namespace.clone();
let window = document.deref().window.root(); let window = document.deref().window.root();
for attr in node_elem.attrs.iter().map(|attr| attr.root()) { for attr in node_elem.attrs.borrow().iter().map(|attr| attr.root()) {
copy_elem.attrs.push_unrooted( copy_elem.attrs.borrow_mut().push_unrooted(
&Attr::new(&*window, &Attr::new(&*window,
attr.deref().local_name.clone(), attr.deref().value.clone(), attr.deref().local_name.clone(), attr.deref().value.clone(),
attr.deref().name.clone(), attr.deref().namespace.clone(), attr.deref().name.clone(), attr.deref().namespace.clone(),
@ -1766,9 +1766,11 @@ impl<'a> NodeMethods for JSRef<'a, Node> {
let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap(); let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap();
// FIXME: namespace prefix // FIXME: namespace prefix
(element.deref().namespace == other_element.deref().namespace) && let element = element.deref();
(element.deref().local_name == other_element.deref().local_name) && let other_element = other_element.deref();
(element.deref().attrs.len() == other_element.deref().attrs.len()) (element.namespace == other_element.namespace) &&
(element.local_name == other_element.local_name) &&
(element.attrs.borrow().len() == other_element.attrs.borrow().len())
} }
fn is_equal_processinginstruction(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { fn is_equal_processinginstruction(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap(); let pi: &JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
@ -1784,9 +1786,11 @@ impl<'a> NodeMethods for JSRef<'a, Node> {
fn is_equal_element_attrs(node: &JSRef<Node>, other: &JSRef<Node>) -> bool { fn is_equal_element_attrs(node: &JSRef<Node>, other: &JSRef<Node>) -> bool {
let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap(); let element: &JSRef<Element> = ElementCast::to_ref(node).unwrap();
let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap(); let other_element: &JSRef<Element> = ElementCast::to_ref(other).unwrap();
assert!(element.deref().attrs.len() == other_element.deref().attrs.len()); let element = element.deref();
element.deref().attrs.iter().map(|attr| attr.root()).all(|attr| { let other_element = other_element.deref();
other_element.deref().attrs.iter().map(|attr| attr.root()).any(|other_attr| { assert!(element.attrs.borrow().len() == other_element.attrs.borrow().len());
element.attrs.borrow().iter().map(|attr| attr.root()).all(|attr| {
other_element.attrs.borrow().iter().map(|attr| attr.root()).any(|other_attr| {
(attr.namespace == other_attr.namespace) && (attr.namespace == other_attr.namespace) &&
(attr.local_name == other_attr.local_name) && (attr.local_name == other_attr.local_name) &&
(attr.value == other_attr.value) (attr.value == other_attr.value)