1use super::prelude::*;
2use crate::Url;
3#[cfg(feature = "visitable")]
4use crate::visit::{NodeId, QueryableNode};
5
6#[node]
16#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
18#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit, queryable(skip))]
19#[cfg_attr(
20 feature = "css_feature_data",
21 derive(::csskit_derives::ToCSSFeature),
22 css_feature("css.at-rules.color-profile")
23)]
24#[derive(csskit_derives::NodeWithMetadata)]
25#[metadata(node_kinds = AtRule, used_at_rules = ColorProfile, property_kinds = Name)]
26pub struct ColorProfileRule<'a> {
27 #[cfg_attr(feature = "visitable", visit(skip))]
28 #[atom(CssAtomSet::ColorProfile)]
29 pub name: T![AtKeyword],
30 pub prelude: ColorProfilePrelude,
31 #[metadata(block)]
32 pub block: ColorProfileRuleBlock<'a>,
33}
34
35#[cfg(feature = "visitable")]
36impl<'a> QueryableNode for ColorProfileRule<'a> {
37 const NODE_ID: NodeId = NodeId::ColorProfileRule;
38
39 fn get_property(&self, kind: PropertyKind) -> Option<Cursor> {
40 match kind {
41 PropertyKind::Name => Some(self.prelude.ident()),
42 _ => None,
43 }
44 }
45}
46
47#[node]
48#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
49#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
50#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
51#[derive(csskit_derives::NodeWithMetadata)]
52pub enum ColorProfilePrelude {
53 Name(T![DashedIdent]),
54 #[atom(CssAtomSet::DeviceCmyk)]
55 DeviceCmyk(T![Ident]),
56}
57
58impl ColorProfilePrelude {
59 pub fn ident(&self) -> Cursor {
61 match self {
62 Self::Name(c) => (*c).into(),
63 Self::DeviceCmyk(c) => (*c).into(),
64 }
65 }
66}
67
68#[node]
69#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
71#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
72#[derive(csskit_derives::NodeWithMetadata)]
73pub struct ColorProfileRuleBlock<'a>(DeclarationList<'a, ColorProfileRuleStyleValue<'a>, CssMetadata>);
74
75#[node]
76#[derive(ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
78#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
79#[derive(csskit_derives::NodeWithMetadata)]
80pub enum ColorProfileRuleStyleValue<'a> {
81 Src(ColorProfileSrcValue),
82 RenderingIntent(RenderingIntentValue),
83 Components(ComponentsValue<'a>),
84 Unknown(ComponentValues<'a>),
85}
86
87#[node]
88#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
90#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
91#[derive(csskit_derives::NodeWithMetadata)]
92pub struct ColorProfileSrcValue(Url);
93
94#[node]
95#[derive(
96 Parse, Peek, IntoCursor, ToSpan, SemanticEq, ToCursors, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
97)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
99#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
100#[derive(csskit_derives::NodeWithMetadata)]
101pub enum RenderingIntentValue {
102 #[atom(CssAtomSet::RelativeColorimetric)]
103 RelativeColorimetric(T![Ident]),
104 #[atom(CssAtomSet::AbsoluteColorimetric)]
105 AbsoluteColorimetric(T![Ident]),
106 #[atom(CssAtomSet::Perceptual)]
107 Perceptual(T![Ident]),
108 #[atom(CssAtomSet::Saturation)]
109 Saturation(T![Ident]),
110}
111
112#[node]
113#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
114#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
115#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
116#[derive(csskit_derives::NodeWithMetadata)]
117pub struct ComponentsValue<'a>(pub CommaSeparated<'a, T![Ident], 1>);
118
119impl<'a> DeclarationValue<'a, CssMetadata> for ColorProfileRuleStyleValue<'a> {
120 fn valid_declaration_name<I>(p: &Parser<'a, I>, c: Cursor) -> bool
121 where
122 I: Iterator<Item = Cursor> + Clone,
123 {
124 matches!(p.to_atom::<CssAtomSet>(c), CssAtomSet::Src | CssAtomSet::RenderingIntent | CssAtomSet::Components)
125 }
126
127 fn is_unknown(&self) -> bool {
128 matches!(self, Self::Unknown(_))
129 }
130
131 fn needs_computing(&self) -> bool {
132 matches!(self, Self::Unknown(_))
133 }
134
135 fn parse_declaration_value<I>(p: &mut Parser<'a, I>, c: Cursor) -> ParserResult<Self>
136 where
137 I: Iterator<Item = Cursor> + Clone,
138 {
139 Ok(match p.to_atom::<CssAtomSet>(c) {
140 CssAtomSet::Src => Self::Src(p.parse::<ColorProfileSrcValue>()?),
141 CssAtomSet::RenderingIntent => Self::RenderingIntent(p.parse::<RenderingIntentValue>()?),
142 CssAtomSet::Components => Self::Components(p.parse::<ComponentsValue<'a>>()?),
143 _ => Self::Unknown(p.parse::<ComponentValues<'a>>()?),
144 })
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::CssAtomSet;
152 use css_parse::assert_parse;
153
154 #[test]
155 fn test_writes() {
156 assert_parse!(CssAtomSet::ATOMS, ColorProfileRule, "@color-profile --swop5c{src:url(\"swop.icc\")}");
157 assert_parse!(CssAtomSet::ATOMS, ColorProfileRule, "@color-profile device-cmyk{src:url(cmyk.icc)}");
158 assert_parse!(
159 CssAtomSet::ATOMS,
160 ColorProfileRule,
161 "@color-profile --unwise{src:url(unwise);components:mi,pi,ni;rendering-intent:perceptual}"
162 );
163 }
164}