mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-29 04:28:20 -06:00
Restore the Telugu system-font fallback the i18n rebase dropped
The rebase onto main resolved the theme.rs and system_fonts.rs conflicts in favour of the new Hangul code and deleted upstream's Telugu fallback (SYSTEM_TELUGU_FALLBACK, telugu_fallback, telugu_candidates, script_fallback and their tests), while tests/fonts.rs kept the Telugu tests, so the build failed. Keep both: Telugu restored as it is on main, Hangul added alongside it through the same script_fallback helper.
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
//! The embedded faces (Inter, egui's defaults, craft-fonts) come first in every family; this one
|
||||
//! only draws characters none of them has, such as an Arabic file name in a build without
|
||||
//! craft-fonts, or the Simplified Chinese interface in a build without a `Hans` face (#826). A
|
||||
//! second installed face, [`devanagari_fallback`], draws Hindi when one is installed. It is
|
||||
//! second, a third and a fourth installed face, [`devanagari_fallback`], [`telugu_fallback`] and
|
||||
//! [`hangul_fallback`], draw Hindi, Telugu and Korean when one is installed. It is
|
||||
//! read at runtime and never embedded or shipped (AGENTS.md §1.4), and `PDFCRAFT_SYSTEM_FONTS=0`
|
||||
//! turns it off (published screenshots do).
|
||||
|
||||
@@ -22,6 +23,8 @@ const MAX_FACES: u32 = 16;
|
||||
const PROBE: char = '\u{0627}';
|
||||
/// Devanagari letter ka: the face must have it to cover Hindi.
|
||||
const DEVANAGARI_PROBE: char = '\u{0915}';
|
||||
/// Telugu letter ka: the face must have it to cover Telugu.
|
||||
const TELUGU_PROBE: char = '\u{0C15}';
|
||||
/// Hangul syllable han (한, U+D55C): the face must have it to cover Korean.
|
||||
const HANGUL_PROBE: char = '\u{D55C}';
|
||||
/// 欢 (U+6B22): Simplified only, absent from the Japanese craft-fonts faces.
|
||||
@@ -71,14 +74,14 @@ fn load(need: Need) -> Option<Arc<FontData>> {
|
||||
/// or no candidate is installed; the interface then draws what the embedded faces can.
|
||||
pub fn devanagari_fallback() -> Option<Arc<FontData>> {
|
||||
static CACHE: OnceLock<Option<Arc<FontData>>> = OnceLock::new();
|
||||
CACHE
|
||||
.get_or_init(|| {
|
||||
if std::env::var_os("PDFCRAFT_SYSTEM_FONTS").is_some_and(|v| v == "0") {
|
||||
return None;
|
||||
}
|
||||
devanagari_candidates().iter().find_map(|path| read(path, DEVANAGARI_PROBE, MAX_BYTES))
|
||||
})
|
||||
.clone()
|
||||
CACHE.get_or_init(|| script_fallback(&devanagari_candidates(), DEVANAGARI_PROBE, MAX_BYTES)).clone()
|
||||
}
|
||||
|
||||
/// The installed fallback face for Telugu, read once. `None` when it is turned off or no
|
||||
/// candidate is installed; the interface then draws what the embedded faces can.
|
||||
pub fn telugu_fallback() -> Option<Arc<FontData>> {
|
||||
static CACHE: OnceLock<Option<Arc<FontData>>> = OnceLock::new();
|
||||
CACHE.get_or_init(|| script_fallback(&telugu_candidates(), TELUGU_PROBE, MAX_BYTES)).clone()
|
||||
}
|
||||
|
||||
/// The installed fallback face for Hangul (Korean), read once. `None` when it is turned off or no
|
||||
@@ -86,14 +89,14 @@ pub fn devanagari_fallback() -> Option<Arc<FontData>> {
|
||||
/// has Hangul, so Korean text shows replacement boxes).
|
||||
pub fn hangul_fallback() -> Option<Arc<FontData>> {
|
||||
static CACHE: OnceLock<Option<Arc<FontData>>> = OnceLock::new();
|
||||
CACHE
|
||||
.get_or_init(|| {
|
||||
if std::env::var_os("PDFCRAFT_SYSTEM_FONTS").is_some_and(|v| v == "0") {
|
||||
return None;
|
||||
}
|
||||
hangul_candidates().iter().find_map(|path| read(path, HANGUL_PROBE, MAX_HAN_BYTES))
|
||||
})
|
||||
.clone()
|
||||
CACHE.get_or_init(|| script_fallback(&hangul_candidates(), HANGUL_PROBE, MAX_HAN_BYTES)).clone()
|
||||
}
|
||||
|
||||
fn script_fallback(candidates: &[PathBuf], probe: char, max: u64) -> Option<Arc<FontData>> {
|
||||
if std::env::var_os("PDFCRAFT_SYSTEM_FONTS").is_some_and(|v| v == "0") {
|
||||
return None;
|
||||
}
|
||||
candidates.iter().find_map(|path| read(path, probe, max))
|
||||
}
|
||||
|
||||
/// Well-known locations of Korean system faces, best first. Noto CJK and Source Han are left out
|
||||
@@ -155,6 +158,37 @@ fn devanagari_candidates() -> Vec<PathBuf> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Well-known locations of Telugu faces, best first.
|
||||
fn telugu_candidates() -> Vec<PathBuf> {
|
||||
if cfg!(windows) {
|
||||
["Nirmala.ttc", "Nirmala.ttf", "gautami.ttf"].iter().map(|f| windows_fonts().join(f)).collect()
|
||||
} else if cfg!(target_os = "macos") {
|
||||
[
|
||||
"/System/Library/Fonts/KohinoorTelugu.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Telugu Sangam MN.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Telugu MN.ttc",
|
||||
"/Library/Fonts/Arial Unicode.ttf",
|
||||
]
|
||||
.iter()
|
||||
.map(PathBuf::from)
|
||||
.collect()
|
||||
} else {
|
||||
unix_fonts(&[
|
||||
"google-noto/NotoSansTeluguUI-Regular.ttf",
|
||||
"google-noto/NotoSansTelugu-Regular.ttf",
|
||||
"google-noto-vf/NotoSansTelugu[wght].ttf",
|
||||
"google-noto-vf/NotoSansTelugu-UI[wght].ttf",
|
||||
"truetype/noto/NotoSansTelugu-Regular.ttf",
|
||||
"truetype/noto/NotoSansTeluguUI-Regular.ttf",
|
||||
"noto/NotoSansTelugu-Regular.ttf",
|
||||
"noto/NotoSansTeluguUI-Regular.ttf",
|
||||
"lohit-telugu-fonts/Lohit-Telugu.ttf",
|
||||
"truetype/lohit-telugu/Lohit-Telugu.ttf",
|
||||
"truetype/fonts-telu-extra/Pothana2000.ttf",
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/// Well-known locations of faces with broad script coverage, best first.
|
||||
fn candidates(need: Need) -> Vec<PathBuf> {
|
||||
match need {
|
||||
@@ -285,6 +319,24 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_script_fallback_is_the_first_candidate_with_the_probe() {
|
||||
let inter = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/../../assets/fonts/Inter-Regular.ttf"));
|
||||
let candidates = [PathBuf::from("definitely/not/here.ttf"), inter];
|
||||
assert!(script_fallback(&candidates, 'A', MAX_BYTES).is_some());
|
||||
assert!(script_fallback(&candidates, TELUGU_PROBE, MAX_BYTES).is_none());
|
||||
assert!(script_fallback(&candidates, DEVANAGARI_PROBE, MAX_BYTES).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn script_candidates_are_absolute_font_files() {
|
||||
for list in [devanagari_candidates(), telugu_candidates(), hangul_candidates()] {
|
||||
assert!(!list.is_empty());
|
||||
assert!(list.iter().all(|p| p.is_absolute() || cfg!(windows)), "{list:?}");
|
||||
assert!(list.iter().all(|p| p.extension().is_some_and(|e| e == "ttf" || e == "ttc")), "{list:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hangul_candidates_are_font_files_without_adobe_designs() {
|
||||
let list = hangul_candidates();
|
||||
|
||||
+13
-13
@@ -218,6 +218,8 @@ pub fn install_fonts_for(ctx: &egui::Context, cjk: CjkPreference) {
|
||||
pub const SYSTEM_FALLBACK: &str = "system-fallback";
|
||||
/// The name of the installed Devanagari (Hindi) face [`installed_font_definitions`] may add.
|
||||
pub const SYSTEM_DEVANAGARI_FALLBACK: &str = "system-devanagari-fallback";
|
||||
/// The name of the installed Telugu face [`installed_font_definitions`] may add.
|
||||
pub const SYSTEM_TELUGU_FALLBACK: &str = "system-telugu-fallback";
|
||||
/// The name of the installed Hangul (Korean) face [`installed_font_definitions`] may add.
|
||||
pub const SYSTEM_HANGUL_FALLBACK: &str = "system-hangul-fallback";
|
||||
|
||||
@@ -232,9 +234,9 @@ pub const SYSTEM_HANGUL_FALLBACK: &str = "system-hangul-fallback";
|
||||
/// - Otherwise it is the last fallback of every family (an Arabic file name in a build without
|
||||
/// craft-fonts).
|
||||
///
|
||||
/// An installed Devanagari face, when there is one, ends every family just before that one, so
|
||||
/// Hindi text draws in a build without a Devanagari face. An installed Hangul face does the same
|
||||
/// for Korean: no craft-fonts face has Hangul yet.
|
||||
/// An installed Devanagari face, an installed Telugu face and an installed Hangul face, when
|
||||
/// there are, end every family just before that one, so Hindi, Telugu and Korean text draw in a
|
||||
/// build without such faces (#1531); no craft-fonts face has Hangul yet.
|
||||
///
|
||||
/// `PDFCRAFT_SYSTEM_FONTS=0` leaves them out.
|
||||
pub fn installed_font_definitions(cjk: CjkPreference) -> FontDefinitions {
|
||||
@@ -244,17 +246,15 @@ pub fn installed_font_definitions(cjk: CjkPreference) -> FontDefinitions {
|
||||
{
|
||||
use crate::system_fonts::{Need, fallback};
|
||||
// Before the general installed face, which stays the last fallback outside Chinese.
|
||||
if let Some(data) = crate::system_fonts::devanagari_fallback() {
|
||||
fonts.font_data.insert(SYSTEM_DEVANAGARI_FALLBACK.to_owned(), data);
|
||||
for (name, data) in [
|
||||
(SYSTEM_DEVANAGARI_FALLBACK, crate::system_fonts::devanagari_fallback()),
|
||||
(SYSTEM_TELUGU_FALLBACK, crate::system_fonts::telugu_fallback()),
|
||||
(SYSTEM_HANGUL_FALLBACK, crate::system_fonts::hangul_fallback()),
|
||||
] {
|
||||
let Some(data) = data else { continue };
|
||||
fonts.font_data.insert(name.to_owned(), data);
|
||||
for stack in fonts.families.values_mut() {
|
||||
stack.push(SYSTEM_DEVANAGARI_FALLBACK.to_owned());
|
||||
}
|
||||
}
|
||||
// No embedded face has Hangul, so Korean text relies on an installed one.
|
||||
if let Some(data) = crate::system_fonts::hangul_fallback() {
|
||||
fonts.font_data.insert(SYSTEM_HANGUL_FALLBACK.to_owned(), data);
|
||||
for stack in fonts.families.values_mut() {
|
||||
stack.push(SYSTEM_HANGUL_FALLBACK.to_owned());
|
||||
stack.push(name.to_owned());
|
||||
}
|
||||
}
|
||||
let need = match cjk {
|
||||
|
||||
Reference in New Issue
Block a user