summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorPeng Guanwen <pg999w@outlook.com>2024-02-01 21:45:33 +0800
committerGitHub <noreply@github.com>2024-02-01 13:45:33 +0000
commit464a15bdca3ea3a54adc6410ba679597d7ca421b (patch)
tree9018afb236bc3b53e0a4f46766fda4128f272196 /crates
parent7d33436e55f8b1aec06d136ebe095dd86bf23e57 (diff)
Introduce override list to FontInfo (#3228)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/Cargo.toml1
-rw-r--r--crates/typst/src/text/font/book.rs92
-rw-r--r--crates/typst/src/text/font/exceptions.rs130
-rw-r--r--crates/typst/src/text/font/mod.rs1
-rw-r--r--crates/typst/src/text/font/variant.rs4
5 files changed, 171 insertions, 57 deletions
diff --git a/crates/typst/Cargo.toml b/crates/typst/Cargo.toml
index f04110ac..b9e3b494 100644
--- a/crates/typst/Cargo.toml
+++ b/crates/typst/Cargo.toml
@@ -41,6 +41,7 @@ lipsum = { workspace = true }
log = { workspace = true }
once_cell = { workspace = true }
palette = { workspace = true }
+phf = { workspace = true }
rayon = { workspace = true }
regex = { workspace = true }
roxmltree = { workspace = true }
diff --git a/crates/typst/src/text/font/book.rs b/crates/typst/src/text/font/book.rs
index 2e64533e..14b38583 100644
--- a/crates/typst/src/text/font/book.rs
+++ b/crates/typst/src/text/font/book.rs
@@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
use ttf_parser::{name_id, PlatformId, Tag};
use unicode_segmentation::UnicodeSegmentation;
+use super::exceptions::find_exception;
use crate::text::{Font, FontStretch, FontStyle, FontVariant, FontWeight};
/// Metadata about a collection of fonts.
@@ -206,6 +207,8 @@ impl FontInfo {
/// Compute metadata for a single ttf-parser face.
pub(super) fn from_ttf(ttf: &ttf_parser::Face) -> Option<Self> {
+ let ps_name = find_name(ttf, name_id::POST_SCRIPT_NAME);
+ let exception = ps_name.as_deref().and_then(find_exception);
// We cannot use Name ID 16 "Typographic Family", because for some
// fonts it groups together more than just Style / Weight / Stretch
// variants (e.g. Display variants of Noto fonts) and then some
@@ -222,45 +225,43 @@ impl FontInfo {
// because Name ID 1 "Family" sometimes contains "Display" and
// sometimes doesn't for the Display variants and that mixes things
// up.
- let family = {
- let mut family = find_name(ttf, name_id::FAMILY)?;
- if family.starts_with("Noto")
- || family.starts_with("NewCM")
- || family.starts_with("NewComputerModern")
- {
- family = find_name(ttf, name_id::FULL_NAME)?;
- }
- typographic_family(&family).to_string()
- };
+ let family =
+ exception.and_then(|c| c.family.map(str::to_string)).or_else(|| {
+ let mut family = find_name(ttf, name_id::FAMILY)?;
+ if family.starts_with("Noto") {
+ family = find_name(ttf, name_id::FULL_NAME)?;
+ }
+ Some(typographic_family(&family).to_string())
+ })?;
let variant = {
- let mut full = find_name(ttf, name_id::FULL_NAME).unwrap_or_default();
- full.make_ascii_lowercase();
-
- // Some fonts miss the relevant bits for italic or oblique, so
- // we also try to infer that from the full name.
- let italic = ttf.is_italic() || full.contains("italic");
- let oblique =
- ttf.is_oblique() || full.contains("oblique") || full.contains("slanted");
-
- let style = match (italic, oblique) {
- (false, false) => FontStyle::Normal,
- (true, _) => FontStyle::Italic,
- (_, true) => FontStyle::Oblique,
- };
-
- let weight = {
- let mut number = ttf.weight().to_number();
- if (family.starts_with("NewCM")
- || family.starts_with("New Computer Modern"))
- && full.contains("book")
- {
- number += 50;
+ let style = exception.and_then(|c| c.style).unwrap_or_else(|| {
+ let mut full = find_name(ttf, name_id::FULL_NAME).unwrap_or_default();
+ full.make_ascii_lowercase();
+
+ // Some fonts miss the relevant bits for italic or oblique, so
+ // we also try to infer that from the full name.
+ let italic = ttf.is_italic() || full.contains("italic");
+ let oblique = ttf.is_oblique()
+ || full.contains("oblique")
+ || full.contains("slanted");
+
+ match (italic, oblique) {
+ (false, false) => FontStyle::Normal,
+ (true, _) => FontStyle::Italic,
+ (_, true) => FontStyle::Oblique,
}
+ });
+
+ let weight = exception.and_then(|c| c.weight).unwrap_or_else(|| {
+ let number = ttf.weight().to_number();
FontWeight::from_number(number)
- };
+ });
+
+ let stretch = exception
+ .and_then(|c| c.stretch)
+ .unwrap_or_else(|| FontStretch::from_number(ttf.width().to_number()));
- let stretch = FontStretch::from_number(ttf.width().to_number());
FontVariant { style, weight, stretch }
};
@@ -355,12 +356,6 @@ fn typographic_family(mut family: &str) -> &str {
"narrow", "condensed", "cond", "cn", "cd", "compressed", "expanded", "exp"
];
- let mut extra = [].as_slice();
- let newcm = family.starts_with("NewCM") || family.starts_with("NewComputerModern");
- if newcm {
- extra = &["book"];
- }
-
// Trim spacing and weird leading dots in Apple fonts.
family = family.trim().trim_start_matches('.');
@@ -376,7 +371,7 @@ fn typographic_family(mut family: &str) -> &str {
// Find style suffix.
let mut t = trimmed;
let mut shortened = false;
- while let Some(s) = SUFFIXES.iter().chain(extra).find_map(|s| t.strip_suffix(s)) {
+ while let Some(s) = SUFFIXES.iter().find_map(|s| t.strip_suffix(s)) {
shortened = true;
t = s;
}
@@ -403,20 +398,7 @@ fn typographic_family(mut family: &str) -> &str {
// Apply style suffix trimming.
family = &family[..len];
- if newcm {
- family = family.trim_end_matches("10");
- }
-
- // Fix bad names.
- match family {
- "Noto Sans Symbols2" => "Noto Sans Symbols 2",
- "NewComputerModern" => "New Computer Modern",
- "NewComputerModernMono" => "New Computer Modern Mono",
- "NewComputerModernSans" => "New Computer Modern Sans",
- "NewComputerModernMath" => "New Computer Modern Math",
- "NewCMUncial" | "NewComputerModernUncial" => "New Computer Modern Uncial",
- other => other,
- }
+ family
}
/// How many words the two strings share in their prefix.
diff --git a/crates/typst/src/text/font/exceptions.rs b/crates/typst/src/text/font/exceptions.rs
new file mode 100644
index 00000000..363c6bfe
--- /dev/null
+++ b/crates/typst/src/text/font/exceptions.rs
@@ -0,0 +1,130 @@
+use serde::Deserialize;
+
+use super::{FontStretch, FontStyle, FontWeight};
+
+#[derive(Debug, Default, Deserialize)]
+pub struct Exception {
+ pub family: Option<&'static str>,
+ pub style: Option<FontStyle>,
+ pub weight: Option<FontWeight>,
+ pub stretch: Option<FontStretch>,
+}
+
+impl Exception {
+ pub const fn new() -> Self {
+ Self {
+ family: None,
+ style: None,
+ weight: None,
+ stretch: None,
+ }
+ }
+
+ const fn family(self, family: &'static str) -> Self {
+ Self { family: Some(family), ..self }
+ }
+
+ const fn style(self, style: FontStyle) -> Self {
+ Self { style: Some(style), ..self }
+ }
+
+ const fn weight(self, weight: u16) -> Self {
+ Self { weight: Some(FontWeight(weight)), ..self }
+ }
+
+ #[allow(unused)] // left for future use
+ const fn stretch(self, stretch: u16) -> Self {
+ Self { stretch: Some(FontStretch(stretch)), ..self }
+ }
+}
+
+pub fn find_exception(postscript_name: &str) -> Option<&'static Exception> {
+ EXCEPTION_MAP.get(postscript_name)
+}
+
+/// A map which keys are PostScript name and values are override entries.
+static EXCEPTION_MAP: phf::Map<&'static str, Exception> = phf::phf_map! {
+ "NewCM08-Book" => Exception::new()
+ .family("New Computer Modern 08")
+ .weight(450),
+ "NewCM08-BookItalic" => Exception::new()
+ .family("New Computer Modern 08")
+ .weight(450),
+ "NewCM08-Italic" => Exception::new()
+ .family("New Computer Modern 08"),
+ "NewCM08-Regular" => Exception::new()
+ .family("New Computer Modern 08"),
+ "NewCM10-Bold" => Exception::new()
+ .family("New Computer Modern"),
+ "NewCM10-BoldItalic" => Exception::new()
+ .family("New Computer Modern"),
+ "NewCM10-Book" => Exception::new()
+ .family("New Computer Modern")
+ .weight(450),
+ "NewCM10-BookItalic" => Exception::new()
+ .family("New Computer Modern")
+ .weight(450),
+ "NewCM10-Italic" => Exception::new()
+ .family("New Computer Modern"),
+ "NewCM10-Regular" => Exception::new()
+ .family("New Computer Modern"),
+ "NewCMMath-Book" => Exception::new()
+ .family("New Computer Modern Math")
+ .weight(450),
+ "NewCMMath-Regular" => Exception::new()
+ .family("New Computer Modern Math"),
+ "NewCMMono10-Bold" => Exception::new()
+ .family("New Computer Modern Mono"),
+ "NewCMMono10-BoldOblique" => Exception::new()
+ .family("New Computer Modern Mono"),
+ "NewCMMono10-Book" => Exception::new()
+ .family("New Computer Modern Mono")
+ .weight(450),
+ "NewCMMono10-BookItalic" => Exception::new()
+ .family("New Computer Modern Mono")
+ .weight(450),
+ "NewCMMono10-Italic" => Exception::new()
+ .family("New Computer Modern Mono"),
+ "NewCMMono10-Regular" => Exception::new()
+ .family("New Computer Modern Mono"),
+ "NewCMSans08-Book" => Exception::new()
+ .family("New Computer Modern Sans 08")
+ .weight(450),
+ "NewCMSans08-BookOblique" => Exception::new()
+ .family("New Computer Modern Sans 08")
+ .weight(450),
+ "NewCMSans08-Oblique" => Exception::new()
+ .family("New Computer Modern Sans 08"),
+ "NewCMSans08-Regular" => Exception::new()
+ .family("New Computer Modern Sans 08"),
+ "NewCMSans10-Bold" => Exception::new()
+ .family("New Computer Modern Sans"),
+ "NewCMSans10-BoldOblique" => Exception::new()
+ .family("New Computer Modern Sans"),
+ "NewCMSans10-Book" => Exception::new()
+ .family("New Computer Modern Sans")
+ .weight(450),
+ "NewCMSans10-BookOblique" => Exception::new()
+ .family("New Computer Modern Sans")
+ .weight(450)
+ .style(FontStyle::Oblique),
+ "NewCMSans10-Oblique" => Exception::new()
+ .family("New Computer Modern Sans")
+ .style(FontStyle::Oblique),
+ "NewCMSans10-Regular" => Exception::new()
+ .family("New Computer Modern Sans"),
+ "NewCMUncial08-Bold" => Exception::new()
+ .family("New Computer Modern Uncial 08"),
+ "NewCMUncial08-Book" => Exception::new()
+ .family("New Computer Modern Uncial 08")
+ .weight(450),
+ "NewCMUncial08-Regular" => Exception::new()
+ .family("New Computer Modern Uncial 08"),
+ "NewCMUncial10-Bold" => Exception::new()
+ .family("New Computer Modern Uncial"),
+ "NewCMUncial10-Book" => Exception::new()
+ .family("New Computer Modern Uncial")
+ .weight(450),
+ "NewCMUncial10-Regular" => Exception::new()
+ .family("New Computer Modern Uncial"),
+};
diff --git a/crates/typst/src/text/font/mod.rs b/crates/typst/src/text/font/mod.rs
index d9eb044b..42a87b7e 100644
--- a/crates/typst/src/text/font/mod.rs
+++ b/crates/typst/src/text/font/mod.rs
@@ -1,6 +1,7 @@
//! Font handling.
mod book;
+mod exceptions;
mod variant;
pub use self::book::{Coverage, FontBook, FontFlags, FontInfo};
diff --git a/crates/typst/src/text/font/variant.rs b/crates/typst/src/text/font/variant.rs
index f96f648d..e34d17b6 100644
--- a/crates/typst/src/text/font/variant.rs
+++ b/crates/typst/src/text/font/variant.rs
@@ -77,7 +77,7 @@ impl From<usvg::FontStyle> for FontStyle {
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
-pub struct FontWeight(u16);
+pub struct FontWeight(pub(super) u16);
impl FontWeight {
/// Thin weight (100).
@@ -180,7 +180,7 @@ cast! {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
-pub struct FontStretch(u16);
+pub struct FontStretch(pub(super) u16);
impl FontStretch {
/// Ultra-condensed stretch (50%).