style: Support image-set() on the cursor property

Differential Revision: https://phabricator.services.mozilla.com/D106745
This commit is contained in:
Oriol Brufau 2023-05-16 07:28:58 +02:00
parent e1f254854d
commit 685d269e31
4 changed files with 49 additions and 20 deletions

View file

@ -5,7 +5,7 @@
//! Computed values for UI properties
use crate::values::computed::color::Color;
use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::image::Image;
use crate::values::computed::Number;
use crate::values::generics::ui as generics;
@ -16,7 +16,7 @@ pub use crate::values::specified::ui::{MozForceBrokenImageIcon, UserSelect};
pub type Cursor = generics::GenericCursor<CursorImage>;
/// A computed value for item of `image cursors`.
pub type CursorImage = generics::GenericCursorImage<ComputedImageUrl, Number>;
pub type CursorImage = generics::GenericCursorImage<Image, Number>;
/// A computed value for `scrollbar-color` property.
pub type ScrollbarColor = generics::GenericScrollbarColor<Color>;

View file

@ -61,15 +61,14 @@ impl<Image: ToCss> ToCss for Cursor<Image> {
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct GenericCursorImage<ImageUrl, Number> {
pub struct GenericCursorImage<Image, Number> {
/// The url to parse images from.
pub url: ImageUrl,
pub image: Image,
/// Whether the image has a hotspot or not.
pub has_hotspot: bool,
/// The x coordinate.
@ -80,12 +79,12 @@ pub struct GenericCursorImage<ImageUrl, Number> {
pub use self::GenericCursorImage as CursorImage;
impl<ImageUrl: ToCss, Number: ToCss> ToCss for CursorImage<ImageUrl, Number> {
impl<Image: ToCss, Number: ToCss> ToCss for CursorImage<Image, Number> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.url.to_css(dest)?;
self.image.to_css(dest)?;
if self.has_hotspot {
dest.write_str(" ")?;
self.hotspot_x.to_css(dest)?;

View file

@ -181,7 +181,7 @@ impl Parse for Image {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Image, ParseError<'i>> {
Image::parse_with_cors_mode(context, input, CorsMode::None, /* allow_none = */ true)
Image::parse_with_cors_mode(context, input, CorsMode::None, /* allow_none = */ true, /* only_url = */ false)
}
}
@ -191,23 +191,32 @@ impl Image {
input: &mut Parser<'i, 't>,
cors_mode: CorsMode,
allow_none: bool,
only_url: bool,
) -> Result<Image, ParseError<'i>> {
if allow_none && input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(generic::Image::None);
}
if let Ok(url) = input
.try_parse(|input| SpecifiedImageUrl::parse_with_cors_mode(context, input, cors_mode))
{
return Ok(generic::Image::Url(url));
}
if let Ok(gradient) = input.try_parse(|i| Gradient::parse(context, i)) {
return Ok(generic::Image::Gradient(Box::new(gradient)));
}
if image_set_enabled() {
if let Ok(is) = input.try_parse(|input| ImageSet::parse(context, input, cors_mode)) {
if let Ok(is) = input.try_parse(|input| ImageSet::parse(context, input, cors_mode, only_url)) {
return Ok(generic::Image::ImageSet(Box::new(is)));
}
}
if only_url {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
if let Ok(gradient) = input.try_parse(|i| Gradient::parse(context, i)) {
return Ok(generic::Image::Gradient(Box::new(gradient)));
}
if cross_fade_enabled() {
if let Ok(cf) = input.try_parse(|input| CrossFade::parse(context, input, cors_mode)) {
return Ok(generic::Image::CrossFade(Box::new(cf)));
@ -264,6 +273,21 @@ impl Image {
input,
CorsMode::Anonymous,
/* allow_none = */ true,
/* only_url = */ false,
)
}
/// Provides an alternate method for parsing, but only for urls.
pub fn parse_only_url<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Image, ParseError<'i>> {
Self::parse_with_cors_mode(
context,
input,
CorsMode::None,
/* allow_none = */ false,
/* only_url = */ true,
)
}
}
@ -310,7 +334,7 @@ impl CrossFadeImage {
cors_mode: CorsMode,
) -> Result<Self, ParseError<'i>> {
if let Ok(image) = input.try_parse(|input| {
Image::parse_with_cors_mode(context, input, cors_mode, /* allow_none = */ false)
Image::parse_with_cors_mode(context, input, cors_mode, /* allow_none = */ false, /* only_url = */ false)
}) {
return Ok(Self::Image(image));
}
@ -339,10 +363,11 @@ impl ImageSet {
context: &ParserContext,
input: &mut Parser<'i, 't>,
cors_mode: CorsMode,
only_url: bool,
) -> Result<Self, ParseError<'i>> {
input.expect_function_matching("image-set")?;
let items = input.parse_nested_block(|input| {
input.parse_comma_separated(|input| ImageSetItem::parse(context, input, cors_mode))
input.parse_comma_separated(|input| ImageSetItem::parse(context, input, cors_mode, only_url))
})?;
Ok(Self {
selected_index: 0,
@ -356,6 +381,7 @@ impl ImageSetItem {
context: &ParserContext,
input: &mut Parser<'i, 't>,
cors_mode: CorsMode,
only_url: bool,
) -> Result<Self, ParseError<'i>> {
let image = match input.try_parse(|i| i.expect_url_or_string()) {
Ok(url) => Image::Url(SpecifiedImageUrl::parse_from_string(
@ -364,7 +390,7 @@ impl ImageSetItem {
cors_mode,
)),
Err(..) => Image::parse_with_cors_mode(
context, input, cors_mode, /* allow_none = */ false,
context, input, cors_mode, /* allow_none = */ false, /* only_url = */ only_url
)?,
};
let resolution = input

View file

@ -7,17 +7,17 @@
use crate::parser::{Parse, ParserContext};
use crate::values::generics::ui as generics;
use crate::values::specified::color::Color;
use crate::values::specified::url::SpecifiedImageUrl;
use crate::values::specified::image::Image;
use crate::values::specified::Number;
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
/// A specified value for the `cursor` property.
pub type Cursor = generics::GenericCursor<CursorImage>;
/// A specified value for item of `image cursors`.
pub type CursorImage = generics::GenericCursorImage<SpecifiedImageUrl, Number>;
pub type CursorImage = generics::GenericCursorImage<Image, Number>;
impl Parse for Cursor {
/// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
@ -47,7 +47,7 @@ impl Parse for CursorImage {
) -> Result<Self, ParseError<'i>> {
use crate::Zero;
let url = SpecifiedImageUrl::parse(context, input)?;
let image = Image::parse_only_url(context, input)?;
let mut has_hotspot = false;
let mut hotspot_x = Number::zero();
let mut hotspot_y = Number::zero();
@ -59,7 +59,7 @@ impl Parse for CursorImage {
}
Ok(Self {
url,
image,
has_hotspot,
hotspot_x,
hotspot_y,
@ -67,6 +67,10 @@ impl Parse for CursorImage {
}
}
// This trait is manually implemented because we don't support the whole <image>
// syntax for cursors
impl SpecifiedValueInfo for CursorImage {}
/// Specified value of `-moz-force-broken-image-icon`
#[derive(
Clone,