mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
style: Add parsing for cross-fade from CSS Image Values and Replaced Content Module Level 4.
This is the first of what will likely be a couple patches for cross-fade's implementation. Bug 546052 tracks it's complete implementation. Differential Revision: https://phabricator.services.mozilla.com/D81889
This commit is contained in:
parent
7c3d815f78
commit
8f89ebffec
4 changed files with 204 additions and 5 deletions
|
@ -207,6 +207,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Parse for Box<T>
|
||||
where
|
||||
T: Parse
|
||||
{
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
T::parse(context, input).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for crate::OwnedStr {
|
||||
fn parse<'i, 't>(
|
||||
_: &ParserContext,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//! [image]: https://drafts.csswg.org/css-images/#image-values
|
||||
|
||||
use crate::values::computed::position::Position;
|
||||
use crate::values::computed::percentage::Percentage;
|
||||
use crate::values::computed::url::ComputedImageUrl;
|
||||
#[cfg(feature = "gecko")]
|
||||
use crate::values::computed::NumberOrPercentage;
|
||||
|
@ -25,7 +26,7 @@ use style_traits::{CssWriter, ToCss};
|
|||
|
||||
/// Computed values for an image according to CSS-IMAGES.
|
||||
/// <https://drafts.csswg.org/css-images/#image-values>
|
||||
pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
|
||||
pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl, Color, Percentage>;
|
||||
|
||||
/// Computed values for a CSS gradient.
|
||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||
|
@ -40,6 +41,12 @@ pub type Gradient = generic::GenericGradient<
|
|||
Color,
|
||||
>;
|
||||
|
||||
/// Computed values for CSS cross-fade
|
||||
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
||||
pub type CrossFade = generic::CrossFade<Image, Color, Percentage>;
|
||||
/// A computed percentage or nothing.
|
||||
pub type PercentOrNone = generic::PercentOrNone<Percentage>;
|
||||
|
||||
/// A computed radial gradient ending shape.
|
||||
pub type EndingShape = generic::GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use style_traits::{CssWriter, ToCss};
|
|||
Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericImage<G, MozImageRect, ImageUrl> {
|
||||
pub enum GenericImage<G, MozImageRect, ImageUrl, Color, Percentage> {
|
||||
/// `none` variant.
|
||||
None,
|
||||
/// A `<url()>` image.
|
||||
|
@ -45,10 +45,96 @@ pub enum GenericImage<G, MozImageRect, ImageUrl> {
|
|||
/// <https://drafts.css-houdini.org/css-paint-api/>
|
||||
#[cfg(feature = "servo-layout-2013")]
|
||||
PaintWorklet(PaintWorklet),
|
||||
|
||||
/// A `<cross-fade()>` image. Storing this directly inside of
|
||||
/// GenericImage increases the size by 8 bytes so we box it here
|
||||
/// and store images directly inside of cross-fade instead of
|
||||
/// boxing them there.
|
||||
CrossFade(Box<GenericCrossFade<Self, Color, Percentage>>),
|
||||
}
|
||||
|
||||
pub use self::GenericImage as Image;
|
||||
|
||||
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
||||
#[css(comma, function = "cross-fade")]
|
||||
#[derive(
|
||||
Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem, ToCss, ToComputedValue,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct GenericCrossFade<Image, Color, Percentage> {
|
||||
/// All of the image percent pairings passed as arguments to
|
||||
/// cross-fade.
|
||||
#[css(iterable)]
|
||||
pub elements: crate::OwnedSlice<GenericCrossFadeElement<Image, Color, Percentage>>,
|
||||
}
|
||||
|
||||
/// A `<percent> | none` value. Represents optional percentage values
|
||||
/// assosicated with cross-fade images.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToComputedValue,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
ToCss,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum PercentOrNone<Percentage> {
|
||||
/// `none` variant.
|
||||
#[css(skip)]
|
||||
None,
|
||||
/// A percentage variant.
|
||||
Percent(Percentage),
|
||||
}
|
||||
|
||||
/// An optional percent and a cross fade image.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToComputedValue,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
ToCss,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct GenericCrossFadeElement<Image, Color, Percentage> {
|
||||
/// The percent of the final image that `image` will be.
|
||||
pub percent: PercentOrNone<Percentage>,
|
||||
/// A color or image that will be blended when cross-fade is
|
||||
/// evaluated.
|
||||
pub image: GenericCrossFadeImage<Image, Color>,
|
||||
}
|
||||
|
||||
/// An image or a color. `cross-fade` takes either when blending
|
||||
/// images together.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToComputedValue,
|
||||
ToResolvedValue,
|
||||
ToShmem,
|
||||
ToCss,
|
||||
Parse,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericCrossFadeImage<I, C> {
|
||||
/// A boxed image value. Boxing provides indirection so images can
|
||||
/// be cross-fades and cross-fades can be images.
|
||||
Image(I),
|
||||
/// A color value.
|
||||
Color(C),
|
||||
}
|
||||
|
||||
pub use self::GenericCrossFade as CrossFade;
|
||||
pub use self::GenericCrossFadeElement as CrossFadeElement;
|
||||
pub use self::GenericCrossFadeImage as CrossFadeImage;
|
||||
|
||||
/// A CSS gradient.
|
||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
|
@ -291,22 +377,26 @@ pub struct GenericMozImageRect<NumberOrPercentage, MozImageRectUrl> {
|
|||
|
||||
pub use self::GenericMozImageRect as MozImageRect;
|
||||
|
||||
impl<G, R, U> fmt::Debug for Image<G, R, U>
|
||||
impl<G, R, U, C, P> fmt::Debug for Image<G, R, U, C, P>
|
||||
where
|
||||
G: ToCss,
|
||||
R: ToCss,
|
||||
U: ToCss,
|
||||
C: ToCss,
|
||||
P: ToCss,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.to_css(&mut CssWriter::new(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, R, U> ToCss for Image<G, R, U>
|
||||
impl<G, R, U, C, P> ToCss for Image<G, R, U, C, P>
|
||||
where
|
||||
G: ToCss,
|
||||
R: ToCss,
|
||||
U: ToCss,
|
||||
C: ToCss,
|
||||
P: ToCss,
|
||||
{
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
|
@ -325,6 +415,7 @@ where
|
|||
serialize_atom_identifier(selector, dest)?;
|
||||
dest.write_str(")")
|
||||
},
|
||||
Image::CrossFade(ref cf) => cf.to_css(dest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
|||
|
||||
/// Specified values for an image according to CSS-IMAGES.
|
||||
/// <https://drafts.csswg.org/css-images/#image-values>
|
||||
pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>;
|
||||
pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl, Color, Percentage>;
|
||||
|
||||
/// Specified values for a CSS gradient.
|
||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||
|
@ -50,6 +50,17 @@ pub type Gradient = generic::Gradient<
|
|||
Color,
|
||||
>;
|
||||
|
||||
/// Specified values for CSS cross-fade
|
||||
/// cross-fade( CrossFadeElement, ...)
|
||||
/// <https://drafts.csswg.org/css-images-4/#cross-fade-function>
|
||||
pub type CrossFade = generic::CrossFade<Image, Color, Percentage>;
|
||||
/// CrossFadeElement = percent? CrossFadeImage
|
||||
pub type CrossFadeElement = generic::CrossFadeElement<Image, Color, Percentage>;
|
||||
/// CrossFadeImage = image | color
|
||||
pub type CrossFadeImage = generic::CrossFadeImage<Image, Color>;
|
||||
/// A specified percentage or nothing.
|
||||
pub type PercentOrNone = generic::PercentOrNone<Percentage>;
|
||||
|
||||
type LengthPercentageItemList = crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>;
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -62,6 +73,16 @@ fn conic_gradients_enabled() -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn cross_fade_enabled() -> bool {
|
||||
static_prefs::pref!("layout.css.cross-fade.enabled")
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
fn cross_fade_enabled() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
impl SpecifiedValueInfo for Gradient {
|
||||
const SUPPORTED_TYPES: u8 = CssType::GRADIENT;
|
||||
|
||||
|
@ -89,6 +110,18 @@ impl SpecifiedValueInfo for Gradient {
|
|||
}
|
||||
}
|
||||
|
||||
// Need to manually implement as whether or not cross-fade shows up in
|
||||
// completions & etc is dependent on it being enabled.
|
||||
impl<Image, Color, Percentage> SpecifiedValueInfo for generic::CrossFade<Image, Color, Percentage> {
|
||||
const SUPPORTED_TYPES: u8 = 0;
|
||||
|
||||
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||
if cross_fade_enabled() {
|
||||
f(&["cross-fade"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified gradient line direction.
|
||||
///
|
||||
/// FIXME(emilio): This should be generic over Angle.
|
||||
|
@ -141,6 +174,11 @@ impl Parse for Image {
|
|||
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)) {
|
||||
return Ok(generic::Image::CrossFade(Box::new(cf)));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "servo-layout-2013")]
|
||||
{
|
||||
if let Ok(paint_worklet) = input.try_parse(|i| PaintWorklet::parse(context, i)) {
|
||||
|
@ -197,6 +235,57 @@ impl Image {
|
|||
}
|
||||
}
|
||||
|
||||
impl Parse for CrossFade {
|
||||
/// cross-fade() = cross-fade( <cf-image># )
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.expect_function_matching("cross-fade")?;
|
||||
let elements = input.parse_nested_block(|input| {
|
||||
input.parse_comma_separated(|input| CrossFadeElement::parse(context, input))
|
||||
})?;
|
||||
let elements = crate::OwnedSlice::from(elements);
|
||||
Ok(Self { elements })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for CrossFadeElement {
|
||||
/// <cf-image> = <percentage>? && [ <image> | <color> ]
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// Try and parse a leading percent sign.
|
||||
let mut percent = PercentOrNone::parse_or_none(context, input);
|
||||
// Parse the image
|
||||
let image = CrossFadeImage::parse(context, input)?;
|
||||
// Try and parse a trailing percent sign.
|
||||
if percent == PercentOrNone::None {
|
||||
percent = PercentOrNone::parse_or_none(context, input);
|
||||
}
|
||||
Ok(Self { percent, image })
|
||||
}
|
||||
}
|
||||
|
||||
impl PercentOrNone {
|
||||
fn parse_or_none<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Self {
|
||||
// We clamp our values here as this is the way that Safari and
|
||||
// Chrome's implementation handle out-of-bounds percentages
|
||||
// but whether or not this behavior follows the specification
|
||||
// is still being discussed. See:
|
||||
// <https://github.com/w3c/csswg-drafts/issues/5333>
|
||||
if let Ok(percent) = input.try_parse(|input| Percentage::parse_non_negative(context, input)) {
|
||||
Self::Percent(percent.clamp_to_hundred())
|
||||
} else {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Gradient {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue