lewp_css/domain/at_rules/font_feature_values/
at_rule.rs

1// This file is part of css. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT. No part of predicator, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
2// Copyright © 2017 The developers of css. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/css/master/COPYRIGHT.
3
4use {
5    super::{
6        FontFeatureValuesDeclaration,
7        PairValues,
8        SingleValue,
9        VectorValues,
10    },
11    crate::{
12        domain::at_rules::font_face::FamilyName,
13        parsers::{FontFeatureValuesAtRuleParser, ParserContext},
14        CustomParseError,
15    },
16    cssparser::{ParseError, Parser, RuleListParser, ToCss},
17    std::fmt,
18};
19
20/// The [`@font-feature-values`][font-feature-values] at-rule.
21///
22/// [font-feature-values]: <https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule>
23#[derive(Clone, Debug, PartialEq)]
24pub struct FontFeatureValuesAtRule {
25    /// Font family list for @font-feature-values rule.
26    /// Family names cannot contain generic families.
27    /// FamilyName also accepts only non-generic names.
28    pub family_names: Vec<FamilyName>,
29
30    /// A @swash block. Specifies a feature name that will work with the swash() functional notation of font-variant-alternates.
31    pub swash: Vec<FontFeatureValuesDeclaration<SingleValue>>,
32
33    /// A @stylistic block. Specifies a feature name that will work with the annotation() functional notation of font-variant-alternates.
34    pub stylistic: Vec<FontFeatureValuesDeclaration<SingleValue>>,
35
36    /// A @ornaments block. Specifies a feature name that will work with the ornaments() ] functional notation of font-variant-alternates.
37    pub ornaments: Vec<FontFeatureValuesDeclaration<SingleValue>>,
38
39    /// A @annotation block. Specifies a feature name that will work with the stylistic() functional notation of font-variant-alternates.
40    pub annotation: Vec<FontFeatureValuesDeclaration<SingleValue>>,
41
42    /// A @character-variant block. Specifies a feature name that will work with the styleset() functional notation of font-variant-alternates. The value can be a pair.
43    pub character_variant: Vec<FontFeatureValuesDeclaration<PairValues>>,
44
45    /// A @styleset block. Specifies a feature name that will work with the character-variant() functional notation of font-variant-alternates. The value can be a list.
46    pub styleset: Vec<FontFeatureValuesDeclaration<VectorValues>>,
47}
48
49impl ToCss for FontFeatureValuesAtRule {
50    fn to_css<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
51        dest.write_str("@font-feature-values ")?;
52        self.font_family_to_css(dest)?;
53        dest.write_char('{')?;
54        self.value_to_css(dest)?;
55        dest.write_char('}')
56    }
57}
58
59impl FontFeatureValuesAtRule {
60    #[inline(always)]
61    fn new(family_names: Vec<FamilyName>) -> Self {
62        Self {
63            family_names,
64            swash: vec![],
65            stylistic: vec![],
66            ornaments: vec![],
67            annotation: vec![],
68            character_variant: vec![],
69            styleset: vec![],
70        }
71    }
72
73    pub(crate) fn parse_body<'i: 't, 't>(
74        context: &ParserContext,
75        input: &mut Parser<'i, 't>,
76        family_names: Vec<FamilyName>,
77    ) -> Result<Self, ParseError<'i, CustomParseError<'i>>> {
78        let mut fontFeatureValuesRule = Self::new(family_names);
79
80        {
81            let iterator = RuleListParser::new_for_nested_rule(
82                input,
83                FontFeatureValuesAtRuleParser {
84                    context,
85                    rule: &mut fontFeatureValuesRule,
86                },
87            );
88            for possiblePreciseParseError in iterator {
89                if possiblePreciseParseError.is_err() {
90                    return Err(possiblePreciseParseError.unwrap_err().0);
91                }
92            }
93        }
94
95        Ok(fontFeatureValuesRule)
96    }
97
98    /// Prints font family names.
99    pub(crate) fn font_family_to_css<W: fmt::Write>(
100        &self,
101        dest: &mut W,
102    ) -> fmt::Result {
103        let mut iter = self.family_names.iter();
104        iter.next().unwrap().to_css(dest)?;
105        for val in iter {
106            dest.write_char(',')?;
107            val.to_css(dest)?;
108        }
109        Ok(())
110    }
111
112    /// Prints inside of `@font-feature-values` block.
113    pub(crate) fn value_to_css<W: fmt::Write>(
114        &self,
115        dest: &mut W,
116    ) -> fmt::Result {
117        #[inline(always)]
118        fn writeBlock<W: fmt::Write, T: ToCss>(
119            dest: &mut W,
120            name: &str,
121            block: &Vec<FontFeatureValuesDeclaration<T>>,
122        ) -> fmt::Result {
123            if !block.is_empty() {
124                dest.write_char('@')?;
125                dest.write_str(name)?;
126                dest.write_char('{')?;
127
128                let length = block.len();
129                if length != 0 {
130                    for index in 0..(length - 1) {
131                        (unsafe { block.get_unchecked(index) }).to_css(dest)?;
132                    }
133                    (unsafe { block.get_unchecked(length - 1) })
134                        .to_css_without_trailing_semicolon(dest)?;
135                }
136
137                dest.write_char('}')
138            } else {
139                Ok(())
140            }
141        }
142
143        writeBlock(dest, "swash", &self.swash)?;
144        writeBlock(dest, "stylistic", &self.stylistic)?;
145        writeBlock(dest, "ornaments", &self.ornaments)?;
146        writeBlock(dest, "annotation", &self.annotation)?;
147        writeBlock(dest, "character-variant", &self.character_variant)?;
148        writeBlock(dest, "styleset", &self.styleset)
149    }
150
151    /// Returns length of all at-rules.
152    pub fn len(&self) -> usize {
153        let mut len = self.swash.len();
154        len += self.stylistic.len();
155        len += self.ornaments.len();
156        len += self.annotation.len();
157        len += self.character_variant.len();
158        len + self.styleset.len()
159    }
160}