servo/components/style/values/generics/image.rs
Emilio Cobos Álvarez 36ff89bd28
style: Remove HasViewportPercentage.
It's not needed since #18268
2017-08-29 23:51:21 +02:00

331 lines
11 KiB
Rust

/* 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 http://mozilla.org/MPL/2.0/. */
//! Generic types for the handling of [images].
//!
//! [images]: https://drafts.csswg.org/css-images/#image-values
use Atom;
use cssparser::serialize_identifier;
use custom_properties::SpecifiedValue;
use std::fmt;
use style_traits::ToCss;
use values::computed::ComputedValueAsSpecified;
/// An [image].
///
/// [image]: https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Image<Gradient, MozImageRect, ImageUrl> {
/// A `<url()>` image.
Url(ImageUrl),
/// A `<gradient>` image.
Gradient(Gradient),
/// A `-moz-image-rect` image
Rect(MozImageRect),
/// A `-moz-element(# <element-id>)`
Element(Atom),
/// A paint worklet image.
/// https://drafts.css-houdini.org/css-paint-api/
#[cfg(feature = "servo")]
PaintWorklet(PaintWorklet),
}
/// A CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle> {
/// Gradients can be linear or radial.
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle>,
/// The color stops and interpolation hints.
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
/// True if this is a repeating gradient.
#[compute(clone)]
pub repeating: bool,
/// Compatibility mode.
#[compute(clone)]
pub compat_mode: CompatMode,
}
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes.
pub enum CompatMode {
/// Modern syntax.
Modern,
/// `-webkit` prefix.
WebKit,
/// `-moz` prefix
Moz,
}
/// A gradient kind.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle> {
/// A linear gradient.
Linear(LineDirection),
/// A radial gradient.
Radial(EndingShape<Length, LengthOrPercentage>, Position, Option<Angle>),
}
/// A radial gradient's ending shape.
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum EndingShape<Length, LengthOrPercentage> {
/// A circular gradient.
Circle(Circle<Length>),
/// An elliptic gradient.
Ellipse(Ellipse<LengthOrPercentage>),
}
/// A circle shape.
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Circle<Length> {
/// A circle radius.
Radius(Length),
/// A circle extent.
Extent(ShapeExtent),
}
/// An ellipse shape.
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Ellipse<LengthOrPercentage> {
/// An ellipse pair of radii.
Radii(LengthOrPercentage, LengthOrPercentage),
/// An ellipse extent.
Extent(ShapeExtent),
}
/// https://drafts.csswg.org/css-images/#typedef-extent-keyword
define_css_keyword_enum!(ShapeExtent:
"closest-side" => ClosestSide,
"farthest-side" => FarthestSide,
"closest-corner" => ClosestCorner,
"farthest-corner" => FarthestCorner,
"contain" => Contain,
"cover" => Cover
);
impl ComputedValueAsSpecified for ShapeExtent {}
/// A gradient item.
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum GradientItem<Color, LengthOrPercentage> {
/// A color stop.
ColorStop(ColorStop<Color, LengthOrPercentage>),
/// An interpolation hint.
InterpolationHint(LengthOrPercentage),
}
/// A color stop.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, Copy, PartialEq, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ColorStop<Color, LengthOrPercentage> {
/// The color of this stop.
pub color: Color,
/// The position of this stop.
pub position: Option<LengthOrPercentage>,
}
/// Specified values for a paint worklet.
/// https://drafts.css-houdini.org/css-paint-api/
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
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.
pub arguments: Vec<SpecifiedValue>,
}
impl ComputedValueAsSpecified for PaintWorklet {}
impl ToCss for PaintWorklet {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_str("paint(")?;
serialize_identifier(&*self.name.to_string(), dest)?;
for argument in &self.arguments {
dest.write_str(", ")?;
argument.to_css(dest)?;
}
dest.write_str(")")
}
}
/// Values for `moz-image-rect`.
///
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[css(comma, function)]
#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub url: MozImageRectUrl,
pub top: NumberOrPercentage,
pub right: NumberOrPercentage,
pub bottom: NumberOrPercentage,
pub left: NumberOrPercentage,
}
impl<G, R, U> fmt::Debug for Image<G, R, U>
where G: fmt::Debug, R: fmt::Debug, U: fmt::Debug + ToCss
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Image::Url(ref url) => url.to_css(f),
Image::Gradient(ref grad) => grad.fmt(f),
Image::Rect(ref rect) => rect.fmt(f),
#[cfg(feature = "servo")]
Image::PaintWorklet(ref paint_worklet) => paint_worklet.fmt(f),
Image::Element(ref selector) => {
f.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), f)?;
f.write_str(")")
},
}
}
}
impl<G, R, U> ToCss for Image<G, R, U>
where G: ToCss, R: ToCss, U: ToCss
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
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")]
Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest),
Image::Element(ref selector) => {
dest.write_str("-moz-element(#")?;
serialize_identifier(&selector.to_string(), dest)?;
dest.write_str(")")
},
}
}
}
impl<D, L, LoP, P, C, A> ToCss for Gradient<D, L, LoP, P, C, A>
where D: LineDirection, L: ToCss, LoP: ToCss, P: ToCss, C: ToCss, A: ToCss
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match self.compat_mode {
CompatMode::WebKit => dest.write_str("-webkit-")?,
CompatMode::Moz => dest.write_str("-moz-")?,
_ => {},
}
if self.repeating {
dest.write_str("repeating-")?;
}
dest.write_str(self.kind.label())?;
dest.write_str("-gradient(")?;
let mut skip_comma = match self.kind {
GradientKind::Linear(ref direction) if direction.points_downwards() => true,
GradientKind::Linear(ref direction) => {
direction.to_css(dest, self.compat_mode)?;
false
},
GradientKind::Radial(ref shape, ref position, ref angle) => {
let omit_shape = match *shape {
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) |
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => {
true
},
_ => false,
};
if self.compat_mode == CompatMode::Modern {
if !omit_shape {
shape.to_css(dest)?;
dest.write_str(" ")?;
}
dest.write_str("at ")?;
position.to_css(dest)?;
} else {
position.to_css(dest)?;
if let Some(ref a) = *angle {
dest.write_str(" ")?;
a.to_css(dest)?;
}
if !omit_shape {
dest.write_str(", ")?;
shape.to_css(dest)?;
}
}
false
},
};
for item in &self.items {
if !skip_comma {
dest.write_str(", ")?;
}
skip_comma = false;
item.to_css(dest)?;
}
dest.write_str(")")
}
}
impl<D, L, LoP, P, A> GradientKind<D, L, LoP, P, A> {
fn label(&self) -> &str {
match *self {
GradientKind::Linear(..) => "linear",
GradientKind::Radial(..) => "radial",
}
}
}
/// The direction of a linear gradient.
pub trait LineDirection {
/// Whether this direction points towards, and thus can be omitted.
fn points_downwards(&self) -> bool;
/// Serialises this direction according to the compatibility mode.
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
where W: fmt::Write;
}
impl<L> ToCss for Circle<L>
where
L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::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)
},
}
}
}
impl<C, L> fmt::Debug for ColorStop<C, L>
where C: fmt::Debug, L: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.color)?;
if let Some(ref pos) = self.position {
write!(f, " {:?}", pos)?;
}
Ok(())
}
}