Skip to content

Commit

Permalink
fontique: Move creation of attributes from fontconfig (#212)
Browse files Browse the repository at this point in the history
This exposes `from_fontconfig` functions on `FontStretch`, `FontStyle`,
and `FontWeight` rather than only defining them locally within the
fontconfig code.

This is in preparation for a change similar to #209 where these types
and others get pulled into a shared vocabulary crate and this sort of
constructor helper would be useful to others.

---------

Co-authored-by: Daniel McNab <[email protected]>
  • Loading branch information
waywardmonkeys and DJMcNab authored Dec 9, 2024
1 parent 1d9d344 commit 0e851bb
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 80 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
80 changes: 80 additions & 0 deletions fontique/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
83 changes: 3 additions & 80 deletions fontique/src/backend/fontconfig/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
Expand Down Expand Up @@ -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 _);
}
}
}
Expand Down

0 comments on commit 0e851bb

Please sign in to comment.