diff --git a/Cargo.lock b/Cargo.lock index 3a156cf1..49d1269b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -762,7 +762,7 @@ dependencies = [ "assert_cmd", "assert_fs", "atty", - "bitflags 2.4.1", + "bitflags 2.6.0", "browserslist-rs", "clap", "const-str", @@ -776,6 +776,7 @@ dependencies = [ "jemallocator", "lazy_static", "lightningcss-derive", + "oxvg_path", "parcel_selectors", "parcel_sourcemap", "paste", @@ -892,7 +893,7 @@ version = "2.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72e0dc78e0524286630914db66e31bad70160e379705a9ce92e0161ce2389d89" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "ctor", "napi-derive", "napi-sys", @@ -988,11 +989,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" +[[package]] +name = "oxvg_path" +version = "0.0.1-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00fb8e08be2a3fcb2ff98de9122a82295dd6ef2cc9596f3c14a8c7fcf3d5a5bc" +dependencies = [ + "bitflags 2.6.0", + "ryu", +] + [[package]] name = "parcel_selectors" version = "0.27.0" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "cssparser", "fxhash", "log", @@ -1387,7 +1398,7 @@ version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -1396,9 +1407,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" diff --git a/Cargo.toml b/Cargo.toml index 7b1cb511..548de688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ const-str = "0.3.1" pathdiff = "0.2.1" ahash = "0.8.7" paste = "1.0.12" +oxvg_path = "0.0.1-beta.2" # CLI deps atty = { version = "0.2", optional = true } clap = { version = "3.0.6", features = ["derive"], optional = true } diff --git a/src/values/shape.rs b/src/values/shape.rs index 9cb5f585..082d8fee 100644 --- a/src/values/shape.rs +++ b/src/values/shape.rs @@ -1,5 +1,7 @@ //! CSS shape values for masking and clipping. +use std::fmt::Write; + use super::length::LengthPercentage; use super::position::Position; use super::rect::Rect; @@ -11,6 +13,7 @@ use crate::traits::{Parse, ToCss}; #[cfg(feature = "visitor")] use crate::visitor::Visit; use cssparser::*; +use oxvg_path; /// A CSS [``](https://www.w3.org/TR/css-shapes-1/#basic-shape-functions) value. #[derive(Debug, Clone, PartialEq)] @@ -31,6 +34,8 @@ pub enum BasicShape { Ellipse(Ellipse), /// A polygon. Polygon(Polygon), + /// A path + Path(Path), } /// An [`inset()`](https://www.w3.org/TR/css-shapes-1/#funcdef-inset) rectangle shape. @@ -124,6 +129,15 @@ pub struct Point { y: LengthPercentage, } +/// A path within a `path()` shape. +/// +/// See [Path](oxvg_path::Path). +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "visitor", derive(Visit))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] +pub struct Path(pub oxvg_path::Path); + enum_property! { /// A [``](https://www.w3.org/TR/css-shapes-1/#typedef-fill-rule) used to /// determine the interior of a `polygon()` shape. @@ -152,6 +166,7 @@ impl<'i> Parse<'i> for BasicShape { "circle" => Ok(BasicShape::Circle(input.parse_nested_block(Circle::parse)?)), "ellipse" => Ok(BasicShape::Ellipse(input.parse_nested_block(Ellipse::parse)?)), "polygon" => Ok(BasicShape::Polygon(input.parse_nested_block(Polygon::parse)?)), + "path" => Ok(BasicShape::Path(input.parse_nested_block(Path::parse)?)), _ => Err(location.new_unexpected_token_error(Token::Ident(f.clone()))), } } @@ -233,6 +248,16 @@ impl<'i> Parse<'i> for Point { } } +impl<'i> Parse<'i> for Path { + fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { + let string = input.expect_string()?.to_string(); + match oxvg_path::Path::parse(string) { + Ok(path) => Ok(Path(path)), + Err(_) => Err(input.new_custom_error(ParserError::InvalidValue)), + } + } +} + impl ToCss for BasicShape { fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> where @@ -259,6 +284,11 @@ impl ToCss for BasicShape { poly.to_css(dest)?; dest.write_char(')') } + BasicShape::Path(path) => { + dest.write_str("polygon(")?; + path.to_css(dest)?; + dest.write_char(')') + } } } } @@ -359,3 +389,12 @@ impl ToCss for Point { self.y.to_css(dest) } } + +impl ToCss for Path { + fn to_css(&self, dest: &mut Printer) -> Result<(), PrinterError> + where + W: std::fmt::Write, + { + Ok(write!(dest, "{}", self.0)?) + } +}