diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 500af8009393..4505ac10192b 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -2246,8 +2246,8 @@ impl ServoComputedValuesCursorUtility for ServoComputedValues { fn get_cursor(&self, default_cursor: Cursor) -> Option { match (self.get_pointing().pointer_events, self.get_pointing().cursor) { (pointer_events::T::none, _) => None, - (pointer_events::T::auto, cursor::T::AutoCursor) => Some(default_cursor), - (pointer_events::T::auto, cursor::T::SpecifiedCursor(cursor)) => Some(cursor), + (pointer_events::T::auto, cursor::Keyword::AutoCursor) => Some(default_cursor), + (pointer_events::T::auto, cursor::Keyword::SpecifiedCursor(cursor)) => Some(cursor), } } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index a82dcd4a4e0d..b8d02879368a 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -19,6 +19,7 @@ use gecko_bindings::bindings::Gecko_Construct_${style_struct.gecko_ffi_name}; use gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ffi_name}; use gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name}; % endfor +use gecko_bindings::bindings::Gecko_CopyCursorArrayFrom; use gecko_bindings::bindings::Gecko_CopyFontFamilyFrom; use gecko_bindings::bindings::Gecko_CopyImageValueFrom; use gecko_bindings::bindings::Gecko_CopyListStyleImageFrom; @@ -28,6 +29,8 @@ use gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use gecko_bindings::bindings::Gecko_FontFamilyList_AppendGeneric; use gecko_bindings::bindings::Gecko_FontFamilyList_AppendNamed; use gecko_bindings::bindings::Gecko_FontFamilyList_Clear; +use gecko_bindings::bindings::Gecko_SetCursorArrayLength; +use gecko_bindings::bindings::Gecko_SetCursorImage; use gecko_bindings::bindings::Gecko_SetListStyleImage; use gecko_bindings::bindings::Gecko_SetListStyleImageNone; use gecko_bindings::bindings::Gecko_SetListStyleType; @@ -2195,12 +2198,12 @@ clip-path <%self:impl_trait style_struct_name="Pointing" skip_longhands="cursor"> pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) { - use properties::longhands::cursor::computed_value::T; + use properties::longhands::cursor::computed_value::Keyword; use style_traits::cursor::Cursor; - self.gecko.mCursor = match v { - T::AutoCursor => structs::NS_STYLE_CURSOR_AUTO, - T::SpecifiedCursor(cursor) => match cursor { + self.gecko.mCursor = match v.keyword { + Keyword::AutoCursor => structs::NS_STYLE_CURSOR_AUTO, + Keyword::SpecifiedCursor(cursor) => match cursor { Cursor::None => structs::NS_STYLE_CURSOR_NONE, Cursor::Default => structs::NS_STYLE_CURSOR_DEFAULT, Cursor::Pointer => structs::NS_STYLE_CURSOR_POINTER, @@ -2238,9 +2241,34 @@ clip-path Cursor::ZoomOut => structs::NS_STYLE_CURSOR_ZOOM_OUT, } } as u8; + + unsafe { + Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len()); + } + for i in 0..v.images.len() { + let image = &v.images[i]; + let extra_data = image.url.extra_data(); + let (ptr, len) = image.url.as_slice_components(); + unsafe { + Gecko_SetCursorImage(&mut self.gecko.mCursorImages[i], + ptr, len as u32, + extra_data.base.get(), + extra_data.referrer.get(), + extra_data.principal.get()); + } + // We don't need to record this struct as uncacheable, like when setting + // background-image to a url() value, since only properties in reset structs + // are re-used from the applicable declaration cache, and the Pointing struct + // is an inherited struct. + } } - ${impl_simple_copy('cursor', 'mCursor')} + pub fn copy_cursor_from(&mut self, other: &Self) { + self.gecko.mCursor = other.gecko.mCursor; + unsafe { + Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko); + } + } <%self:impl_trait style_struct_name="Column" diff --git a/components/style/properties/longhand/pointing.mako.rs b/components/style/properties/longhand/pointing.mako.rs index f140b32336e3..c46e4fdb8417 100644 --- a/components/style/properties/longhand/pointing.mako.rs +++ b/components/style/properties/longhand/pointing.mako.rs @@ -10,6 +10,7 @@ pub use self::computed_value::T as SpecifiedValue; use values::NoViewportPercentage; use values::computed::ComputedValueAsSpecified; + use values::specified::url::SpecifiedUrl; impl ComputedValueAsSpecified for SpecifiedValue {} impl NoViewportPercentage for SpecifiedValue {} @@ -18,38 +19,127 @@ use std::fmt; use style_traits::cursor::Cursor; use style_traits::ToCss; + use values::specified::url::SpecifiedUrl; - #[derive(Clone, PartialEq, Eq, Copy, Debug)] + #[derive(Clone, PartialEq, Copy, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum T { + pub enum Keyword { AutoCursor, SpecifiedCursor(Cursor), } - impl ToCss for T { + #[cfg(not(feature = "gecko"))] + pub type T = Keyword; + + #[cfg(feature = "gecko")] + #[derive(Clone, PartialEq, Debug)] + pub struct Image { + pub url: SpecifiedUrl, + pub hotspot: Option<(f32, f32)>, + } + + #[cfg(feature = "gecko")] + #[derive(Clone, PartialEq, Debug)] + pub struct T { + pub images: Vec, + pub keyword: Keyword, + } + + impl ToCss for Keyword { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { - T::AutoCursor => dest.write_str("auto"), - T::SpecifiedCursor(c) => c.to_css(dest), + Keyword::AutoCursor => dest.write_str("auto"), + Keyword::SpecifiedCursor(c) => c.to_css(dest), + } + } + } + + #[cfg(feature = "gecko")] + impl ToCss for Image { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.url.to_css(dest)); + if let Some((x, y)) = self.hotspot { + try!(dest.write_str(" ")); + try!(x.to_css(dest)); + try!(dest.write_str(" ")); + try!(y.to_css(dest)); + } + Ok(()) + } + } + + #[cfg(feature = "gecko")] + impl ToCss for T { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + for url in &self.images { + try!(url.to_css(dest)); + try!(dest.write_str(", ")); } + self.keyword.to_css(dest) } } } + #[cfg(not(feature = "gecko"))] #[inline] pub fn get_initial_value() -> computed_value::T { - computed_value::T::AutoCursor + computed_value::Keyword::AutoCursor } + + #[cfg(feature = "gecko")] + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + images: vec![], + keyword: computed_value::Keyword::AutoCursor + } + } + + impl Parse for computed_value::Keyword { + fn parse(input: &mut Parser) -> Result { + use std::ascii::AsciiExt; + use style_traits::cursor::Cursor; + let ident = try!(input.expect_ident()); + if ident.eq_ignore_ascii_case("auto") { + Ok(computed_value::Keyword::AutoCursor) + } else { + Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor) + } + } + } + + #[cfg(feature = "gecko")] + fn parse_image(context: &ParserContext, input: &mut Parser) -> Result { + Ok(computed_value::Image { + url: try!(SpecifiedUrl::parse(context, input)), + hotspot: match input.try(|input| input.expect_number()) { + Ok(number) => Some((number, try!(input.expect_number()))), + Err(()) => None, + }, + }) + } + + #[cfg(not(feature = "gecko"))] pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { - use std::ascii::AsciiExt; - use style_traits::cursor::Cursor; - let ident = try!(input.expect_ident()); - if ident.eq_ignore_ascii_case("auto") { - Ok(SpecifiedValue::AutoCursor) - } else { - Cursor::from_css_keyword(&ident) - .map(SpecifiedValue::SpecifiedCursor) + computed_value::Keyword::parse(input) + } + + /// cursor: [ [ ]?]# [auto | default | ...] + #[cfg(feature = "gecko")] + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + let mut images = vec![]; + loop { + match input.try(|input| parse_image(context, input)) { + Ok(image) => images.push(image), + Err(()) => break, + } + try!(input.expect_comma()); } + + Ok(computed_value::T { + images: images, + keyword: try!(computed_value::Keyword::parse(input)), + }) }