From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- servo/components/style/values/generics/image.rs | 614 ++++++++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 servo/components/style/values/generics/image.rs (limited to 'servo/components/style/values/generics/image.rs') diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs new file mode 100644 index 0000000000..532920581f --- /dev/null +++ b/servo/components/style/values/generics/image.rs @@ -0,0 +1,614 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Generic types for the handling of [images]. +//! +//! [images]: https://drafts.csswg.org/css-images/#image-values + +use crate::custom_properties; +use crate::values::generics::position::PositionComponent; +use crate::values::generics::Optional; +use crate::values::serialize_atom_identifier; +use crate::Atom; +use crate::Zero; +use servo_arc::Arc; +use std::fmt::{self, Write}; +use style_traits::{CssWriter, ToCss}; + +/// An ` | none` value. +/// +/// https://drafts.csswg.org/css-images/#image-values +#[derive( + Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, +)] +#[repr(C, u8)] +pub enum GenericImage { + /// `none` variant. + None, + /// A `` image. + Url(ImageUrl), + + /// A `` image. Gradients are rather large, and not nearly as + /// common as urls, so we box them here to keep the size of this enum sane. + Gradient(Box), + /// A `-moz-image-rect` image. Also fairly large and rare. + // not cfg’ed out on non-Gecko to avoid `error[E0392]: parameter `MozImageRect` is never used` + // Instead we make MozImageRect an empty enum + Rect(Box), + + /// A `-moz-element(# )` + #[cfg(feature = "gecko")] + #[css(function = "-moz-element")] + Element(Atom), + + /// A paint worklet image. + /// + #[cfg(feature = "servo-layout-2013")] + PaintWorklet(PaintWorklet), + + /// A `` 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>), + + /// An `image-set()` function. + ImageSet(#[compute(field_bound)] Box>), +} + +pub use self::GenericImage as Image; + +/// +#[derive( + Clone, Debug, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem, ToCss, ToComputedValue, +)] +#[css(comma, function = "cross-fade")] +#[repr(C)] +pub struct GenericCrossFade { + /// All of the image percent pairings passed as arguments to + /// cross-fade. + #[css(iterable)] + pub elements: crate::OwnedSlice>, +} + +/// An optional percent and a cross fade image. +#[derive( + Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss, +)] +#[repr(C)] +pub struct GenericCrossFadeElement { + /// The percent of the final image that `image` will be. + pub percent: Optional, + /// A color or image that will be blended when cross-fade is + /// evaluated. + pub image: GenericCrossFadeImage, +} + +/// An image or a color. `cross-fade` takes either when blending +/// images together. +#[derive( + Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss, +)] +#[repr(C, u8)] +pub enum GenericCrossFadeImage { + /// 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; + +/// https://drafts.csswg.org/css-images-4/#image-set-notation +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToShmem)] +#[css(comma, function = "image-set")] +#[repr(C)] +pub struct GenericImageSet { + /// The index of the selected candidate. usize::MAX for specified values or invalid images. + #[css(skip)] + pub selected_index: usize, + + /// All of the image and resolution pairs. + #[css(iterable)] + pub items: crate::OwnedSlice>, +} + +/// An optional percent and a cross fade image. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] +#[repr(C)] +pub struct GenericImageSetItem { + /// ``. `` is converted to `Image::Url` at parse time. + pub image: Image, + /// The ``. + /// + /// TODO: Skip serialization if it is 1x. + pub resolution: Resolution, + + /// The `type()` + /// (Optional) Specify the image's MIME type + pub mime_type: crate::OwnedStr, + + /// True if mime_type has been specified + pub has_mime_type: bool, +} + +impl ToCss for GenericImageSetItem { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + self.image.to_css(dest)?; + dest.write_char(' ')?; + self.resolution.to_css(dest)?; + + if self.has_mime_type { + dest.write_char(' ')?; + dest.write_str("type(")?; + self.mime_type.to_css(dest)?; + dest.write_char(')')?; + } + Ok(()) + } +} + +pub use self::GenericImageSet as ImageSet; +pub use self::GenericImageSetItem as ImageSetItem; + +/// A CSS gradient. +/// +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] +#[repr(C)] +pub enum GenericGradient< + LineDirection, + LengthPercentage, + NonNegativeLength, + NonNegativeLengthPercentage, + Position, + Angle, + AngleOrPercentage, + Color, +> { + /// A linear gradient. + Linear { + /// Line direction + direction: LineDirection, + /// The color stops and interpolation hints. + items: crate::OwnedSlice>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, + /// A radial gradient. + Radial { + /// Shape of gradient + shape: GenericEndingShape, + /// Center of gradient + position: Position, + /// The color stops and interpolation hints. + items: crate::OwnedSlice>, + /// True if this is a repeating gradient. + repeating: bool, + /// Compatibility mode. + compat_mode: GradientCompatMode, + }, + /// A conic gradient. + Conic { + /// Start angle of gradient + angle: Angle, + /// Center of gradient + position: Position, + /// The color stops and interpolation hints. + items: crate::OwnedSlice>, + /// True if this is a repeating gradient. + repeating: bool, + }, +} + +pub use self::GenericGradient as Gradient; + +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, +)] +#[repr(u8)] +/// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes. +pub enum GradientCompatMode { + /// Modern syntax. + Modern, + /// `-webkit` prefix. + WebKit, + /// `-moz` prefix + Moz, +} + +/// A radial gradient's ending shape. +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, +)] +#[repr(C, u8)] +pub enum GenericEndingShape { + /// A circular gradient. + Circle(GenericCircle), + /// An elliptic gradient. + Ellipse(GenericEllipse), +} + +pub use self::GenericEndingShape as EndingShape; + +/// A circle shape. +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, +)] +#[repr(C, u8)] +pub enum GenericCircle { + /// A circle radius. + Radius(NonNegativeLength), + /// A circle extent. + Extent(ShapeExtent), +} + +pub use self::GenericCircle as Circle; + +/// An ellipse shape. +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, +)] +#[repr(C, u8)] +pub enum GenericEllipse { + /// An ellipse pair of radii. + Radii(NonNegativeLengthPercentage, NonNegativeLengthPercentage), + /// An ellipse extent. + Extent(ShapeExtent), +} + +pub use self::GenericEllipse as Ellipse; + +/// +#[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive( + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum ShapeExtent { + ClosestSide, + FarthestSide, + ClosestCorner, + FarthestCorner, + Contain, + Cover, +} + +/// A gradient item. +/// +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, +)] +#[repr(C, u8)] +pub enum GenericGradientItem { + /// A simple color stop, without position. + SimpleColorStop(Color), + /// A complex color stop, with a position. + ComplexColorStop { + /// The color for the stop. + color: Color, + /// The position for the stop. + position: T, + }, + /// An interpolation hint. + InterpolationHint(T), +} + +pub use self::GenericGradientItem as GradientItem; + +/// A color stop. +/// +#[derive( + Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem, +)] +pub struct ColorStop { + /// The color of this stop. + pub color: Color, + /// The position of this stop. + pub position: Option, +} + +impl ColorStop { + /// Convert the color stop into an appropriate `GradientItem`. + #[inline] + pub fn into_item(self) -> GradientItem { + match self.position { + Some(position) => GradientItem::ComplexColorStop { + color: self.color, + position, + }, + None => GradientItem::SimpleColorStop(self.color), + } + } +} + +/// Specified values for a paint worklet. +/// +#[cfg_attr(feature = "servo", derive(MallocSizeOf))] +#[derive(Clone, Debug, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)] +pub struct PaintWorklet { + /// The name the worklet was registered with. + pub name: Atom, + /// The arguments for the worklet. + /// TODO: store a parsed representation of the arguments. + #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] + #[compute(no_field_bound)] + #[resolve(no_field_bound)] + pub arguments: Vec>, +} + +impl ::style_traits::SpecifiedValueInfo for PaintWorklet {} + +impl ToCss for PaintWorklet { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + dest.write_str("paint(")?; + serialize_atom_identifier(&self.name, dest)?; + for argument in &self.arguments { + dest.write_str(", ")?; + argument.to_css(dest)?; + } + dest.write_char(')') + } +} + +/// Values for `moz-image-rect`. +/// +/// `-moz-image-rect(, top, right, bottom, left);` +#[allow(missing_docs)] +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[css(comma, function = "-moz-image-rect")] +#[repr(C)] +pub struct GenericMozImageRect { + pub url: MozImageRectUrl, + pub top: NumberOrPercentage, + pub right: NumberOrPercentage, + pub bottom: NumberOrPercentage, + pub left: NumberOrPercentage, +} + +pub use self::GenericMozImageRect as MozImageRect; + +impl fmt::Debug for Image +where + Image: ToCss, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_css(&mut CssWriter::new(f)) + } +} + +impl ToCss for Image +where + G: ToCss, + R: ToCss, + U: ToCss, + C: ToCss, + P: ToCss, + Resolution: ToCss, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + match *self { + Image::None => dest.write_str("none"), + Image::Url(ref url) => url.to_css(dest), + Image::Gradient(ref gradient) => gradient.to_css(dest), + Image::Rect(ref rect) => rect.to_css(dest), + #[cfg(feature = "servo-layout-2013")] + Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest), + #[cfg(feature = "gecko")] + Image::Element(ref selector) => { + dest.write_str("-moz-element(#")?; + serialize_atom_identifier(selector, dest)?; + dest.write_char(')') + }, + Image::ImageSet(ref is) => is.to_css(dest), + Image::CrossFade(ref cf) => cf.to_css(dest), + } + } +} + +impl ToCss for Gradient +where + D: LineDirection, + LP: ToCss, + NL: ToCss, + NLP: ToCss, + P: PositionComponent + ToCss, + A: ToCss, + AoP: ToCss, + C: ToCss, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + let (compat_mode, repeating) = match *self { + Gradient::Linear { + compat_mode, + repeating, + .. + } => (compat_mode, repeating), + Gradient::Radial { + compat_mode, + repeating, + .. + } => (compat_mode, repeating), + Gradient::Conic { repeating, .. } => (GradientCompatMode::Modern, repeating), + }; + + match compat_mode { + GradientCompatMode::WebKit => dest.write_str("-webkit-")?, + GradientCompatMode::Moz => dest.write_str("-moz-")?, + _ => {}, + } + + if repeating { + dest.write_str("repeating-")?; + } + + match *self { + Gradient::Linear { + ref direction, + ref items, + compat_mode, + .. + } => { + dest.write_str("linear-gradient(")?; + let mut skip_comma = if !direction.points_downwards(compat_mode) { + direction.to_css(dest, compat_mode)?; + false + } else { + true + }; + for item in &**items { + if !skip_comma { + dest.write_str(", ")?; + } + skip_comma = false; + item.to_css(dest)?; + } + }, + Gradient::Radial { + ref shape, + ref position, + ref items, + compat_mode, + .. + } => { + dest.write_str("radial-gradient(")?; + let omit_shape = match *shape { + EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) | + EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true, + _ => false, + }; + let omit_position = position.is_center(); + if compat_mode == GradientCompatMode::Modern { + if !omit_shape { + shape.to_css(dest)?; + if !omit_position { + dest.write_char(' ')?; + } + } + if !omit_position { + dest.write_str("at ")?; + position.to_css(dest)?; + } + } else { + if !omit_position { + position.to_css(dest)?; + if !omit_shape { + dest.write_str(", ")?; + } + } + if !omit_shape { + shape.to_css(dest)?; + } + } + let mut skip_comma = omit_shape && omit_position; + for item in &**items { + if !skip_comma { + dest.write_str(", ")?; + } + skip_comma = false; + item.to_css(dest)?; + } + }, + Gradient::Conic { + ref angle, + ref position, + ref items, + .. + } => { + dest.write_str("conic-gradient(")?; + let omit_angle = angle.is_zero(); + let omit_position = position.is_center(); + if !omit_angle { + dest.write_str("from ")?; + angle.to_css(dest)?; + if !omit_position { + dest.write_char(' ')?; + } + } + if !omit_position { + dest.write_str("at ")?; + position.to_css(dest)?; + } + let mut skip_comma = omit_angle && omit_position; + for item in &**items { + if !skip_comma { + dest.write_str(", ")?; + } + skip_comma = false; + item.to_css(dest)?; + } + }, + } + dest.write_char(')') + } +} + +/// The direction of a linear gradient. +pub trait LineDirection { + /// Whether this direction points towards, and thus can be omitted. + fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool; + + /// Serialises this direction according to the compatibility mode. + fn to_css(&self, dest: &mut CssWriter, compat_mode: GradientCompatMode) -> fmt::Result + where + W: Write; +} + +impl ToCss for Circle +where + L: ToCss, +{ + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + match *self { + Circle::Extent(ShapeExtent::FarthestCorner) | Circle::Extent(ShapeExtent::Cover) => { + dest.write_str("circle") + }, + Circle::Extent(keyword) => { + dest.write_str("circle ")?; + keyword.to_css(dest) + }, + Circle::Radius(ref length) => length.to_css(dest), + } + } +} -- cgit v1.2.3