mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
Simplify rust-selectors API for attribute selectors
This commit is contained in:
parent
2ca2c2d2be
commit
83c7824fda
15 changed files with 447 additions and 480 deletions
|
@ -12,6 +12,8 @@ use cssparser::{self, Color, RGBA};
|
|||
use euclid::num::Zero;
|
||||
use num_traits::ToPrimitive;
|
||||
use properties::PropertyDeclarationBlock;
|
||||
use selector_parser::SelectorImpl;
|
||||
use selectors::attr::AttrSelectorOperation;
|
||||
use servo_url::ServoUrl;
|
||||
use shared_lock::Locked;
|
||||
use std::ascii::AsciiExt;
|
||||
|
@ -349,6 +351,12 @@ impl AttrValue {
|
|||
panic!("Uint not found");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_selector(&self, selector: &AttrSelectorOperation<SelectorImpl>) -> bool {
|
||||
// FIXME(SimonSapin) this can be more efficient by matching on `(self, selector)` variants
|
||||
// and doing Atom comparisons instead of string comparisons where possible.
|
||||
selector.eval_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Deref for AttrValue {
|
||||
|
|
|
@ -8,14 +8,15 @@
|
|||
use dom::TElement;
|
||||
use element_state::ElementState;
|
||||
use gecko::snapshot_helpers;
|
||||
use gecko::wrapper::{AttrSelectorHelpers, GeckoElement};
|
||||
use gecko::wrapper::{NamespaceConstraintHelpers, GeckoElement};
|
||||
use gecko_bindings::bindings;
|
||||
use gecko_bindings::structs::ServoElementSnapshot;
|
||||
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
|
||||
use gecko_bindings::structs::ServoElementSnapshotTable;
|
||||
use restyle_hints::ElementSnapshot;
|
||||
use selector_parser::SelectorImpl;
|
||||
use selectors::parser::AttrSelector;
|
||||
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity};
|
||||
use selectors::parser::NamespaceConstraint;
|
||||
use string_cache::Atom;
|
||||
|
||||
/// A snapshot of a Gecko element.
|
||||
|
@ -47,11 +48,6 @@ impl SnapshotMap {
|
|||
}
|
||||
|
||||
impl GeckoElementSnapshot {
|
||||
#[inline]
|
||||
fn is_html_element_in_html_document(&self) -> bool {
|
||||
self.mIsHTMLElementInHTMLDocument
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_any(&self, flags: Flags) -> bool {
|
||||
(self.mContains as u8 & flags as u8) != 0
|
||||
|
@ -60,76 +56,67 @@ impl GeckoElementSnapshot {
|
|||
fn as_ptr(&self) -> *const Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ::selectors::MatchAttr for GeckoElementSnapshot {
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
|
||||
/// selectors::Element::attr_matches
|
||||
pub fn attr_matches(&self,
|
||||
ns: &NamespaceConstraint<SelectorImpl>,
|
||||
local_name: &Atom,
|
||||
operation: &AttrSelectorOperation<SelectorImpl>)
|
||||
-> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotHasAttr(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()))
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrEquals(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ false)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrEquals(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ true)
|
||||
}
|
||||
}
|
||||
fn match_attr_includes(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrIncludes(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_dash(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrDashEquals(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_prefix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasPrefix(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_substring(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasSubstring(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_suffix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_SnapshotAttrHasSuffix(self,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
match *operation {
|
||||
AttrSelectorOperation::Exists => {
|
||||
bindings:: Gecko_SnapshotHasAttr(self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr())
|
||||
}
|
||||
AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
|
||||
let ignore_case = match case_sensitivity {
|
||||
CaseSensitivity::CaseSensitive => false,
|
||||
CaseSensitivity::AsciiCaseInsensitive => true,
|
||||
};
|
||||
// FIXME: case sensitivity for operators other than Equal
|
||||
match operator {
|
||||
AttrSelectorOperator::Equal => bindings::Gecko_SnapshotAttrEquals(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
ignore_case
|
||||
),
|
||||
AttrSelectorOperator::Includes => bindings::Gecko_SnapshotAttrIncludes(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::DashMatch => bindings::Gecko_SnapshotAttrDashEquals(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Prefix => bindings::Gecko_SnapshotAttrHasPrefix(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Suffix => bindings::Gecko_SnapshotAttrHasSuffix(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Substring => bindings::Gecko_SnapshotAttrHasSubstring(
|
||||
self,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,9 @@ use properties::style_structs::Font;
|
|||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||
use selector_parser::ElementExt;
|
||||
use selectors::Element;
|
||||
use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator, CaseSensitivity};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||
use selectors::parser::{AttrSelector, NamespaceConstraint};
|
||||
use selectors::parser::NamespaceConstraint;
|
||||
use shared_lock::Locked;
|
||||
use sink::Push;
|
||||
use std::cell::RefCell;
|
||||
|
@ -1082,6 +1083,8 @@ impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
|
|||
}
|
||||
|
||||
impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn parent_element(&self) -> Option<Self> {
|
||||
let parent_node = self.as_node().parent_node();
|
||||
parent_node.and_then(|n| n.as_element())
|
||||
|
@ -1136,6 +1139,68 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
None
|
||||
}
|
||||
|
||||
fn attr_matches(&self,
|
||||
ns: &NamespaceConstraint<SelectorImpl>,
|
||||
local_name: &Atom,
|
||||
operation: &AttrSelectorOperation<SelectorImpl>)
|
||||
-> bool {
|
||||
unsafe {
|
||||
match *operation {
|
||||
AttrSelectorOperation::Exists => {
|
||||
bindings::Gecko_HasAttr(self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr())
|
||||
}
|
||||
AttrSelectorOperation::WithValue { operator, case_sensitivity, expected_value } => {
|
||||
let ignore_case = match case_sensitivity {
|
||||
CaseSensitivity::CaseSensitive => false,
|
||||
CaseSensitivity::AsciiCaseInsensitive => true,
|
||||
};
|
||||
// FIXME: case sensitivity for operators other than Equal
|
||||
match operator {
|
||||
AttrSelectorOperator::Equal => bindings::Gecko_AttrEquals(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
ignore_case
|
||||
),
|
||||
AttrSelectorOperator::Includes => bindings::Gecko_AttrIncludes(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::DashMatch => bindings::Gecko_AttrDashEquals(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Prefix => bindings::Gecko_AttrHasPrefix(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Suffix => bindings::Gecko_AttrHasSuffix(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
AttrSelectorOperator::Substring => bindings::Gecko_AttrHasSubstring(
|
||||
self.0,
|
||||
ns.atom_or_null(),
|
||||
local_name.as_ptr(),
|
||||
expected_value.as_ptr(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_root(&self) -> bool {
|
||||
unsafe {
|
||||
Gecko_IsRootElement(self.0)
|
||||
|
@ -1343,99 +1408,18 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
}
|
||||
|
||||
/// A few helpers to help with attribute selectors and snapshotting.
|
||||
pub trait AttrSelectorHelpers {
|
||||
pub trait NamespaceConstraintHelpers {
|
||||
/// Returns the namespace of the selector, or null otherwise.
|
||||
fn ns_or_null(&self) -> *mut nsIAtom;
|
||||
/// Returns the proper selector name depending on whether the requesting
|
||||
/// element is an HTML element in an HTML document or not.
|
||||
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom;
|
||||
fn atom_or_null(&self) -> *mut nsIAtom;
|
||||
}
|
||||
|
||||
impl AttrSelectorHelpers for AttrSelector<SelectorImpl> {
|
||||
fn ns_or_null(&self) -> *mut nsIAtom {
|
||||
match self.namespace {
|
||||
impl NamespaceConstraintHelpers for NamespaceConstraint<SelectorImpl> {
|
||||
fn atom_or_null(&self) -> *mut nsIAtom {
|
||||
match *self {
|
||||
NamespaceConstraint::Any => ptr::null_mut(),
|
||||
NamespaceConstraint::Specific(ref ns) => ns.url.0.as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom {
|
||||
if is_html_element_in_html_document {
|
||||
self.lower_name.as_ptr()
|
||||
} else {
|
||||
self.name.as_ptr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector<Self::Impl>) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_HasAttr(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()))
|
||||
}
|
||||
}
|
||||
fn match_attr_equals(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ false)
|
||||
}
|
||||
}
|
||||
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr(),
|
||||
/* ignoreCase = */ true)
|
||||
}
|
||||
}
|
||||
fn match_attr_includes(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrIncludes(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_dash(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrDashEquals(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_prefix(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrHasPrefix(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_substring(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrHasSubstring(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
fn match_attr_suffix(&self, attr: &AttrSelector<Self::Impl>, value: &Atom) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_AttrHasSuffix(self.0,
|
||||
attr.ns_or_null(),
|
||||
attr.select_name(self.is_html_element_in_html_document()),
|
||||
value.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> ElementExt for GeckoElement<'le> {
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use Atom;
|
||||
use LocalName;
|
||||
use dom::TElement;
|
||||
use element_state::*;
|
||||
#[cfg(feature = "gecko")]
|
||||
use gecko_bindings::structs::nsRestyleHint;
|
||||
#[cfg(feature = "servo")]
|
||||
use heapsize::HeapSizeOf;
|
||||
use selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap};
|
||||
use selectors::{Element, MatchAttr};
|
||||
use selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl, Snapshot, SnapshotMap};
|
||||
use selectors::Element;
|
||||
use selectors::attr::AttrSelectorOperation;
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode};
|
||||
use selectors::matching::matches_selector;
|
||||
use selectors::parser::{AttrSelector, Combinator, Component, Selector};
|
||||
use selectors::parser::{SelectorInner, SelectorMethods};
|
||||
use selectors::parser::{Combinator, Component, Selector};
|
||||
use selectors::parser::{SelectorInner, SelectorMethods, NamespaceConstraint};
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Borrow;
|
||||
|
@ -170,7 +172,7 @@ impl HeapSizeOf for RestyleHint {
|
|||
/// still need to take the ElementWrapper approach for attribute-dependent
|
||||
/// style. So we do it the same both ways for now to reduce complexity, but it's
|
||||
/// worth measuring the performance impact (if any) of the mStateMask approach.
|
||||
pub trait ElementSnapshot : Sized + MatchAttr<Impl=SelectorImpl> {
|
||||
pub trait ElementSnapshot : Sized {
|
||||
/// The state of the snapshot, if any.
|
||||
fn state(&self) -> Option<ElementState>;
|
||||
|
||||
|
@ -242,90 +244,6 @@ impl<'a, E> ElementWrapper<'a, E>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, E> MatchAttr for ElementWrapper<'a, E>
|
||||
where E: TElement,
|
||||
{
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_has(attr),
|
||||
_ => self.element.match_attr_has(attr)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_equals(attr, value),
|
||||
_ => self.element.match_attr_equals(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_equals_ignore_ascii_case(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_equals_ignore_ascii_case(attr, value),
|
||||
_ => self.element.match_attr_equals_ignore_ascii_case(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_includes(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_includes(attr, value),
|
||||
_ => self.element.match_attr_includes(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_dash(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_dash(attr, value),
|
||||
_ => self.element.match_attr_dash(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_prefix(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_prefix(attr, value),
|
||||
_ => self.element.match_attr_prefix(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_substring(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_substring(attr, value),
|
||||
_ => self.element.match_attr_substring(attr, value)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attr_suffix(&self,
|
||||
attr: &AttrSelector<SelectorImpl>,
|
||||
value: &AttrValue) -> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
=> snapshot.match_attr_suffix(attr, value),
|
||||
_ => self.element.match_attr_suffix(attr, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn dir_selector_to_state(s: &[u16]) -> ElementState {
|
||||
// Jump through some hoops to deal with our Box<[u16]> thing.
|
||||
|
@ -345,6 +263,8 @@ fn dir_selector_to_state(s: &[u16]) -> ElementState {
|
|||
impl<'a, E> Element for ElementWrapper<'a, E>
|
||||
where E: TElement,
|
||||
{
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn match_non_ts_pseudo_class<F>(&self,
|
||||
pseudo_class: &NonTSPseudoClass,
|
||||
context: &mut MatchingContext,
|
||||
|
@ -450,6 +370,19 @@ impl<'a, E> Element for ElementWrapper<'a, E>
|
|||
self.element.get_namespace()
|
||||
}
|
||||
|
||||
fn attr_matches(&self,
|
||||
ns: &NamespaceConstraint<Self::Impl>,
|
||||
local_name: &LocalName,
|
||||
operation: &AttrSelectorOperation<Self::Impl>)
|
||||
-> bool {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs() => {
|
||||
snapshot.attr_matches(ns, local_name, operation)
|
||||
}
|
||||
_ => self.element.attr_matches(ns, local_name, operation)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_id(&self) -> Option<Atom> {
|
||||
match self.snapshot() {
|
||||
Some(snapshot) if snapshot.has_attrs()
|
||||
|
|
|
@ -14,9 +14,10 @@ use element_state::ElementState;
|
|||
use fnv::FnvHashMap;
|
||||
use restyle_hints::ElementSnapshot;
|
||||
use selector_parser::{ElementExt, PseudoElementCascadeType, SelectorParser};
|
||||
use selectors::{Element, MatchAttrGeneric};
|
||||
use selectors::{Element};
|
||||
use selectors::attr::AttrSelectorOperation;
|
||||
use selectors::matching::{MatchingContext, MatchingMode};
|
||||
use selectors::parser::{AttrSelector, SelectorMethods};
|
||||
use selectors::parser::{SelectorMethods, NamespaceConstraint};
|
||||
use selectors::visitor::SelectorVisitor;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
@ -519,10 +520,10 @@ impl ServoElementSnapshot {
|
|||
.map(|&(_, ref v)| v)
|
||||
}
|
||||
|
||||
fn get_attr_ignore_ns(&self, name: &LocalName) -> Option<&AttrValue> {
|
||||
fn any_attr_ignore_ns<F>(&self, name: &LocalName, mut f: F) -> bool
|
||||
where F: FnMut(&AttrValue) -> bool {
|
||||
self.attrs.as_ref().unwrap().iter()
|
||||
.find(|&&(ref ident, _)| ident.local_name == *name)
|
||||
.map(|&(_, ref v)| v)
|
||||
.any(|&(ref ident, ref v)| ident.local_name == *name && f(v))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,19 +556,23 @@ impl ElementSnapshot for ServoElementSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
impl MatchAttrGeneric for ServoElementSnapshot {
|
||||
type Impl = SelectorImpl;
|
||||
|
||||
fn match_attr<F>(&self, attr: &AttrSelector<SelectorImpl>, test: F) -> bool
|
||||
where F: Fn(&str) -> bool
|
||||
{
|
||||
impl ServoElementSnapshot {
|
||||
/// selectors::Element::attr_matches
|
||||
pub fn attr_matches(&self,
|
||||
ns: &NamespaceConstraint<SelectorImpl>,
|
||||
local_name: &LocalName,
|
||||
operation: &AttrSelectorOperation<SelectorImpl>)
|
||||
-> bool {
|
||||
use selectors::parser::NamespaceConstraint;
|
||||
let html = self.is_html_element_in_html_document;
|
||||
let local_name = if html { &attr.lower_name } else { &attr.name };
|
||||
match attr.namespace {
|
||||
NamespaceConstraint::Specific(ref ns) => self.get_attr(&ns.url, local_name),
|
||||
NamespaceConstraint::Any => self.get_attr_ignore_ns(local_name),
|
||||
}.map_or(false, |v| test(v))
|
||||
match *ns {
|
||||
NamespaceConstraint::Specific(ref ns) => {
|
||||
self.get_attr(&ns.url, local_name)
|
||||
.map_or(false, |value| value.eval_selector(operation))
|
||||
}
|
||||
NamespaceConstraint::Any => {
|
||||
self.any_attr_ignore_ns(local_name, |value| value.eval_selector(operation))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue