--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1038,16 +1038,31 @@ AttrHasSuffix(Implementor* aElement, nsA
aValue->ToString(str);
WITH_COMPARATOR(aIgnoreCase, c,
StringEndsWith(str, nsDependentAtomString(aStr), c))
};
return DoMatch(aElement, aNS, aName, match);
}
/**
+ * Returns whether an element contains a class in its class list or not.
+ */
+template <typename Implementor>
+static bool
+HasClass(Implementor* aElement, nsAtom* aClass, bool aIgnoreCase)
+{
+ const nsAttrValue* attr = aElement->DoGetClasses();
+ if (!attr) {
+ return false;
+ }
+
+ return attr->Contains(aClass, aIgnoreCase ? eIgnoreCase : eCaseMatters);
+}
+
+/**
* Gets the class or class list (if any) of the implementor. The calling
* convention here is rather hairy, and is optimized for getting Servo the
* information it needs for hot calls.
*
* The return value indicates the number of classes. If zero, neither outparam
* is valid. If one, the class_ outparam is filled with the atom of the class.
* If two or more, the classList outparam is set to point to an array of atoms
* representing the class list.
@@ -1106,63 +1121,68 @@ ClassOrClassList(Implementor* aElement,
RefPtr<nsAtom>* elements = atomArray->Elements();
nsAtom** rawElements = reinterpret_cast<nsAtom**>(elements);
*aClassList = rawElements;
return atomArray->Length();
}
#define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
- nsAtom* prefix_##AtomAttrValue(implementor_ aElement, nsAtom* aName) \
+ nsAtom* prefix_##AtomAttrValue(implementor_ aElement, nsAtom* aName) \
{ \
return AtomAttrValue(aElement, aName); \
} \
- nsAtom* prefix_##LangValue(implementor_ aElement) \
+ nsAtom* prefix_##LangValue(implementor_ aElement) \
{ \
return LangValue(aElement); \
} \
- bool prefix_##HasAttr(implementor_ aElement, nsAtom* aNS, nsAtom* aName) \
+ bool prefix_##HasAttr(implementor_ aElement, nsAtom* aNS, nsAtom* aName) \
{ \
return HasAttr(aElement, aNS, aName); \
} \
- bool prefix_##AttrEquals(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
+ bool prefix_##AttrEquals(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrEquals(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- bool prefix_##AttrDashEquals(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
+ bool prefix_##AttrDashEquals(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrDashEquals(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- bool prefix_##AttrIncludes(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
+ bool prefix_##AttrIncludes(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrIncludes(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- bool prefix_##AttrHasSubstring(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase)\
+ bool prefix_##AttrHasSubstring(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrHasSubstring(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- bool prefix_##AttrHasPrefix(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
+ bool prefix_##AttrHasPrefix(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrHasPrefix(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- bool prefix_##AttrHasSuffix(implementor_ aElement, nsAtom* aNS, \
- nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
+ bool prefix_##AttrHasSuffix(implementor_ aElement, nsAtom* aNS, \
+ nsAtom* aName, nsAtom* aStr, bool aIgnoreCase) \
{ \
return AttrHasSuffix(aElement, aNS, aName, aStr, aIgnoreCase); \
} \
- uint32_t prefix_##ClassOrClassList(implementor_ aElement, nsAtom** aClass, \
- nsAtom*** aClassList) \
+ uint32_t prefix_##ClassOrClassList(implementor_ aElement, nsAtom** aClass, \
+ nsAtom*** aClassList) \
{ \
return ClassOrClassList(aElement, aClass, aClassList); \
- }
+ } \
+ bool prefix_##HasClass(implementor_ aElement, nsAtom* aClass, bool aIgnoreCase)\
+ { \
+ return HasClass(aElement, aClass, aIgnoreCase); \
+ } \
+
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, const ServoElementSnapshot*)
#undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
nsAtom*
Gecko_Atomize(const char* aString, uint32_t aLength)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -191,34 +191,36 @@ bool Gecko_MatchesElement(mozilla::CSSPs
bool Gecko_MatchLang(RawGeckoElementBorrowed element,
nsAtom* override_lang, bool has_override_lang,
const char16_t* value);
nsAtom* Gecko_GetXMLLangValue(RawGeckoElementBorrowed element);
nsIDocument::DocumentTheme Gecko_GetDocumentLWTheme(const nsIDocument* aDocument);
// Attributes.
#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
- nsAtom* prefix_##AtomAttrValue(implementor_ element, nsAtom* attribute); \
- nsAtom* prefix_##LangValue(implementor_ element); \
- bool prefix_##HasAttr(implementor_ element, nsAtom* ns, nsAtom* name); \
- bool prefix_##AttrEquals(implementor_ element, nsAtom* ns, nsAtom* name, \
- nsAtom* str, bool ignoreCase); \
- bool prefix_##AttrDashEquals(implementor_ element, nsAtom* ns, \
- nsAtom* name, nsAtom* str, bool ignore_case);\
- bool prefix_##AttrIncludes(implementor_ element, nsAtom* ns, \
- nsAtom* name, nsAtom* str, bool ignore_case); \
- bool prefix_##AttrHasSubstring(implementor_ element, nsAtom* ns, \
- nsAtom* name, nsAtom* str, \
+ nsAtom* prefix_##AtomAttrValue(implementor_ element, nsAtom* attribute); \
+ nsAtom* prefix_##LangValue(implementor_ element); \
+ bool prefix_##HasAttr(implementor_ element, nsAtom* ns, nsAtom* name); \
+ bool prefix_##AttrEquals(implementor_ element, nsAtom* ns, nsAtom* name, \
+ nsAtom* str, bool ignoreCase); \
+ bool prefix_##AttrDashEquals(implementor_ element, nsAtom* ns, \
+ nsAtom* name, nsAtom* str, bool ignore_case); \
+ bool prefix_##AttrIncludes(implementor_ element, nsAtom* ns, \
+ nsAtom* name, nsAtom* str, bool ignore_case); \
+ bool prefix_##AttrHasSubstring(implementor_ element, nsAtom* ns, \
+ nsAtom* name, nsAtom* str, \
bool ignore_case); \
- bool prefix_##AttrHasPrefix(implementor_ element, nsAtom* ns, \
- nsAtom* name, nsAtom* str, bool ignore_case); \
- bool prefix_##AttrHasSuffix(implementor_ element, nsAtom* ns, \
- nsAtom* name, nsAtom* str, bool ignore_case); \
- uint32_t prefix_##ClassOrClassList(implementor_ element, nsAtom** class_, \
- nsAtom*** classList);
+ bool prefix_##AttrHasPrefix(implementor_ element, nsAtom* ns, \
+ nsAtom* name, nsAtom* str, bool ignore_case); \
+ bool prefix_##AttrHasSuffix(implementor_ element, nsAtom* ns, \
+ nsAtom* name, nsAtom* str, bool ignore_case); \
+ uint32_t prefix_##ClassOrClassList(implementor_ element, nsAtom** class_, \
+ nsAtom*** classList); \
+ bool prefix_##HasClass(implementor_ element, nsAtom* class_, \
+ bool ignore_case);
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
const ServoElementSnapshot*)
#undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
// Style attributes.
--- a/servo/components/style/gecko/snapshot.rs
+++ b/servo/components/style/gecko/snapshot.rs
@@ -180,33 +180,37 @@ impl ElementSnapshot for GeckoElementSna
}
#[inline]
fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
if !self.has_any(Flags::MaybeClass) {
return false;
}
- snapshot_helpers::has_class(self.as_ptr(),
- name,
- case_sensitivity,
- bindings::Gecko_SnapshotClassOrClassList)
+ snapshot_helpers::has_class(
+ self.as_ptr(),
+ name,
+ case_sensitivity,
+ bindings::Gecko_SnapshotHasClass,
+ )
}
#[inline]
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
if !self.has_any(Flags::MaybeClass) {
return;
}
- snapshot_helpers::each_class(self.as_ptr(),
- callback,
- bindings::Gecko_SnapshotClassOrClassList)
+ snapshot_helpers::each_class(
+ self.as_ptr(),
+ callback,
+ bindings::Gecko_SnapshotClassOrClassList,
+ )
}
#[inline]
fn lang_attr(&self) -> Option<Atom> {
let ptr = unsafe { bindings::Gecko_SnapshotLangValue(self) };
if ptr.is_null() {
None
} else {
--- a/servo/components/style/gecko/snapshot_helpers.rs
+++ b/servo/components/style/gecko/snapshot_helpers.rs
@@ -1,53 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Element an snapshot common logic.
-use CaseSensitivityExt;
use gecko_bindings::structs::nsAtom;
-use gecko_string_cache::WeakAtom;
use selectors::attr::CaseSensitivity;
use std::{ptr, slice};
use string_cache::Atom;
/// A function that, given an element of type `T`, allows you to get a single
/// class or a class list.
pub type ClassOrClassList<T> = unsafe extern fn (T, *mut *mut nsAtom, *mut *mut *mut nsAtom) -> u32;
+/// A function to return whether an element of type `T` has a given class.
+///
+/// The `bool` argument represents whether it should compare case-insensitively
+/// or not.
+pub type HasClass<T> = unsafe extern fn (T, *mut nsAtom, bool) -> bool;
+
/// Given an item `T`, a class name, and a getter function, return whether that
/// element has the class that `name` represents.
+#[inline(always)]
pub fn has_class<T>(
item: T,
name: &Atom,
case_sensitivity: CaseSensitivity,
- getter: ClassOrClassList<T>,
+ getter: HasClass<T>,
) -> bool {
- unsafe {
- let mut class: *mut nsAtom = ptr::null_mut();
- let mut list: *mut *mut nsAtom = ptr::null_mut();
- let length = getter(item, &mut class, &mut list);
- match length {
- 0 => false,
- 1 => case_sensitivity.eq_atom(name, WeakAtom::new(class)),
- n => {
- let classes = slice::from_raw_parts(list, n as usize);
- match case_sensitivity {
- CaseSensitivity::CaseSensitive => {
- classes.iter().any(|ptr| &**name == WeakAtom::new(*ptr))
- }
- CaseSensitivity::AsciiCaseInsensitive => {
- classes.iter().any(|ptr| name.eq_ignore_ascii_case(WeakAtom::new(*ptr)))
- }
- }
- }
- }
- }
+ let ignore_case = match case_sensitivity {
+ CaseSensitivity::CaseSensitive => false,
+ CaseSensitivity::AsciiCaseInsensitive => true,
+ };
+
+ unsafe { getter(item, name.as_ptr(), ignore_case) }
}
/// Given an item, a callback, and a getter, execute `callback` for each class
/// this `item` has.
pub fn each_class<F, T>(
item: T,
mut callback: F,
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -2196,17 +2196,17 @@ impl<'le> ::selectors::Element for Gecko
if !self.may_have_class() {
return false;
}
snapshot_helpers::has_class(
self.0,
name,
case_sensitivity,
- Gecko_ClassOrClassList,
+ bindings::Gecko_HasClass,
)
}
#[inline]
fn is_html_element_in_html_document(&self) -> bool {
self.is_html_element() &&
self.as_node().owner_doc().is_html_document()
}