mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Restore perf improvement from #1554
Lower-case attribute names when parsing selectors rather than when matching. This avoid one allocation in matching code.
This commit is contained in:
parent
b8556afeeb
commit
5b0768c4f6
5 changed files with 34 additions and 37 deletions
|
@ -14,7 +14,6 @@
|
||||||
//! (2) Layout is not allowed to see anything with `Abstract` in the name, because it could hang
|
//! (2) Layout is not allowed to see anything with `Abstract` in the name, because it could hang
|
||||||
//! onto these objects and cause use-after-free.
|
//! onto these objects and cause use-after-free.
|
||||||
|
|
||||||
use std::ascii::StrAsciiExt;
|
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId};
|
use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId};
|
||||||
use script::dom::element::{HTMLLinkElementTypeId};
|
use script::dom::element::{HTMLLinkElementTypeId};
|
||||||
|
@ -26,7 +25,7 @@ use script::dom::node::{AbstractNode, DocumentNodeTypeId, ElementNodeTypeId, Nod
|
||||||
use script::dom::text::Text;
|
use script::dom::text::Text;
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use style::{PropertyDeclarationBlock, TElement, TNode};
|
use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector};
|
||||||
|
|
||||||
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
||||||
/// only ever see these and must never see instances of `AbstractNode`.
|
/// only ever see these and must never see instances of `AbstractNode`.
|
||||||
|
@ -282,6 +281,21 @@ impl<'ln> TNode<LayoutElement<'ln>> for LayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool {
|
||||||
|
self.with_element(|element| {
|
||||||
|
let name = if element.element.html_element_in_html_document() {
|
||||||
|
attr.lower_name.as_slice()
|
||||||
|
} else {
|
||||||
|
attr.name.as_slice()
|
||||||
|
};
|
||||||
|
// FIXME: avoid .clone() here? See #1367
|
||||||
|
match element.get_attr(attr.namespace.clone(), name) {
|
||||||
|
Some(value) => test(value),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutNodeChildrenIterator<'a> {
|
pub struct LayoutNodeChildrenIterator<'a> {
|
||||||
|
@ -379,33 +393,22 @@ impl<'le> LayoutElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> TElement for LayoutElement<'le> {
|
impl<'le> TElement for LayoutElement<'le> {
|
||||||
|
#[inline]
|
||||||
fn get_local_name<'a>(&'a self) -> &'a str {
|
fn get_local_name<'a>(&'a self) -> &'a str {
|
||||||
self.element.tag_name.as_slice()
|
self.element.tag_name.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn get_namespace_url<'a>(&'a self) -> &'a str {
|
fn get_namespace_url<'a>(&'a self) -> &'a str {
|
||||||
self.element.namespace.to_str().unwrap_or("")
|
self.element.namespace.to_str().unwrap_or("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn get_attr(&self, ns_url: Option<~str>, name: &str) -> Option<&'static str> {
|
fn get_attr(&self, ns_url: Option<~str>, name: &str) -> Option<&'static str> {
|
||||||
let namespace = Namespace::from_str(ns_url);
|
let namespace = Namespace::from_str(ns_url);
|
||||||
unsafe { self.element.get_attr_val_for_layout(namespace, name) }
|
unsafe { self.element.get_attr_val_for_layout(namespace, name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_attr(&self, ns_url: Option<~str>, name: &str, test: &|&str| -> bool) -> bool {
|
|
||||||
let temp;
|
|
||||||
let name = if self.element.html_element_in_html_document() {
|
|
||||||
temp = name.to_ascii_lower();
|
|
||||||
temp.as_slice()
|
|
||||||
} else {
|
|
||||||
name
|
|
||||||
};
|
|
||||||
match self.get_attr(ns_url, name) {
|
|
||||||
Some(value) => (*test)(value),
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_link(&self) -> Option<~str> {
|
fn get_link(&self) -> Option<~str> {
|
||||||
// FIXME: This is HTML only.
|
// FIXME: This is HTML only.
|
||||||
match self.element.node.type_id {
|
match self.element.node.type_id {
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
//! Traits that nodes must implement. Breaks the otherwise-cyclic dependency between layout and
|
||||||
//! style.
|
//! style.
|
||||||
|
|
||||||
|
use selectors::AttrSelector;
|
||||||
|
|
||||||
|
|
||||||
pub trait TNode<E:TElement> : Clone {
|
pub trait TNode<E:TElement> : Clone {
|
||||||
fn parent_node(&self) -> Option<Self>;
|
fn parent_node(&self) -> Option<Self>;
|
||||||
fn prev_sibling(&self) -> Option<Self>;
|
fn prev_sibling(&self) -> Option<Self>;
|
||||||
|
@ -15,11 +18,12 @@ pub trait TNode<E:TElement> : Clone {
|
||||||
|
|
||||||
/// FIXME(pcwalton): This should not use the `with` pattern.
|
/// FIXME(pcwalton): This should not use the `with` pattern.
|
||||||
fn with_element<'a, R>(&self, f: |&E| -> R) -> R;
|
fn with_element<'a, R>(&self, f: |&E| -> R) -> R;
|
||||||
|
|
||||||
|
fn match_attr(&self, attr: &AttrSelector, test: |&str| -> bool) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TElement {
|
pub trait TElement {
|
||||||
fn get_attr(&self, namespace: Option<~str>, attr: &str) -> Option<&'static str>;
|
fn get_attr(&self, namespace: Option<~str>, attr: &str) -> Option<&'static str>;
|
||||||
fn match_attr(&self, ns_url: Option<~str>, name: &str, test: &|&str| -> bool) -> bool;
|
|
||||||
fn get_link(&self) -> Option<~str>;
|
fn get_link(&self) -> Option<~str>;
|
||||||
fn get_local_name<'a>(&'a self) -> &'a str;
|
fn get_local_name<'a>(&'a self) -> &'a str;
|
||||||
fn get_namespace_url<'a>(&'a self) -> &'a str;
|
fn get_namespace_url<'a>(&'a self) -> &'a str;
|
||||||
|
|
|
@ -513,22 +513,22 @@ fn matches_simple_selector<E:TElement,N:TNode<E>>(selector: &SimpleSelector, ele
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
AttrExists(ref attr) => match_attribute(attr, element, |_| true),
|
AttrExists(ref attr) => element.match_attr(attr, |_| true),
|
||||||
AttrEqual(ref attr, ref value) => match_attribute(attr, element, |v| v == value.as_slice()),
|
AttrEqual(ref attr, ref value) => element.match_attr(attr, |v| v == value.as_slice()),
|
||||||
AttrIncludes(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
AttrIncludes(ref attr, ref value) => element.match_attr(attr, |attr_value| {
|
||||||
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
attr_value.split(SELECTOR_WHITESPACE).any(|v| v == value.as_slice())
|
||||||
}),
|
}),
|
||||||
AttrDashMatch(ref attr, ref value, ref dashing_value)
|
AttrDashMatch(ref attr, ref value, ref dashing_value)
|
||||||
=> match_attribute(attr, element, |attr_value| {
|
=> element.match_attr(attr, |attr_value| {
|
||||||
attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice())
|
attr_value == value.as_slice() || attr_value.starts_with(dashing_value.as_slice())
|
||||||
}),
|
}),
|
||||||
AttrPrefixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
AttrPrefixMatch(ref attr, ref value) => element.match_attr(attr, |attr_value| {
|
||||||
attr_value.starts_with(value.as_slice())
|
attr_value.starts_with(value.as_slice())
|
||||||
}),
|
}),
|
||||||
AttrSubstringMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
AttrSubstringMatch(ref attr, ref value) => element.match_attr(attr, |attr_value| {
|
||||||
attr_value.contains(value.as_slice())
|
attr_value.contains(value.as_slice())
|
||||||
}),
|
}),
|
||||||
AttrSuffixMatch(ref attr, ref value) => match_attribute(attr, element, |attr_value| {
|
AttrSuffixMatch(ref attr, ref value) => element.match_attr(attr, |attr_value| {
|
||||||
attr_value.ends_with(value.as_slice())
|
attr_value.ends_with(value.as_slice())
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -696,18 +696,6 @@ fn matches_last_child<E:TElement,N:TNode<E>>(element: &N) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn match_attribute<E:TElement,
|
|
||||||
N:TNode<E>>(
|
|
||||||
attr: &AttrSelector,
|
|
||||||
element: &N,
|
|
||||||
test: |&str| -> bool)
|
|
||||||
-> bool {
|
|
||||||
element.with_element(|element: &E| {
|
|
||||||
// FIXME: avoid .clone() here? See #1367
|
|
||||||
element.match_attr(attr.namespace.clone(), attr.name, &test)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
|
@ -88,6 +88,7 @@ pub enum SimpleSelector {
|
||||||
#[deriving(Eq, Clone)]
|
#[deriving(Eq, Clone)]
|
||||||
pub struct AttrSelector {
|
pub struct AttrSelector {
|
||||||
name: ~str,
|
name: ~str,
|
||||||
|
lower_name: ~str,
|
||||||
namespace: Option<~str>,
|
namespace: Option<~str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,6 +424,7 @@ fn parse_attribute_selector(content: ~[ComponentValue], namespaces: &NamespaceMa
|
||||||
QualifiedName(_, None) => fail!("Implementation error, this should not happen."),
|
QualifiedName(_, None) => fail!("Implementation error, this should not happen."),
|
||||||
QualifiedName(namespace, Some(local_name)) => AttrSelector {
|
QualifiedName(namespace, Some(local_name)) => AttrSelector {
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
lower_name: local_name.to_ascii_lower(),
|
||||||
name: local_name,
|
name: local_name,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub use properties::{cascade, PropertyDeclaration, ComputedValues, computed_valu
|
||||||
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
pub use properties::{PropertyDeclarationBlock, parse_style_attribute}; // Style attributes
|
||||||
pub use errors::with_errors_silenced;
|
pub use errors::with_errors_silenced;
|
||||||
pub use node::{TElement, TNode};
|
pub use node::{TElement, TNode};
|
||||||
pub use selectors::{PseudoElement, Before, After};
|
pub use selectors::{PseudoElement, Before, After, AttrSelector};
|
||||||
|
|
||||||
mod stylesheets;
|
mod stylesheets;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue