servo: Merge #7611 - Cache the id attribute on Element (from nox:cache-element-id); r=frewsxcv

Thanks to @asabil for the original work, I only rebased it.

Fixes #6359 and #7040.

Source-Repo: https://github.com/servo/servo
Source-Revision: d1269294e6c602c91012397c7584e3c2077e21ac
This commit is contained in:
Ali Sabil 2015-09-20 09:23:20 -06:00
parent fac5f2cebf
commit a77bcca98e
4 changed files with 43 additions and 47 deletions

View File

@ -487,7 +487,7 @@ impl<'le> ::selectors::Element for LayoutElement<'le> {
#[inline]
fn get_id(&self) -> Option<Atom> {
unsafe {
(*self.element.unsafe_get()).get_attr_atom_for_layout(&ns!(""), &atom!("id"))
(*self.element.id_attribute()).clone()
}
}

View File

@ -70,7 +70,7 @@ use selectors::parser::{AttrSelector, NamespaceConstraint};
use smallvec::VecLike;
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
use std::cell::{Ref, RefMut};
use std::cell::Ref;
use std::default::Default;
use std::mem;
use std::sync::Arc;
@ -92,6 +92,7 @@ pub struct Element {
namespace: Namespace,
prefix: Option<DOMString>,
attrs: DOMRefCell<Vec<JS<Attr>>>,
id_attribute: DOMRefCell<Option<Atom>>,
style_attribute: DOMRefCell<Option<PropertyDeclarationBlock>>,
attr_list: MutNullableHeap<JS<NamedNodeMap>>,
class_list: MutNullableHeap<JS<DOMTokenList>>,
@ -146,6 +147,7 @@ impl Element {
attrs: DOMRefCell::new(vec!()),
attr_list: Default::default(),
class_list: Default::default(),
id_attribute: DOMRefCell::new(None),
style_attribute: DOMRefCell::new(None),
}
}
@ -505,6 +507,7 @@ pub trait LayoutElementHelpers {
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
#[allow(unsafe_code)]
unsafe fn has_attr_for_layout(&self, namespace: &Namespace, name: &Atom) -> bool;
fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<PropertyDeclarationBlock>;
fn local_name(&self) -> &Atom;
fn namespace(&self) -> &Namespace;
@ -528,6 +531,13 @@ impl LayoutElementHelpers for LayoutJS<Element> {
get_attr_for_layout(&*self.unsafe_get(), namespace, name).is_some()
}
#[allow(unsafe_code)]
fn id_attribute(&self) -> *const Option<Atom> {
unsafe {
(*self.unsafe_get()).id_attribute.borrow_for_layout()
}
}
#[allow(unsafe_code)]
fn style_attribute(&self) -> *const Option<PropertyDeclarationBlock> {
unsafe {
@ -610,10 +620,6 @@ impl Element {
self.attrs.borrow()
}
pub fn attrs_mut(&self) -> RefMut<Vec<JS<Attr>>> {
self.attrs.borrow_mut()
}
pub fn style_attribute(&self) -> &DOMRefCell<Option<PropertyDeclarationBlock>> {
&self.style_attribute
}
@ -1484,6 +1490,15 @@ impl VirtualMethods for Element {
NodeDamage::NodeStyleDamaged
},
&atom!(id) => {
*self.id_attribute.borrow_mut() =
mutation.new_value(attr).and_then(|value| {
let value = value.as_atom();
if value != &atom!("") {
Some(value.clone())
} else {
None
}
});
if node.is_in_doc() {
let value = attr.value().as_atom().clone();
match mutation {
@ -1530,13 +1545,9 @@ impl VirtualMethods for Element {
if !tree_in_doc { return; }
if let Some(ref attr) = self.get_attribute(&ns!(""), &atom!("id")) {
let value = attr.value();
if !value.is_empty() {
if let Some(ref value) = *self.id_attribute.borrow() {
let doc = document_from_node(self);
let value = Atom::from_slice(&value);
doc.register_named_element(self, value.to_owned());
}
doc.register_named_element(self, value.clone());
}
}
@ -1547,13 +1558,9 @@ impl VirtualMethods for Element {
if !tree_in_doc { return; }
if let Some(ref attr) = self.get_attribute(&ns!(""), &atom!("id")) {
let value = attr.value();
if !value.is_empty() {
if let Some(ref value) = *self.id_attribute.borrow() {
let doc = document_from_node(self);
let value = Atom::from_slice(&value);
doc.unregister_named_element(self, value.to_owned());
}
doc.unregister_named_element(self, value.clone());
}
}
}
@ -1639,12 +1646,7 @@ impl<'a> ::selectors::Element for Root<Element> {
node.get_focus_state()
}
fn get_id(&self) -> Option<Atom> {
self.get_attribute(&ns!(""), &atom!("id")).map(|attr| {
match *attr.r().value() {
AttrValue::Atom(ref val) => val.clone(),
_ => panic!("`id` attribute should be AttrValue::Atom"),
}
})
self.id_attribute.borrow().clone()
}
fn get_disabled_state(&self) -> bool {
let node = NodeCast::from_ref(&**self);

View File

@ -811,18 +811,17 @@ impl Node {
Err(()) => Err(Syntax),
// Step 3.
Ok(ref selectors) => {
let root = self.ancestors().last();
let root = root.r().unwrap_or(self.clone());
Ok(root.traverse_preorder().filter_map(ElementCast::to_root).find(|element| {
Ok(self.traverse_preorder().filter_map(ElementCast::to_root).find(|element| {
matches(selectors, element, None)
}))
}
}
}
/// https://dom.spec.whatwg.org/#scope-match-a-selectors-string
/// Get an iterator over all nodes which match a set of selectors
/// Be careful not to do anything which may manipulate the DOM tree whilst iterating, otherwise
/// the iterator may be invalidated
/// Be careful not to do anything which may manipulate the DOM tree
/// whilst iterating, otherwise the iterator may be invalidated.
#[allow(unsafe_code)]
pub unsafe fn query_selector_iter(&self, selectors: DOMString)
-> Fallible<QuerySelectorIterator> {
@ -832,9 +831,7 @@ impl Node {
Err(()) => Err(Syntax),
// Step 3.
Ok(selectors) => {
let root = self.ancestors().last();
let root = root.r().unwrap_or(self);
Ok(QuerySelectorIterator::new(root.traverse_preorder(), selectors))
Ok(QuerySelectorIterator::new(self.traverse_preorder(), selectors))
}
}
}
@ -1767,15 +1764,12 @@ impl Node {
let node_elem = ElementCast::to_ref(node).unwrap();
let copy_elem = ElementCast::to_ref(copy.r()).unwrap();
let window = document.r().window();
for ref attr in &*node_elem.attrs() {
let attr = attr.root();
let newattr =
Attr::new(window.r(),
attr.r().local_name().clone(), attr.r().value().clone(),
attr.r().name().clone(), attr.r().namespace().clone(),
attr.r().prefix().clone(), Some(copy_elem));
copy_elem.attrs_mut().push(JS::from_rooted(&newattr));
for attr in node_elem.attrs().iter().map(JS::root) {
copy_elem.push_new_attribute(attr.local_name().clone(),
attr.value().clone(),
attr.name().clone(),
attr.namespace().clone(),
attr.prefix().clone());
}
},
_ => ()

View File

@ -39,9 +39,9 @@ macro_rules! sizeof_checker (
// Update the sizes here
sizeof_checker!(size_event_target, EventTarget, 40);
sizeof_checker!(size_node, Node, 168);
sizeof_checker!(size_element, Element, 280);
sizeof_checker!(size_htmlelement, HTMLElement, 296);
sizeof_checker!(size_div, HTMLDivElement, 296);
sizeof_checker!(size_span, HTMLSpanElement, 296);
sizeof_checker!(size_element, Element, 304);
sizeof_checker!(size_htmlelement, HTMLElement, 320);
sizeof_checker!(size_div, HTMLDivElement, 320);
sizeof_checker!(size_span, HTMLSpanElement, 320);
sizeof_checker!(size_text, Text, 200);
sizeof_checker!(size_characterdata, CharacterData, 200);