Simplify rust-selectors API for attribute selectors

This commit is contained in:
Simon Sapin 2017-05-17 19:41:21 +02:00
parent 2ca2c2d2be
commit 83c7824fda
15 changed files with 447 additions and 480 deletions

View file

@ -86,9 +86,10 @@ use net_traits::request::CorsSettings;
use ref_filter_map::ref_filter_map;
use script_layout_interface::message::ReflowQueryType;
use script_thread::Runnable;
use selectors::attr::AttrSelectorOperation;
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, matches_selector_list};
use selectors::matching::{HAS_EDGE_CHILD_SELECTOR, HAS_SLOW_SELECTOR, HAS_SLOW_SELECTOR_LATER_SIBLINGS};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use selectors::parser::NamespaceConstraint;
use servo_atoms::Atom;
use std::ascii::AsciiExt;
use std::borrow::Cow;
@ -288,7 +289,7 @@ pub trait RawLayoutElementHelpers {
-> Option<&'a AttrValue>;
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
-> Option<&'a str>;
unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a str>;
unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue>;
}
#[inline]
@ -314,6 +315,7 @@ impl RawLayoutElementHelpers for Element {
})
}
#[inline]
unsafe fn get_attr_val_for_layout<'a>(&'a self, namespace: &Namespace, name: &LocalName)
-> Option<&'a str> {
get_attr_for_layout(self, namespace, name).map(|attr| {
@ -322,12 +324,12 @@ impl RawLayoutElementHelpers for Element {
}
#[inline]
unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a str> {
unsafe fn get_attr_vals_for_layout<'a>(&'a self, name: &LocalName) -> Vec<&'a AttrValue> {
let attrs = self.attrs.borrow_for_layout();
attrs.iter().filter_map(|attr| {
let attr = attr.to_layout();
if *name == attr.local_name_atom_forever() {
Some(attr.value_ref_forever())
Some(attr.value_forever())
} else {
None
}
@ -2352,37 +2354,9 @@ impl VirtualMethods for Element {
}
}
impl<'a> ::selectors::MatchAttrGeneric for Root<Element> {
impl<'a> ::selectors::Element for Root<Element> {
type Impl = SelectorImpl;
fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
where F: Fn(&str) -> bool
{
use ::selectors::Element;
let local_name = {
if self.is_html_element_in_html_document() {
&attr.lower_name
} else {
&attr.name
}
};
match attr.namespace {
NamespaceConstraint::Specific(ref ns) => {
self.get_attribute(&ns.url, local_name)
.map_or(false, |attr| {
test(&attr.value())
})
},
NamespaceConstraint::Any => {
self.attrs.borrow().iter().any(|attr| {
attr.local_name() == local_name && test(&attr.value())
})
}
}
}
}
impl<'a> ::selectors::Element for Root<Element> {
fn parent_element(&self) -> Option<Root<Element>> {
self.upcast::<Node>().GetParentElement()
}
@ -2412,6 +2386,25 @@ impl<'a> ::selectors::Element for Root<Element> {
self.node.following_siblings().filter_map(Root::downcast).next()
}
fn attr_matches(&self,
ns: &NamespaceConstraint<SelectorImpl>,
local_name: &LocalName,
operation: &AttrSelectorOperation<SelectorImpl>)
-> bool {
match *ns {
NamespaceConstraint::Specific(ref ns) => {
self.get_attribute(&ns.url, local_name)
.map_or(false, |attr| attr.value().eval_selector(operation))
}
NamespaceConstraint::Any => {
self.attrs.borrow().iter().any(|attr| {
attr.local_name() == local_name &&
attr.value().eval_selector(operation)
})
}
}
}
fn is_root(&self) -> bool {
match self.node.GetParentNode() {
None => false,

View file

@ -50,8 +50,9 @@ use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, Truste
use script_layout_interface::{OpaqueStyleAndLayoutData, PartialPersistentLayoutData};
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
use selectors::attr::AttrSelectorOperation;
use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::parser::{AttrSelector, NamespaceConstraint};
use selectors::parser::NamespaceConstraint;
use servo_atoms::Atom;
use servo_url::ServoUrl;
use std::fmt;
@ -509,6 +510,13 @@ impl<'le> ServoLayoutElement<'le> {
}
}
#[inline]
fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue> {
unsafe {
(*self.element.unsafe_get()).get_attr_for_layout(namespace, name)
}
}
#[inline]
fn get_attr(&self, namespace: &Namespace, name: &LocalName) -> Option<&str> {
unsafe {
@ -558,32 +566,9 @@ fn as_element<'le>(node: LayoutJS<Node>) -> Option<ServoLayoutElement<'le>> {
node.downcast().map(ServoLayoutElement::from_layout_js)
}
impl<'le> ::selectors::MatchAttrGeneric for ServoLayoutElement<'le> {
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
type Impl = SelectorImpl;
fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
where F: Fn(&str) -> bool {
use ::selectors::Element;
let name = if self.is_html_element_in_html_document() {
&attr.lower_name
} else {
&attr.name
};
match attr.namespace {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr(&ns.url, name).map_or(false, |attr| test(attr))
},
NamespaceConstraint::Any => {
let attrs = unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(name)
};
attrs.iter().any(|attr| test(*attr))
}
}
}
}
impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
fn parent_element(&self) -> Option<ServoLayoutElement<'le>> {
unsafe {
self.element.upcast().parent_node_ref().and_then(as_element)
@ -620,6 +605,25 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
None
}
fn attr_matches(&self,
ns: &NamespaceConstraint<SelectorImpl>,
local_name: &LocalName,
operation: &AttrSelectorOperation<SelectorImpl>)
-> bool {
match *ns {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr_enum(&ns.url, local_name)
.map_or(false, |value| value.eval_selector(operation))
}
NamespaceConstraint::Any => {
let values = unsafe {
(*self.element.unsafe_get()).get_attr_vals_for_layout(local_name)
};
values.iter().any(|value| value.eval_selector(operation))
}
}
}
fn is_root(&self) -> bool {
match self.as_node().parent_node() {
None => false,
@ -1075,6 +1079,10 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
self.element
}
fn get_attr_enum(&self, namespace: &Namespace, name: &LocalName) -> Option<&AttrValue> {
self.element.get_attr_enum(namespace, name)
}
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &LocalName) -> Option<&'a str> {
self.element.get_attr(namespace, name)
}
@ -1096,25 +1104,9 @@ impl<'le> ThreadSafeLayoutElement for ServoThreadSafeLayoutElement<'le> {
///
/// Note that the element implementation is needed only for selector matching,
/// not for inheritance (styles are inherited appropiately).
impl<'le> ::selectors::MatchAttrGeneric for ServoThreadSafeLayoutElement<'le> {
impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
type Impl = SelectorImpl;
fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
where F: Fn(&str) -> bool {
match attr.namespace {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr(&ns.url, &attr.name).map_or(false, |attr| test(attr))
},
NamespaceConstraint::Any => {
unsafe {
(*self.element.element.unsafe_get()).get_attr_vals_for_layout(&attr.name).iter()
.any(|attr| test(*attr))
}
}
}
}
}
impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
fn parent_element(&self) -> Option<Self> {
warn!("ServoThreadSafeLayoutElement::parent_element called");
None
@ -1166,6 +1158,25 @@ impl<'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> {
false
}
fn attr_matches(&self,
ns: &NamespaceConstraint<SelectorImpl>,
local_name: &LocalName,
operation: &AttrSelectorOperation<SelectorImpl>)
-> bool {
match *ns {
NamespaceConstraint::Specific(ref ns) => {
self.get_attr_enum(&ns.url, local_name)
.map_or(false, |value| value.eval_selector(operation))
}
NamespaceConstraint::Any => {
let values = unsafe {
(*self.element.element.unsafe_get()).get_attr_vals_for_layout(local_name)
};
values.iter().any(|v| v.eval_selector(operation))
}
}
}
fn match_non_ts_pseudo_class<F>(&self,
_: &NonTSPseudoClass,
_: &mut MatchingContext,