diff options
Diffstat (limited to 'components/style/gecko/snapshot_helpers.rs')
-rw-r--r-- | components/style/gecko/snapshot_helpers.rs | 122 |
1 files changed, 89 insertions, 33 deletions
diff --git a/components/style/gecko/snapshot_helpers.rs b/components/style/gecko/snapshot_helpers.rs index 3f84de7fd50..6c40f242d5f 100644 --- a/components/style/gecko/snapshot_helpers.rs +++ b/components/style/gecko/snapshot_helpers.rs @@ -4,58 +4,114 @@ //! Element an snapshot common logic. -use gecko_bindings::structs::nsAtom; +use CaseSensitivityExt; +use gecko_bindings::bindings; +use gecko_bindings::structs::{self, nsAtom}; use selectors::attr::CaseSensitivity; -use std::{ptr, slice}; -use string_cache::Atom; +use string_cache::{Atom, WeakAtom}; /// 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 "C" fn(T, *mut *mut nsAtom, *mut *mut *mut nsAtom) -> u32; +enum Class<'a> { + None, + One(*const nsAtom), + More(&'a [structs::RefPtr<nsAtom>]), +} + +#[inline(always)] +fn base_type(attr: &structs::nsAttrValue) -> structs::nsAttrValue_ValueBaseType { + (attr.mBits & structs::NS_ATTRVALUE_BASETYPE_MASK) as structs::nsAttrValue_ValueBaseType +} + +#[inline(always)] +unsafe fn ptr<T>(attr: &structs::nsAttrValue) -> *const T { + (attr.mBits & !structs::NS_ATTRVALUE_BASETYPE_MASK) as *const T +} + +#[inline(always)] +unsafe fn get_class_from_attr(attr: &structs::nsAttrValue) -> Class { + debug_assert!(bindings::Gecko_AssertClassAttrValueIsSane(attr)); + let base_type = base_type(attr); + if base_type == structs::nsAttrValue_ValueBaseType_eStringBase { + return Class::None; + } + if base_type == structs::nsAttrValue_ValueBaseType_eAtomBase { + return Class::One(ptr::<nsAtom>(attr)); + } + debug_assert_eq!(base_type, structs::nsAttrValue_ValueBaseType_eOtherBase); + + let container = ptr::<structs::MiscContainer>(attr); + debug_assert_eq!((*container).mType, structs::nsAttrValue_ValueType_eAtomArray); + let array = + (*container).__bindgen_anon_1.mValue.as_ref().__bindgen_anon_1.mAtomArray.as_ref(); + Class::More(&***array) +} + +#[inline(always)] +unsafe fn get_id_from_attr(attr: &structs::nsAttrValue) -> &WeakAtom { + debug_assert_eq!(base_type(attr), structs::nsAttrValue_ValueBaseType_eAtomBase); + WeakAtom::new(ptr::<nsAtom>(attr)) +} -/// 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 "C" fn(T, *mut nsAtom, bool) -> bool; +/// Find an attribute value with a given name and no namespace. +#[inline(always)] +pub fn find_attr<'a>( + attrs: &'a [structs::AttrArray_InternalAttr], + name: &Atom, +) -> Option<&'a structs::nsAttrValue> { + attrs.iter() + .find(|attr| attr.mName.mBits == name.as_ptr() as usize) + .map(|attr| &attr.mValue) +} + +/// Finds the id attribute from a list of attributes. +#[inline(always)] +pub fn get_id(attrs: &[structs::AttrArray_InternalAttr]) -> Option<&WeakAtom> { + Some(unsafe { get_id_from_attr(find_attr(attrs, &atom!("id"))?) }) +} -/// Given an item `T`, a class name, and a getter function, return whether that -/// element has the class that `name` represents. +/// Given a class name, a case sensitivity, and an array of attributes, returns +/// whether the class has the attribute that name represents. #[inline(always)] -pub fn has_class<T>( - item: T, +pub fn has_class( name: &Atom, case_sensitivity: CaseSensitivity, - getter: HasClass<T>, + attr: &structs::nsAttrValue, ) -> bool { - let ignore_case = match case_sensitivity { - CaseSensitivity::CaseSensitive => false, - CaseSensitivity::AsciiCaseInsensitive => true, - }; - - unsafe { getter(item, name.as_ptr(), ignore_case) } + match unsafe { get_class_from_attr(attr) } { + Class::None => false, + Class::One(atom) => unsafe { + case_sensitivity.eq_atom(name, WeakAtom::new(atom)) + }, + Class::More(atoms) => { + match case_sensitivity { + CaseSensitivity::CaseSensitive => { + atoms.iter().any(|atom| atom.mRawPtr == name.as_ptr()) + } + CaseSensitivity::AsciiCaseInsensitive => unsafe { + atoms.iter().any(|atom| WeakAtom::new(atom.mRawPtr).eq_ignore_ascii_case(name)) + } + } + } + } } /// 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, getter: ClassOrClassList<T>) +#[inline(always)] +pub fn each_class<F>(attr: &structs::nsAttrValue, mut callback: F) where F: FnMut(&Atom), { 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 => {}, - 1 => Atom::with(class, callback), - n => { - let classes = slice::from_raw_parts(list, n as usize); - for c in classes { - Atom::with(*c, &mut callback) + match get_class_from_attr(attr) { + Class::None => {}, + Class::One(atom) => Atom::with(atom, callback), + Class::More(atoms) => { + for atom in atoms { + Atom::with(atom.mRawPtr, &mut callback) } - }, + } } } } |