Skip to main content

topcoat_font/
format.rs

1//! Font file formats for the `format()` hint on a CSS `@font-face` `src`
2//! descriptor.
3
4/// A font file format, as named by the `format()` hint of a CSS `@font-face`
5/// `src` descriptor.
6///
7/// Displays as the CSS format keyword used inside `format(...)` (`woff2`,
8/// `opentype`, `embedded-opentype`, ...).
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum FontFormat {
11    /// OpenType Collection (`.otc`, `.ttc`), CSS `collection`.
12    Collection,
13    /// Embedded OpenType (`.eot`), CSS `embedded-opentype`.
14    EmbeddedOpenType,
15    /// OpenType (`.otf`, `.ttf`), CSS `opentype`.
16    OpenType,
17    /// SVG Font (`.svg`, `.svgz`), CSS `svg`.
18    ///
19    /// SVG fonts are deprecated and unsupported by most modern browsers.
20    Svg,
21    /// TrueType (`.ttf`), CSS `truetype`.
22    TrueType,
23    /// WOFF 1.0 (`.woff`), CSS `woff`.
24    Woff,
25    /// WOFF 2.0 (`.woff2`), CSS `woff2`.
26    Woff2,
27}
28
29impl FontFormat {
30    /// The CSS format keyword for this format, as written inside `format(...)`.
31    #[must_use]
32    pub const fn keyword(self) -> &'static str {
33        match self {
34            Self::Collection => "collection",
35            Self::EmbeddedOpenType => "embedded-opentype",
36            Self::OpenType => "opentype",
37            Self::Svg => "svg",
38            Self::TrueType => "truetype",
39            Self::Woff => "woff",
40            Self::Woff2 => "woff2",
41        }
42    }
43
44    /// The format named by the given CSS `format(...)` keyword, if the keyword
45    /// names a known format.
46    #[must_use]
47    pub fn from_keyword(keyword: &str) -> Option<Self> {
48        Some(match keyword {
49            "collection" => Self::Collection,
50            "embedded-opentype" => Self::EmbeddedOpenType,
51            "opentype" => Self::OpenType,
52            "svg" => Self::Svg,
53            "truetype" => Self::TrueType,
54            "woff" => Self::Woff,
55            "woff2" => Self::Woff2,
56            _ => return None,
57        })
58    }
59
60    /// The MIME type of this format, as used in a `type` attribute (e.g. on a
61    /// `<link rel="preload" as="font">`).
62    #[must_use]
63    pub const fn mime_type(self) -> &'static str {
64        match self {
65            Self::Collection => "font/collection",
66            Self::EmbeddedOpenType => "application/vnd.ms-fontobject",
67            Self::OpenType => "font/otf",
68            Self::Svg => "image/svg+xml",
69            Self::TrueType => "font/ttf",
70            Self::Woff => "font/woff",
71            Self::Woff2 => "font/woff2",
72        }
73    }
74
75    /// The human-readable name of this format.
76    #[must_use]
77    pub const fn name(self) -> &'static str {
78        match self {
79            Self::Collection => "OpenType Collection",
80            Self::EmbeddedOpenType => "Embedded OpenType",
81            Self::OpenType => "OpenType",
82            Self::Svg => "SVG Font",
83            Self::TrueType => "TrueType",
84            Self::Woff => "WOFF 1.0",
85            Self::Woff2 => "WOFF 2.0",
86        }
87    }
88
89    /// The file extensions associated with this format, without a leading dot.
90    ///
91    /// Some extensions are shared across formats (`ttf` is valid for both
92    /// [`OpenType`](Self::OpenType) and [`TrueType`](Self::TrueType)).
93    #[must_use]
94    pub const fn extensions(self) -> &'static [&'static str] {
95        match self {
96            Self::Collection => &["otc", "ttc"],
97            Self::EmbeddedOpenType => &["eot"],
98            Self::OpenType => &["otf", "ttf"],
99            Self::Svg => &["svg", "svgz"],
100            Self::TrueType => &["ttf"],
101            Self::Woff => &["woff"],
102            Self::Woff2 => &["woff2"],
103        }
104    }
105
106    /// Folds this format into a running content hash.
107    pub(crate) const fn hash(
108        self,
109        h: topcoat_core::fnv1a::Fnv1a<u64>,
110    ) -> topcoat_core::fnv1a::Fnv1a<u64> {
111        h.write(self.keyword().as_bytes())
112    }
113}
114
115impl std::fmt::Display for FontFormat {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.write_str(self.keyword())
118    }
119}