diff --git a/ports/geckolib/gecko_bindings/bindings.rs b/ports/geckolib/gecko_bindings/bindings.rs index c3a29f94885..b5019e16d03 100644 --- a/ports/geckolib/gecko_bindings/bindings.rs +++ b/ports/geckolib/gecko_bindings/bindings.rs @@ -146,6 +146,10 @@ extern "C" { pub fn Gecko_IsRootElement(element: *mut RawGeckoElement) -> bool; pub fn Gecko_LocalName(element: *mut RawGeckoElement) -> *mut nsIAtom; pub fn Gecko_Namespace(element: *mut RawGeckoElement) -> *mut nsIAtom; + pub fn Gecko_GetElementId(element: *mut RawGeckoElement) -> *mut nsIAtom; + pub fn Gecko_ClassOrClassList(element: *mut RawGeckoElement, + class_: *mut *mut nsIAtom, + classList: *mut *mut *mut nsIAtom) -> u32; pub fn Gecko_GetNodeData(node: *mut RawGeckoNode) -> *mut ServoNodeData; pub fn Gecko_SetNodeData(node: *mut RawGeckoNode, data: *mut ServoNodeData); diff --git a/ports/geckolib/gecko_bindings/tools/regen_bindings.sh b/ports/geckolib/gecko_bindings/tools/regen_bindings.sh index da147247541..13678732f26 100755 --- a/ports/geckolib/gecko_bindings/tools/regen_bindings.sh +++ b/ports/geckolib/gecko_bindings/tools/regen_bindings.sh @@ -75,10 +75,16 @@ eval ./rust-bindgen/target/debug/bindgen \ -x c++ -std=gnu++0x \ "-I$DIST_INCLUDE" \ "-I$DIST_INCLUDE/nspr/" \ - "-I$SRCDIR/nsprpub/pr/include/" \ + "-I$1/nsprpub/pr/include/" \ $PLATFORM_DEPENDENT_DEFINES \ + -DMOZILLA_INTERNAL_API \ + -DMOZ_STYLO_BINDINGS=1 \ + -DJS_DEBUG=1 \ + -DDEBUG=1 -DTRACING=1 -DOS_POSIX=1 \ + -DIMPL_LIBXUL \ -o ../bindings.rs \ -no-type-renaming \ + -include "$1/mozilla-config.h" \ "$DIST_INCLUDE/mozilla/ServoBindings.h" \ -match "ServoBindings.h" \ -match "nsStyleStructList.h" \ diff --git a/ports/geckolib/string_cache/lib.rs b/ports/geckolib/string_cache/lib.rs index 6b6b0ed9c76..de98f3d2c68 100644 --- a/ports/geckolib/string_cache/lib.rs +++ b/ports/geckolib/string_cache/lib.rs @@ -134,6 +134,10 @@ impl Atom { self.0 } + pub unsafe fn with(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) { + callback(transmute(&ptr)) + } + // Static atoms have a dummy AddRef/Release, so we don't bother calling // AddRef() here. This would cause memory corruption with non-static atoms // both because (a) we wouldn't hold the atom alive, and (b) we can't avoid @@ -226,3 +230,12 @@ impl From for Atom { Atom::from(&*string) } } + +impl From<*mut nsIAtom> for Atom { + fn from(ptr: *mut nsIAtom) -> Atom { + unsafe { + Gecko_AddRefAtom(ptr); + Atom(ptr) + } + } +} diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index a30060d416a..ec913823caf 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -5,7 +5,9 @@ #![allow(unsafe_code)] use gecko_bindings::bindings::{Gecko_ChildrenCount}; +use gecko_bindings::bindings::{Gecko_ClassOrClassList}; use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetAttrAsUTF8, Gecko_GetDocumentElement}; +use gecko_bindings::bindings::{Gecko_GetElementId}; use gecko_bindings::bindings::{Gecko_GetFirstChild, Gecko_GetFirstChildElement}; use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetLastChildElement}; use gecko_bindings::bindings::{Gecko_GetNextSibling, Gecko_GetNextSiblingElement}; @@ -18,6 +20,7 @@ use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink}; use gecko_bindings::bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData}; use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode}; use gecko_bindings::bindings::{ServoNodeData}; +use gecko_bindings::bindings::{nsIAtom}; use libc::uintptr_t; use properties::GeckoComputedValues; use selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PrivateStyleData}; @@ -28,6 +31,7 @@ use smallvec::VecLike; use std::cell::{Ref, RefCell, RefMut}; use std::marker::PhantomData; use std::ops::BitOr; +use std::ptr; use std::slice; use std::str::from_utf8_unchecked; use std::sync::Arc; @@ -447,23 +451,46 @@ impl<'le> ::selectors::Element for GeckoElement<'le> { } fn get_id(&self) -> Option { - // FIXME(bholley): Servo caches the id atom directly on the element to - // make this blazing fast. Assuming that was a measured optimization, doing - // the dumb thing like we do below will almost certainly be a bottleneck. - self.get_attr(&ns!(), &atom!("id")).map(|s| Atom::from(s)) + unsafe { + let ptr = Gecko_GetElementId(self.element); + if ptr.is_null() { + None + } else { + Some(Atom::from(ptr)) + } + } } fn has_class(&self, name: &Atom) -> bool { - // FIXME(bholley): Do this smarter. - self.get_attr(&ns!(), &atom!("class")) - .map_or(false, |classes| classes.split(" ").any(|n| &Atom::from(n) == name)) + unsafe { + let mut class: *mut nsIAtom = ptr::null_mut(); + let mut list: *mut *mut nsIAtom = ptr::null_mut(); + let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list); + match length { + 0 => false, + 1 => name.as_ptr() == class, + n => { + let classes = slice::from_raw_parts(list, n as usize); + classes.iter().any(|ptr| name.as_ptr() == *ptr) + } + } + } } fn each_class(&self, mut callback: F) where F: FnMut(&Atom) { - // FIXME(bholley): Synergize with the DOM to stop splitting strings here. - if let Some(classes) = self.get_attr(&ns!(), &atom!("class")) { - for c in classes.split(" ") { - callback(&Atom::from(c)); + unsafe { + let mut class: *mut nsIAtom = ptr::null_mut(); + let mut list: *mut *mut nsIAtom = ptr::null_mut(); + let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list); + match length { + 0 => {} + 1 => Atom::with(class, &mut callback), + n => { + let classes = slice::from_raw_parts(list, n as usize); + for c in classes { + Atom::with(*c, &mut callback) + } + } } } }