mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +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
|
@ -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> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue