1use css_parse::DeclarationValue;
2use csskit_proc_macro::syntax;
3
4use super::prelude::*;
5use crate::{CssMetadata, FontDisplayValue, Unknown};
6
7#[node]
9#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
11#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
12#[cfg_attr(feature = "css_feature_data", derive(::csskit_derives::ToCSSFeature), css_feature("css.at-rules.font-face"))]
13#[derive(csskit_derives::NodeWithMetadata)]
14#[metadata(node_kinds = AtRule, used_at_rules = FontFace)]
15pub struct FontFaceRule<'a> {
16 #[atom(CssAtomSet::FontFace)]
17 #[cfg_attr(feature = "visitable", visit(skip))]
18 pub name: T![AtKeyword],
19 #[metadata(block)]
20 pub block: FontFaceRuleBlock<'a>,
21}
22
23#[node]
24#[derive(Parse, Peek, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
26#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
27#[derive(csskit_derives::NodeWithMetadata)]
28pub struct FontFaceRuleBlock<'a>(DeclarationList<'a, FontFaceRuleStyleValue<'a>, CssMetadata>);
29
30#[node]
32#[derive(ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
34#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
35#[derive(csskit_derives::NodeWithMetadata)]
36pub enum FontFaceRuleStyleValue<'a> {
37 AscentOverride(FontFaceAscentOverrideDescriptor<'a>),
38 DescentOverride(FontFaceDescentOverrideDescriptor<'a>),
39 FontDisplay(FontDisplayValue),
40 FontFamily(FontFaceFontFamilyDescriptor<'a>),
41 FontFeatureSettings(FontFaceFontFeatureSettingsDescriptor<'a>),
42 FontLanguageOverride(FontFaceFontLanguageOverrideDescriptor<'a>),
43 FontNamedInstance(FontFaceFontNamedInstanceDescriptor<'a>),
44 FontSize(FontFaceFontSizeDescriptor<'a>),
45 FontStyle(FontFaceFontStyleDescriptor<'a>),
46 FontVariationSettings(FontFaceFontVariationSettingsDescriptor<'a>),
47 FontWeight(FontFaceFontWeightDescriptor<'a>),
48 FontWidth(FontFaceFontWidthDescriptor<'a>),
49 LineGapOverride(FontFaceLineGapOverrideDescriptor<'a>),
50 SizeAdjust(FontFaceSizeAdjustDescriptor<'a>),
51 Src(FontFaceSrcDescriptor<'a>),
52 SubscriptPositionOverride(FontFaceSubscriptPositionOverrideDescriptor<'a>),
53 SubscriptSizeOverride(FontFaceSubscriptSizeOverrideDescriptor<'a>),
54 SuperscriptPositionOverride(FontFaceSuperscriptPositionOverrideDescriptor<'a>),
55 SuperscriptSizeOverride(FontFaceSuperscriptSizeOverrideDescriptor<'a>),
56 UnicodeRange(FontFaceUnicodeRangeDescriptor<'a>),
57 Unknown(Unknown<'a>),
58}
59
60impl<'a> DeclarationValue<'a, CssMetadata> for FontFaceRuleStyleValue<'a> {
61 fn valid_declaration_name<I>(p: &Parser<'a, I>, c: Cursor) -> bool
62 where
63 I: Iterator<Item = Cursor> + Clone,
64 {
65 matches!(
66 p.to_atom::<CssAtomSet>(c),
67 CssAtomSet::AscentOverride
68 | CssAtomSet::DescentOverride
69 | CssAtomSet::FontDisplay
70 | CssAtomSet::FontFamily
71 | CssAtomSet::FontFeatureSettings
72 | CssAtomSet::FontLanguageOverride
73 | CssAtomSet::FontNamedInstance
74 | CssAtomSet::FontSize
75 | CssAtomSet::FontStyle
76 | CssAtomSet::FontVariationSettings
77 | CssAtomSet::FontWeight
78 | CssAtomSet::FontWidth
79 | CssAtomSet::LineGapOverride
80 | CssAtomSet::SizeAdjust
81 | CssAtomSet::Src
82 | CssAtomSet::SubscriptPositionOverride
83 | CssAtomSet::SubscriptSizeOverride
84 | CssAtomSet::SuperscriptPositionOverride
85 | CssAtomSet::SuperscriptSizeOverride
86 | CssAtomSet::UnicodeRange
87 )
88 }
89
90 fn is_unknown(&self) -> bool {
91 matches!(self, Self::Unknown(_))
92 }
93
94 fn needs_computing(&self) -> bool {
95 matches!(self, Self::Unknown(_))
96 }
97
98 fn parse_specified_declaration_value<I>(p: &mut Parser<'a, I>, c: Cursor) -> ParserResult<Self>
99 where
100 I: Iterator<Item = Cursor> + Clone,
101 {
102 Ok(match p.to_atom::<CssAtomSet>(c) {
103 CssAtomSet::AscentOverride => Self::AscentOverride(p.parse::<FontFaceAscentOverrideDescriptor<'a>>()?),
104 CssAtomSet::DescentOverride => Self::DescentOverride(p.parse::<FontFaceDescentOverrideDescriptor<'a>>()?),
105 CssAtomSet::FontDisplay => Self::FontDisplay(p.parse::<FontDisplayValue>()?),
106 CssAtomSet::FontFamily => Self::FontFamily(p.parse::<FontFaceFontFamilyDescriptor<'a>>()?),
107 CssAtomSet::FontFeatureSettings => {
108 Self::FontFeatureSettings(p.parse::<FontFaceFontFeatureSettingsDescriptor<'a>>()?)
109 }
110 CssAtomSet::FontLanguageOverride => {
111 Self::FontLanguageOverride(p.parse::<FontFaceFontLanguageOverrideDescriptor<'a>>()?)
112 }
113 CssAtomSet::FontNamedInstance => {
114 Self::FontNamedInstance(p.parse::<FontFaceFontNamedInstanceDescriptor<'a>>()?)
115 }
116 CssAtomSet::FontSize => Self::FontSize(p.parse::<FontFaceFontSizeDescriptor<'a>>()?),
117 CssAtomSet::FontStyle => Self::FontStyle(p.parse::<FontFaceFontStyleDescriptor<'a>>()?),
118 CssAtomSet::FontVariationSettings => {
119 Self::FontVariationSettings(p.parse::<FontFaceFontVariationSettingsDescriptor<'a>>()?)
120 }
121 CssAtomSet::FontWeight => Self::FontWeight(p.parse::<FontFaceFontWeightDescriptor<'a>>()?),
122 CssAtomSet::FontWidth => Self::FontWidth(p.parse::<FontFaceFontWidthDescriptor<'a>>()?),
123 CssAtomSet::LineGapOverride => Self::LineGapOverride(p.parse::<FontFaceLineGapOverrideDescriptor<'a>>()?),
124 CssAtomSet::SizeAdjust => Self::SizeAdjust(p.parse::<FontFaceSizeAdjustDescriptor<'a>>()?),
125 CssAtomSet::Src => Self::Src(p.parse::<FontFaceSrcDescriptor<'a>>()?),
126 CssAtomSet::SubscriptPositionOverride => {
127 Self::SubscriptPositionOverride(p.parse::<FontFaceSubscriptPositionOverrideDescriptor<'a>>()?)
128 }
129 CssAtomSet::SubscriptSizeOverride => {
130 Self::SubscriptSizeOverride(p.parse::<FontFaceSubscriptSizeOverrideDescriptor<'a>>()?)
131 }
132 CssAtomSet::SuperscriptPositionOverride => {
133 Self::SuperscriptPositionOverride(p.parse::<FontFaceSuperscriptPositionOverrideDescriptor<'a>>()?)
134 }
135 CssAtomSet::SuperscriptSizeOverride => {
136 Self::SuperscriptSizeOverride(p.parse::<FontFaceSuperscriptSizeOverrideDescriptor<'a>>()?)
137 }
138 CssAtomSet::UnicodeRange => Self::UnicodeRange(p.parse::<FontFaceUnicodeRangeDescriptor<'a>>()?),
139 _ => Err(Diagnostic::new(c, Diagnostic::unexpected))?,
140 })
141 }
142
143 fn parse_unknown_declaration_value<I>(p: &mut Parser<'a, I>, _: Cursor) -> ParserResult<Self>
144 where
145 I: Iterator<Item = Cursor> + Clone,
146 {
147 p.parse::<Unknown>().map(Self::Unknown)
148 }
149}
150
151#[syntax(" <font-src-list> ")]
157#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
158#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
159#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
160#[derive(csskit_derives::NodeWithMetadata)]
161pub struct FontFaceSrcDescriptor<'a>;
162
163#[syntax(" <unicode-range># ")]
169#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
170#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
171#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
172#[derive(csskit_derives::NodeWithMetadata)]
173pub struct FontFaceUnicodeRangeDescriptor<'a>;
174
175#[syntax(" <font-family-name> ")]
181#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
182#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
183#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
184#[derive(csskit_derives::NodeWithMetadata)]
185pub struct FontFaceFontFamilyDescriptor<'a>;
186
187#[syntax(" auto | normal | italic | left | right | oblique [ <angle [-90deg,90deg]>{1,2} ]? ")]
193#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
195#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
196#[derive(csskit_derives::NodeWithMetadata)]
197pub enum FontFaceFontStyleDescriptor<'a> {}
198
199#[syntax(" auto | <font-weight-absolute>{1,2} ")]
205#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
206#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
207#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
208#[derive(csskit_derives::NodeWithMetadata)]
209pub struct FontFaceFontWeightDescriptor<'a>;
210
211#[syntax(" auto | <'font-width'>{1,2} ")]
217#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
218#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
219#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
220#[derive(csskit_derives::NodeWithMetadata)]
221pub struct FontFaceFontWidthDescriptor<'a>;
222
223#[syntax(" auto | <number>{1,2} ")]
229#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
230#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
231#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
232#[derive(csskit_derives::NodeWithMetadata)]
233pub struct FontFaceFontSizeDescriptor<'a>;
234
235#[syntax(" normal | <feature-tag-value># ")]
241#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
243#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
244#[derive(csskit_derives::NodeWithMetadata)]
245pub struct FontFaceFontFeatureSettingsDescriptor<'a>;
246
247#[syntax(" normal | [ <opentype-tag> <number> ]# ")]
253#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
254#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
255#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
256#[derive(csskit_derives::NodeWithMetadata)]
257pub struct FontFaceFontVariationSettingsDescriptor<'a>;
258
259#[syntax(" normal | <string> ")]
265#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
266#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
267#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
268#[derive(csskit_derives::NodeWithMetadata)]
269pub struct FontFaceFontLanguageOverrideDescriptor<'a>;
270
271#[syntax(" auto | <string> ")]
277#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
278#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
279#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
280#[derive(csskit_derives::NodeWithMetadata)]
281pub struct FontFaceFontNamedInstanceDescriptor<'a>;
282
283#[syntax(" <percentage [0,∞]> ")]
289#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
290#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
291#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
292#[derive(csskit_derives::NodeWithMetadata)]
293pub struct FontFaceSizeAdjustDescriptor<'a>;
294
295#[syntax(" [ normal | <percentage [0,∞]> ]{1,2} ")]
301#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
302#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
303#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
304#[derive(csskit_derives::NodeWithMetadata)]
305pub struct FontFaceAscentOverrideDescriptor<'a>;
306
307#[syntax(" [ normal | <percentage [0,∞]> ]{1,2} ")]
313#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
314#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
315#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
316#[derive(csskit_derives::NodeWithMetadata)]
317pub struct FontFaceDescentOverrideDescriptor<'a>;
318
319#[syntax(" [ normal | <percentage [0,∞]> ]{1,2} ")]
325#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
326#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
327#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
328#[derive(csskit_derives::NodeWithMetadata)]
329pub struct FontFaceLineGapOverrideDescriptor<'a>;
330
331#[syntax(" [ normal | from-font | <percentage> ]{1,2} ")]
337#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
338#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
339#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
340#[derive(csskit_derives::NodeWithMetadata)]
341pub struct FontFaceSuperscriptPositionOverrideDescriptor<'a>;
342
343#[syntax(" [ normal | from-font | <percentage> ]{1,2} ")]
349#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
350#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
351#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
352#[derive(csskit_derives::NodeWithMetadata)]
353pub struct FontFaceSubscriptPositionOverrideDescriptor<'a>;
354
355#[syntax(" [ normal | from-font | <percentage [0,∞]> ]{1,2} ")]
361#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
362#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
363#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
364#[derive(csskit_derives::NodeWithMetadata)]
365pub struct FontFaceSuperscriptSizeOverrideDescriptor<'a>;
366
367#[syntax(" [ normal | from-font | <percentage [0,∞]> ]{1,2} ")]
373#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
374#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
375#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
376#[derive(csskit_derives::NodeWithMetadata)]
377pub struct FontFaceSubscriptSizeOverrideDescriptor<'a>;
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382 use css_parse::assert_parse;
383
384 #[test]
385 fn test_writes() {
386 assert_parse!(CssAtomSet::ATOMS, FontFaceRule, "@font-face{}");
387 assert_parse!(
388 CssAtomSet::ATOMS,
389 FontFaceRule,
390 "@font-face{font-family:\"Gentium\";src:url(gentium.woff2)format(woff2),local(Gentium)}"
391 );
392 assert_parse!(CssAtomSet::ATOMS, FontFaceRule, "@font-face{unicode-range:U+0-7F,U+4E00-9FFF}");
393 assert_parse!(CssAtomSet::ATOMS, FontFaceRule, "@font-face{font-weight:100 900;font-width:75% 125%}");
394 assert_parse!(
395 CssAtomSet::ATOMS,
396 FontFaceRule,
397 "@font-face{ascent-override:90%;descent-override:normal 10%;line-gap-override:0%}"
398 );
399 assert_parse!(
400 CssAtomSet::ATOMS,
401 FontFaceRule,
402 "@font-face{size-adjust:105%;font-display:swap;font-named-instance:\"Book\"}"
403 );
404 assert_parse!(
405 CssAtomSet::ATOMS,
406 FontFaceRule,
407 "@font-face{superscript-size-override:from-font;subscript-position-override:normal 20%}"
408 );
409 assert_parse!(CssAtomSet::ATOMS, FontFaceRule, "@font-face{font-style:oblique 14deg 30deg;font-size:1 2}");
410 assert_parse!(
411 CssAtomSet::ATOMS,
412 FontFaceRule,
413 "@font-face{font-feature-settings:\"liga\" off;font-variation-settings:\"wght\" 400}"
414 );
415 }
416
417 #[test]
418 fn test_unknown_descriptor() {
419 assert_parse!(CssAtomSet::ATOMS, FontFaceRule, "@font-face{color:red}");
420 }
421}