Skip to main content

css_ast/types/
mask_layer.rs

1use super::prelude::*;
2use crate::{CompositingOperator, GeometryBox, MaskReference, MaskingMode, PositionAndSize, RepeatStyle};
3use css_parse::Box;
4
5/// <https://drafts.csswg.org/css-masking-1/#typedef-mask-layer>
6///
7/// ```text,ignore
8/// <mask-layer> = <mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> ||
9///   <geometry-box> || [ <geometry-box> | no-clip ] || <compositing-operator> ||
10///   <masking-mode>
11/// ```
12///
13/// The first `<geometry-box>` sets `mask-origin`, the second (or `no-clip`) sets
14/// `mask-clip`.
15#[node]
16#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[parse(all_must_occur)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
19#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
20#[derive(csskit_derives::NodeWithMetadata)]
21pub struct MaskLayer<'a> {
22	pub image: Option<MaskReference<'a>>,
23	pub position: Option<Box<'a, PositionAndSize<'a>>>,
24	pub repeat: Option<RepeatStyle>,
25	pub origin: Option<GeometryBox>,
26	pub clip: Option<MaskLayerClip>,
27	pub composite: Option<CompositingOperator>,
28	pub mode: Option<MaskingMode>,
29}
30
31/// The `[ <geometry-box> | no-clip ]` component of `<mask-layer>`, setting
32/// `mask-clip`.
33///
34/// ```text,ignore
35/// [ <geometry-box> | no-clip ]
36/// ```
37///
38/// <https://drafts.csswg.org/css-masking-1/#typedef-mask-layer>
39#[node]
40#[derive(Parse, Peek, ToSpan, SemanticEq, ToCursors, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
42#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
43#[derive(csskit_derives::NodeWithMetadata)]
44pub enum MaskLayerClip {
45	GeometryBox(GeometryBox),
46	#[atom(CssAtomSet::NoClip)]
47	NoClip(T![Ident]),
48}
49
50#[cfg(test)]
51mod tests {
52	use super::*;
53	use crate::CssAtomSet;
54	use css_parse::{assert_parse, assert_peek_false};
55
56	#[test]
57	fn test_writes() {
58		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "none");
59		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "url(mask.svg)");
60		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "center");
61		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "center / cover");
62		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "no-repeat");
63		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "fill-box");
64		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "no-clip");
65		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "border-box no-clip");
66		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "content-box border-box");
67		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "add");
68		assert_parse!(CssAtomSet::ATOMS, MaskLayer, "luminance");
69		assert_parse!(
70			CssAtomSet::ATOMS,
71			MaskLayer,
72			"url(mask.svg) center / cover no-repeat view-box no-clip add alpha"
73		);
74	}
75
76	#[test]
77	fn test_errors() {
78		assert_peek_false!(CssAtomSet::ATOMS, MaskLayer, "");
79	}
80}