diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index adf5a43ced6..53d51591220 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -12,7 +12,7 @@ use data::PerDocumentStyleData; use euclid::Size2D; use gecko_style_structs::SheetParsingMode; use properties::GeckoComputedValues; -use selector_impl::{GeckoSelectorImpl, SharedStyleContext, Stylesheet}; +use selector_impl::{GeckoSelectorImpl, PseudoElement, SharedStyleContext, Stylesheet}; use std::marker::PhantomData; use std::mem::{forget, transmute}; use std::ptr; @@ -30,6 +30,29 @@ use url::Url; use util::arc_ptr_eq; use wrapper::{GeckoDocument, GeckoElement, GeckoNode, NonOpaqueStyleData}; +// TODO: This is ugly and should go away once we get an atom back-end. +pub fn pseudo_element_from_atom(pseudo: *mut nsIAtom, + in_ua_stylesheet: bool) -> Result { + use bindings::Gecko_GetAtomAsUTF16; + use selectors::parser::{ParserContext, SelectorImpl}; + + let pseudo_string = unsafe { + let mut length = 0; + let mut buff = Gecko_GetAtomAsUTF16(pseudo, &mut length); + + // Handle the annoying preceding colon in front of everything in nsCSSAnonBoxList.h. + debug_assert!(length >= 2 && *buff == ':' as u16 && *buff.offset(1) != ':' as u16); + buff = buff.offset(1); + length -= 1; + + String::from_utf16(slice::from_raw_parts(buff, length as usize)).unwrap() + }; + + let mut context = ParserContext::new(); + context.in_user_agent_stylesheet = in_ua_stylesheet; + GeckoSelectorImpl::parse_pseudo_element(&context, &pseudo_string).map_err(|_| pseudo_string) +} + /* * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against @@ -106,19 +129,40 @@ pub struct ArcHelpers { phantom2: PhantomData, } + impl ArcHelpers { pub fn with(raw: *mut GeckoType, cb: F) -> Output where F: FnOnce(&Arc) -> Output { + debug_assert!(!raw.is_null()); + let owned = unsafe { Self::into(raw) }; let result = cb(&owned); forget(owned); result } + pub fn maybe_with(maybe_raw: *mut GeckoType, cb: F) -> Output + where F: FnOnce(Option<&Arc>) -> Output { + let owned = if maybe_raw.is_null() { + None + } else { + Some(unsafe { Self::into(maybe_raw) }) + }; + + let result = cb(owned.as_ref()); + forget(owned); + + result + } + pub unsafe fn into(ptr: *mut GeckoType) -> Arc { transmute(ptr) } + pub unsafe fn from(owned: Arc) -> *mut GeckoType { + transmute(owned) + } + pub unsafe fn addref(ptr: *mut GeckoType) { Self::with(ptr, |arc| forget(arc.clone())); } @@ -210,44 +254,22 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: * pseudo_tag: *mut nsIAtom, raw_data: *mut RawServoStyleSet) -> *mut ServoComputedValues { - use bindings::Gecko_GetAtomAsUTF16; - use selectors::parser::{ParserContext, SelectorImpl}; - let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data); - // TODO: This is ugly and should go away once we get an atom back-end. - let pseudo_string = unsafe { - let mut length = 0; - let buff = Gecko_GetAtomAsUTF16(pseudo_tag, &mut length); - String::from_utf16(slice::from_raw_parts(buff, length as usize)).unwrap() - }; - - let mut context = ParserContext::new(); - // Parse every pseudo-element possible. - context.in_user_agent_stylesheet = true; - - let pseudo = match GeckoSelectorImpl::parse_pseudo_element(&context, &pseudo_string) { + let pseudo = match pseudo_element_from_atom(pseudo_tag, true) { Ok(pseudo) => pseudo, - Err(_) => { - warn!("stylo: Unable to parse pseudo-element: {}", pseudo_string); + Err(pseudo) => { + warn!("stylo: Unable to parse anonymous-box pseudo-element: {}", pseudo); return ptr::null_mut(); } }; - unsafe { - let parent: Option> = - if parent_style_or_null.is_null() { - None - } else { - Some(transmute(parent_style_or_null)) - }; + type Helpers = ArcHelpers; - let new_computed = data.stylist.computed_values_for_pseudo(&pseudo, parent.as_ref()); - - forget(parent); - - new_computed.map_or(ptr::null_mut(), |c| transmute(c)) - } + Helpers::maybe_with(parent_style_or_null, |maybe_parent| { + let new_computed = data.stylist.computed_values_for_pseudo(&pseudo, maybe_parent); + new_computed.map_or(ptr::null_mut(), |c| unsafe { Helpers::from(c) }) + }) } #[no_mangle]