aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCameron McCormack <cam@mcc.id.au>2016-10-17 17:12:24 +0800
committerCameron McCormack <cam@mcc.id.au>2016-11-21 14:48:59 +0800
commit830cc88283d3cf92f378cd104efd2743aa38da11 (patch)
tree2700549c128987cfe7e2ba663431168002fc70ff
parentc6be1a8995eed8cb40288e7cf90dfa07cb9351ac (diff)
downloadservo-830cc88283d3cf92f378cd104efd2743aa38da11.tar.gz
servo-830cc88283d3cf92f378cd104efd2743aa38da11.zip
Support cursor property url() values in stylo. r=manishearth
MozReview-Commit-ID: 6herzaXUz4i
-rw-r--r--components/layout/display_list_builder.rs4
-rw-r--r--components/style/properties/gecko.mako.rs38
-rw-r--r--components/style/properties/longhand/pointing.mako.rs118
3 files changed, 139 insertions, 21 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 500af800939..4505ac10192 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<Cursor> {
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 a82dcd4a4e0..b8d02879368 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>
<%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 f140b32336e..c46e4fdb841 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<Image>,
+ pub keyword: Keyword,
+ }
+
+ impl ToCss for Keyword {
fn to_css<W>(&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<W>(&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<W>(&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<computed_value::Keyword, ()> {
+ 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<computed_value::Image, ()> {
+ 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<SpecifiedValue, ()> {
- 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: [<url> [<number> <number>]?]# [auto | default | ...]
+ #[cfg(feature = "gecko")]
+ pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ 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)),
+ })
}
</%helpers:longhand>