//! CSS properties used in SVG. use crate::error::{ParserError, PrinterError}; use crate::macros::enum_property; use crate::printer::Printer; use crate::targets::{Browsers, Targets}; use crate::traits::{FallbackValues, IsCompatible, Parse, ToCss}; use crate::values::length::LengthPercentage; use crate::values::{color::CssColor, url::Url}; #[cfg(feature = "visitor")] use crate::visitor::Visit; use cssparser::*; /// An SVG [``](https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint) value /// used in the `fill` and `stroke` properties. #[derive(Debug, Clone, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "type", rename_all = "kebab-case") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] pub enum SVGPaint<'i> { /// A URL reference to a paint server element, e.g. `linearGradient`, `radialGradient`, and `pattern`. Url { #[cfg_attr(feature = "serde", serde(borrow))] /// The url of the paint server. url: Url<'i>, /// A fallback to be used used in case the paint server cannot be resolved. fallback: Option, }, /// A solid color paint. #[cfg_attr(feature = "serde", serde(with = "crate::serialization::ValueWrapper::"))] Color(CssColor), /// Use the paint value of fill from a context element. ContextFill, /// Use the paint value of stroke from a context element. ContextStroke, /// No paint. None, } /// A fallback for an SVG paint in case a paint server `url()` cannot be resolved. /// /// See [SVGPaint](SVGPaint). #[derive(Debug, Clone, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "type", content = "value", rename_all = "kebab-case") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum SVGPaintFallback { /// No fallback. None, /// A solid color. Color(CssColor), } impl<'i> FallbackValues for SVGPaint<'i> { fn get_fallbacks(&mut self, targets: Targets) -> Vec { match self { SVGPaint::Color(color) => color .get_fallbacks(targets) .into_iter() .map(|color| SVGPaint::Color(color)) .collect(), SVGPaint::Url { url, fallback: Some(SVGPaintFallback::Color(color)), } => color .get_fallbacks(targets) .into_iter() .map(|color| SVGPaint::Url { url: url.clone(), fallback: Some(SVGPaintFallback::Color(color)), }) .collect(), _ => Vec::new(), } } } impl IsCompatible for SVGPaint<'_> { fn is_compatible(&self, browsers: Browsers) -> bool { match self { SVGPaint::Color(c) | SVGPaint::Url { fallback: Some(SVGPaintFallback::Color(c)), .. } => c.is_compatible(browsers), SVGPaint::Url { .. } | SVGPaint::None | SVGPaint::ContextFill | SVGPaint::ContextStroke => true, } } } enum_property! { /// A value for the [stroke-linecap](https://www.w3.org/TR/SVG2/painting.html#LineCaps) property. pub enum StrokeLinecap { /// The stroke does not extend beyond its endpoints. Butt, /// The ends of the stroke are rounded. Round, /// The ends of the stroke are squared. Square, } } enum_property! { /// A value for the [stroke-linejoin](https://www.w3.org/TR/SVG2/painting.html#LineJoin) property. pub enum StrokeLinejoin { /// A sharp corner is to be used to join path segments. Miter, /// Same as `miter` but clipped beyond `stroke-miterlimit`. MiterClip, /// A round corner is to be used to join path segments. Round, /// A bevelled corner is to be used to join path segments. Bevel, /// An arcs corner is to be used to join path segments. Arcs, } } /// A value for the [stroke-dasharray](https://www.w3.org/TR/SVG2/painting.html#StrokeDashing) property. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "type", content = "value", rename_all = "kebab-case") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum StrokeDasharray { /// No dashing is used. None, /// Specifies a dashing pattern to use. Values(Vec), } impl<'i> Parse<'i> for StrokeDasharray { fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() { return Ok(StrokeDasharray::None); } input.skip_whitespace(); let mut results = vec![LengthPercentage::parse(input)?]; loop { input.skip_whitespace(); let comma_location = input.current_source_location(); let comma = input.try_parse(|i| i.expect_comma()).is_ok(); if let Ok(item) = input.try_parse(LengthPercentage::parse) { results.push(item); } else if comma { return Err(comma_location.new_unexpected_token_error(Token::Comma)); } else { break; } } Ok(StrokeDasharray::Values(results)) } } impl ToCss for StrokeDasharray { fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> where W: std::fmt::Write, { match self { StrokeDasharray::None => dest.write_str("none"), StrokeDasharray::Values(values) => { let mut first = true; for value in values { if first { first = false; } else { dest.write_char(' ')?; } value.to_css_unitless(dest)?; } Ok(()) } } } } /// A value for the [marker](https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties) properties. #[derive(Debug, Clone, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(tag = "type", content = "value", rename_all = "kebab-case") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] pub enum Marker<'i> { /// No marker. None, /// A url reference to a `` element. #[cfg_attr(feature = "serde", serde(borrow))] Url(Url<'i>), } /// A value for the [color-interpolation](https://www.w3.org/TR/SVG2/painting.html#ColorInterpolation) property. #[derive(Debug, Clone, Copy, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum ColorInterpolation { /// The UA can choose between sRGB or linearRGB. Auto, /// Color interpolation occurs in the sRGB color space. SRGB, /// Color interpolation occurs in the linearized RGB color space LinearRGB, } /// A value for the [color-rendering](https://www.w3.org/TR/SVG2/painting.html#ColorRendering) property. #[derive(Debug, Clone, Copy, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum ColorRendering { /// The UA can choose a tradeoff between speed and quality. Auto, /// The UA shall optimize speed over quality. OptimizeSpeed, /// The UA shall optimize quality over speed. OptimizeQuality, } /// A value for the [shape-rendering](https://www.w3.org/TR/SVG2/painting.html#ShapeRendering) property. #[derive(Debug, Clone, Copy, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum ShapeRendering { /// The UA can choose an appropriate tradeoff. Auto, /// The UA shall optimize speed. OptimizeSpeed, /// The UA shall optimize crisp edges. CrispEdges, /// The UA shall optimize geometric precision. GeometricPrecision, } /// A value for the [text-rendering](https://www.w3.org/TR/SVG2/painting.html#TextRendering) property. #[derive(Debug, Clone, Copy, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum TextRendering { /// The UA can choose an appropriate tradeoff. Auto, /// The UA shall optimize speed. OptimizeSpeed, /// The UA shall optimize legibility. OptimizeLegibility, /// The UA shall optimize geometric precision. GeometricPrecision, } /// A value for the [image-rendering](https://www.w3.org/TR/SVG2/painting.html#ImageRendering) property. #[derive(Debug, Clone, Copy, PartialEq, Parse, ToCss)] #[cfg_attr(feature = "visitor", derive(Visit))] #[cfg_attr( feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(rename_all = "lowercase") )] #[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] pub enum ImageRendering { /// The UA can choose a tradeoff between speed and quality. Auto, /// The UA shall optimize speed over quality. OptimizeSpeed, /// The UA shall optimize quality over speed. OptimizeQuality, }