diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e2914d..21bfe4d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ This release has an [MSRV] of 1.75. ### Added +#### Fontique + +- `FontStretch`, `FontStyle`, and `FontWeight` get helper functions `from_fontconfig` ([#212] by [@waywardmonkeys][]) + #### Parley - `Generation` on `PlainEditor` to help implement lazy drawing. ([#143] by [@xorgy]) diff --git a/fontique/src/attributes.rs b/fontique/src/attributes.rs index 0bad9e65..d57768e5 100644 --- a/fontique/src/attributes.rs +++ b/fontique/src/attributes.rs @@ -191,6 +191,28 @@ impl FontStretch { } } +impl FontStretch { + /// Creates a new stretch attribute with the given value from Fontconfig. + /// + /// The values are determined based on the [fonts.conf documentation]. + /// + /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html + pub fn from_fontconfig(width: i32) -> Self { + match width { + 50 => Self::ULTRA_CONDENSED, + 63 => Self::EXTRA_CONDENSED, + 75 => Self::CONDENSED, + 87 => Self::SEMI_CONDENSED, + 100 => Self::NORMAL, + 113 => Self::SEMI_EXPANDED, + 125 => Self::EXPANDED, + 150 => Self::EXTRA_EXPANDED, + 200 => Self::ULTRA_EXPANDED, + _ => Self::from_ratio(width as f32 / 100.0), + } + } +} + impl fmt::Display for FontStretch { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let value = self.0 * 1000.0; @@ -304,6 +326,49 @@ impl FontWeight { } } +impl FontWeight { + /// Creates a new weight attribute with the given value from Fontconfig. + /// + /// The values are determined based on the [fonts.conf documentation]. + /// + /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html + pub fn from_fontconfig(weight: i32) -> Self { + // A selection of OpenType weights (first) and their corresponding fontconfig value (second) + // Invariant: The fontconfig values are sorted + const MAP: &[(i32, i32)] = &[ + (0, 0), + (100, 0), + (200, 40), + (300, 50), + (350, 55), + (380, 75), + (400, 80), + (500, 100), + (600, 180), + (700, 200), + (800, 205), + (900, 210), + (950, 215), + ]; + for (i, (ot, fc)) in MAP.iter().skip(1).enumerate() { + if weight == *fc { + return Self::new(*ot as f32); + } + // Linear interpolation if not an exact match + if weight < *fc { + let weight = weight as f32; + let fc_a = MAP[i - 1].1 as f32; + let fc_b = *fc as f32; + let ot_a = MAP[i - 1].1 as f32; + let ot_b = *ot as f32; + let t = (fc_a - fc_b) / (weight - fc_a); + return Self::new(ot_a + (ot_b - ot_a) * t); + } + } + Self::EXTRA_BLACK + } +} + impl Default for FontWeight { fn default() -> Self { Self::NORMAL @@ -399,6 +464,21 @@ impl FontStyle { } } +impl FontStyle { + /// Creates a new style attribute with the given value from Fontconfig. + /// + /// The values are determined based on the [fonts.conf documentation]. + /// + /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html + pub fn from_fontconfig(slant: i32) -> Self { + match slant { + 100 => Self::Italic, + 110 => Self::Oblique(None), + _ => Self::Normal, + } + } +} + impl fmt::Display for FontStyle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let value = match self { diff --git a/fontique/src/backend/fontconfig/cache.rs b/fontique/src/backend/fontconfig/cache.rs index 9eba2aea..79e13d33 100644 --- a/fontique/src/backend/fontconfig/cache.rs +++ b/fontique/src/backend/fontconfig/cache.rs @@ -6,83 +6,6 @@ use fontconfig_cache_parser::{Cache, CharSetLeaf, Object, Pattern, Value}; use std::io::Read; use std::path::PathBuf; -impl FontStretch { - /// Creates a new stretch attribute with the given value from Fontconfig. - /// - /// The values are determined based on the [fonts.conf documentation]. - /// - /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html - pub fn from_fc(width: i32) -> Self { - match width { - 50 => Self::ULTRA_CONDENSED, - 63 => Self::EXTRA_CONDENSED, - 75 => Self::CONDENSED, - 87 => Self::SEMI_CONDENSED, - 100 => Self::NORMAL, - 113 => Self::SEMI_EXPANDED, - 125 => Self::EXPANDED, - 150 => Self::EXTRA_EXPANDED, - 200 => Self::ULTRA_EXPANDED, - _ => Self::from_ratio(width as f32 / 100.0), - } - } -} - -impl FontStyle { - /// Creates a new style attribute with the given value from Fontconfig. - /// - /// The values are determined based on the [fonts.conf documentation]. - /// - /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html - fn from_fc(slant: i32) -> Self { - match slant { - 100 => Self::Italic, - 110 => Self::Oblique(None), - _ => Self::Normal, - } - } -} - -impl FontWeight { - /// Creates a new weight attribute with the given value from Fontconfig. - /// - /// The values are determined based on the [fonts.conf documentation]. - /// - /// [fonts.conf documentation]: https://www.freedesktop.org/software/fontconfig/fontconfig-user.html - fn from_fc(weight: i32) -> Self { - const MAP: &[(i32, i32)] = &[ - (0, 0), - (100, 0), - (200, 40), - (300, 50), - (350, 55), - (380, 75), - (400, 80), - (500, 100), - (600, 180), - (700, 200), - (800, 205), - (900, 210), - (950, 215), - ]; - for (i, (ot, fc)) in MAP.iter().skip(1).enumerate() { - if weight == *fc { - return Self::new(*ot as f32); - } - if weight < *fc { - let weight = weight as f32; - let fc_a = MAP[i - 1].1 as f32; - let fc_b = *fc as f32; - let ot_a = MAP[i - 1].1 as f32; - let ot_b = *ot as f32; - let t = (fc_a - fc_b) / (weight - fc_a); - return Self::new(ot_a + (ot_b - ot_a) * t); - } - } - Self::EXTRA_BLACK - } -} - #[derive(Default)] pub struct CachedFont { pub family: Vec, @@ -177,21 +100,21 @@ fn parse_font( Object::Slant => { for val in elt.values().ok()? { if let Value::Int(i) = val.ok()? { - font.style = FontStyle::from_fc(i as _); + font.style = FontStyle::from_fontconfig(i as _); } } } Object::Weight => { for val in elt.values().ok()? { if let Value::Int(i) = val.ok()? { - font.weight = FontWeight::from_fc(i as _); + font.weight = FontWeight::from_fontconfig(i as _); } } } Object::Width => { for val in elt.values().ok()? { if let Value::Int(i) = val.ok()? { - font.stretch = FontStretch::from_fc(i as _); + font.stretch = FontStretch::from_fontconfig(i as _); } } }