Skip to content

Commit

Permalink
Support cursor property url() values in stylo. r=manishearth
Browse files Browse the repository at this point in the history
MozReview-Commit-ID: 6herzaXUz4i
  • Loading branch information
heycam committed Nov 21, 2016
1 parent c6be1a8 commit 830cc88
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 21 deletions.
4 changes: 2 additions & 2 deletions components/layout/display_list_builder.rs
Expand Up @@ -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),
}
}
}
Expand Down
38 changes: 33 additions & 5 deletions components/style/properties/gecko.mako.rs
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Expand Down
118 changes: 104 additions & 14 deletions components/style/properties/longhand/pointing.mako.rs
Expand Up @@ -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 {}
Expand All @@ -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>

Expand Down

0 comments on commit 830cc88

Please sign in to comment.