Skip to main content

css_ast/rules/
font_face.rs

1use css_parse::DeclarationValue;
2use csskit_proc_macro::syntax;
3
4use super::prelude::*;
5use crate::{CssMetadata, FontDisplayValue, Unknown};
6
7/// <https://drafts.csswg.org/css-fonts/#font-face-rule>
8#[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/// The descriptors allowed inside a [`FontFaceRule`] block.
31#[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/// ```text,ignore
152/// <font-src-list>
153/// ```
154///
155/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-src>
156#[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/// ```text,ignore
164/// <unicode-range-token>#
165/// ```
166///
167/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-unicode-range>
168#[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/// ```text,ignore
176/// <font-family-name>
177/// ```
178///
179/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-family>
180#[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/// ```text,ignore
188/// auto | normal | italic | left | right | oblique [ <angle [-90deg,90deg]>{1,2} ]?
189/// ```
190///
191/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-style>
192#[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/// ```text,ignore
200/// auto | <font-weight-absolute>{1,2}
201/// ```
202///
203/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight>
204#[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/// ```text,ignore
212/// auto | <'font-width'>{1,2}
213/// ```
214///
215/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-width>
216#[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/// ```text,ignore
224/// auto | [ <number> ]{1,2}
225/// ```
226///
227/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-font-size>
228#[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/// ```text,ignore
236/// normal | <feature-tag-value>#
237/// ```
238///
239/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings>
240#[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/// ```text,ignore
248/// normal | [ <opentype-tag> <number> ]#
249/// ```
250///
251/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-variation-settings>
252#[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/// ```text,ignore
260/// normal | <string>
261/// ```
262///
263/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-language-override>
264#[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/// ```text,ignore
272/// auto | <string>
273/// ```
274///
275/// <https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-named-instance>
276#[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/// ```text,ignore
284/// <percentage [0,∞]>
285/// ```
286///
287/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-size-adjust>
288#[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/// ```text,ignore
296/// [ normal | <percentage [0,∞]> ]{1,2}
297/// ```
298///
299/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-ascent-override>
300#[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/// ```text,ignore
308/// [ normal | <percentage [0,∞]> ]{1,2}
309/// ```
310///
311/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-descent-override>
312#[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/// ```text,ignore
320/// [ normal | <percentage [0,∞]> ]{1,2}
321/// ```
322///
323/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-line-gap-override>
324#[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/// ```text,ignore
332/// [ normal | from-font | <percentage> ]{1,2}
333/// ```
334///
335/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-superscript-position-override>
336#[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/// ```text,ignore
344/// [ normal | from-font | <percentage> ]{1,2}
345/// ```
346///
347/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-subscript-position-override>
348#[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/// ```text,ignore
356/// [ normal | from-font | <percentage [0,∞]> ]{1,2}
357/// ```
358///
359/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-superscript-size-override>
360#[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/// ```text,ignore
368/// [ normal | from-font | <percentage [0,∞]> ]{1,2}
369/// ```
370///
371/// <https://drafts.csswg.org/css-fonts-5/#descdef-font-face-subscript-size-override>
372#[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}