Fix #683: Preferences > Type > Additional Fonts Folder

VectorCraft found fonts only in the system's font folders (and, on Windows,
those font services activate). A new preference names one more folder, read
with its subfolders after the platform's: its fonts are listed in the font
menus and used as if installed, without installing them.

- vectorcraft_text::set_user_font_dirs / user_font_dirs: folders
  system_font_dirs adds to every scan (none on wasm).
- prefs fontsFolder (Type > Options > Additional Fonts Folder), trimmed; when
  it changes after the first scan, the fonts are scanned again at once, so the
  folder's fonts appear (or go) and type in them lays out again.
- The label is translated where Additional Plug-ins Folder is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-09 12:04:22 +07:00
parent b61089e5c6
commit e92bbdbdac
14 changed files with 69 additions and 4 deletions

File diff suppressed because one or more lines are too long

View File

@ -247,7 +247,7 @@ fn font_list(_: &mut Session, p: &Value) -> Result<Value> {
}
}
fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
pub(crate) fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
let db = vectorcraft_text::FontDb::global();
#[cfg(not(target_arch = "wasm32"))]
let faces = db.load_system_fonts();
@ -283,6 +283,21 @@ fn rescan(s: &mut Session, _: &Value) -> Result<Value> {
mod tests {
use super::*;
/// Type › Options › Additional Fonts Folder (#683) adds its folder to the system font scan,
/// trimmed; clearing it takes the folder out again.
#[test]
fn the_additional_fonts_folder_joins_the_font_scan() {
let mut s = Session::new();
let dir = std::env::temp_dir().join("vectorcraft-fonts-folder-pref");
s.execute("prefs.set", &json!({"key": "fontsFolder", "value": format!(" {} ", dir.display())})).unwrap();
assert_eq!(vectorcraft_text::user_font_dirs(), std::slice::from_ref(&dir));
if !cfg!(target_arch = "wasm32") {
assert!(vectorcraft_text::system_font_dirs().contains(&dir));
}
s.execute("prefs.set", &json!({"key": "fontsFolder", "value": ""})).unwrap();
assert!(vectorcraft_text::user_font_dirs().is_empty() && !vectorcraft_text::system_font_dirs().contains(&dir));
}
#[test]
fn list_flag_missing_replace_and_select() {
let mut s = Session::new();

View File

@ -187,6 +187,7 @@ pub const PREF_SPECS: &[PrefSpec] = &[
p!("missingGlyphProtection", "Type", "Options", "Enable Missing Glyph Protection", bool),
p!("highlightAlternateGlyphs", "Type", "Options", "Highlight Alternate Glyphs", bool),
p!("placeholderText", "Type", "Options", "Fill New Type Objects With Placeholder Text", bool),
p!("fontsFolder", "Type", "Options", "Additional Fonts Folder", text),
// Units
p!("unitsGeneral", "Units", "", "General", choice(UNITS)),
p!("unitsStroke", "Units", "", "Stroke", choice(UNITS)),
@ -460,7 +461,18 @@ impl Session {
let grid_changed = p.gridline_every != self.prefs.gridline_every || p.grid_subdivisions != self.prefs.grid_subdivisions;
let history_changed = p.history_states != self.prefs.history_states;
let tile_edge_changed = p.pattern_tile_edge_color != self.prefs.pattern_tile_edge_color;
let fonts_folder_changed = p.fonts_folder != self.prefs.fonts_folder;
self.prefs = p;
if fonts_folder_changed {
let folder = self.prefs.fonts_folder.trim();
vectorcraft_text::set_user_font_dirs(if folder.is_empty() { vec![] } else { vec![folder.into()] });
// Once the fonts were scanned, scan again now: the folder's fonts appear (or go) in the
// font menus, and type in them lays out again. The first scan reads it anyway.
if vectorcraft_text::FontDb::global().installed_fonts_changed() {
// Its result only counts the faces cataloged.
let _ = super::fonts::rescan(self, &serde_json::Value::Null);
}
}
vectorcraft_render::set_default_threads(u16::try_from(self.prefs.render_threads).ok());
for st in &mut self.docs {
if history_changed {

View File

@ -480,6 +480,9 @@ pub struct Prefs {
// Hyphenation
pub hyphenation_language: String,
pub hyphenation_exceptions: String,
/// Type › Options › Additional Fonts Folder: a folder (read with its subfolders) whose fonts
/// are listed and used as if installed (#683); empty for none.
pub fonts_folder: String,
// Performance & Storage (Plug-ins & Scratch Disks)
pub plugins_folder: String,
pub scratch_primary: String,
@ -696,6 +699,7 @@ impl Default for Prefs {
slice_line_color: s("#ff3f3f"),
hyphenation_language: s("English: USA"),
hyphenation_exceptions: String::new(),
fonts_folder: String::new(),
plugins_folder: String::new(),
scratch_primary: s("Startup"),
scratch_secondary: s("None"),

View File

@ -878,6 +878,31 @@ pub fn set_platform_font_files(list: PlatformFontFiles) {
let _ = list;
}
/// Folders the user adds to the font scan (Preferences › Type › Additional Fonts Folder, #683),
/// read with their subfolders after the platform's.
#[cfg(not(target_arch = "wasm32"))]
static USER_FONT_DIRS: std::sync::RwLock<Vec<PathBuf>> = std::sync::RwLock::new(Vec::new());
/// Have [`system_font_dirs`] also read `dirs` (#683), so the fonts in them are listed and used as
/// if installed. The next check for installed fonts ([`FontDb::installed_fonts_changed`]) then
/// reports the change, and a scan catalogs them.
pub fn set_user_font_dirs(dirs: Vec<PathBuf>) {
#[cfg(not(target_arch = "wasm32"))]
{
*USER_FONT_DIRS.write().unwrap_or_else(std::sync::PoisonError::into_inner) = dirs;
}
#[cfg(target_arch = "wasm32")]
let _ = dirs;
}
/// The folders [`set_user_font_dirs`] added (none on wasm).
pub fn user_font_dirs() -> Vec<PathBuf> {
#[cfg(not(target_arch = "wasm32"))]
return USER_FONT_DIRS.read().unwrap_or_else(std::sync::PoisonError::into_inner).clone();
#[cfg(target_arch = "wasm32")]
Vec::new()
}
/// The platform's font folders (the system's and the user's) and the font files known to it
/// outside them (on Windows those registered with it, and those [`set_platform_font_files`]
/// lists), scanned by [`FontDb::global`].
@ -926,6 +951,7 @@ pub fn system_font_dirs() -> Vec<PathBuf> {
let files = fonts_outside(list(), &dirs);
dirs.extend(files);
}
dirs.extend(user_font_dirs());
dirs
}

View File

@ -25,8 +25,8 @@ pub mod thread;
pub use craft_fonts::{CRAFT_FONTS, CraftFont};
pub use features::{LIGATURE_TRACKING_LIMITS, OtFeatures, explicit_ligatures, ligatures_suppressed_by};
pub use fontdb::{
FALLBACK_FAMILY, FontClass, FontDb, FontFace, FontMatch, FontTraits, IcfMargins, PlatformFontFiles, set_platform_font_files, style_weight,
system_font_dirs,
FALLBACK_FAMILY, FontClass, FontDb, FontFace, FontMatch, FontTraits, IcfMargins, PlatformFontFiles, set_platform_font_files, set_user_font_dirs,
style_weight, system_font_dirs, user_font_dirs,
};
use kurbo::{Affine, BezPath, Point, Rect, Vec2};
pub use layout::{layout, layout_with};

View File

@ -76,6 +76,7 @@
Add to Swatches Agregar a muestras
Add Used Colors Agregar colores usados
Additional Plug-ins Folder Carpeta de plugins adicionales
Additional Fonts Folder Carpeta de fuentes adicionales
Adjust Adjoining Width Points Ajustar puntos de anchura contiguos
Adjust Color Balance… Ajustar equilibrio de color…
Adjust Colors Ajustar colores

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -77,6 +77,7 @@
Add to Swatches Ajouter au nuancier
Add Used Colors Ajouter les couleurs utilisées
Additional Plug-ins Folder Dossier de modules externes supplémentaires
Additional Fonts Folder Dossier de polices supplémentaires
Adjust Adjoining Width Points Ajuster les points de largeur adjacents
Adjust Color Balance… Régler la balance des couleurs…
Adjust Colors Régler les couleurs

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -76,6 +76,7 @@
Add to Swatches Aggiungi ai campioni
Add Used Colors Aggiungi colori usati
Additional Plug-ins Folder Cartella plug-in aggiuntivi
Additional Fonts Folder Cartella font aggiuntivi
Adjust Adjoining Width Points Regola punti di larghezza adiacenti
Adjust Color Balance… Regola bilanciamento colore…
Adjust Colors Regola colori

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -724,6 +724,7 @@
Add to Selection 選択範囲に追加
Add to Swatches スウォッチに追加
Additional Plug-ins Folder 追加プラグインフォルダー
Additional Fonts Folder 追加フォントフォルダー
Adjust Adjoining Width Points 隣接する幅ポイントを調整
Adjust Colors カラーを調整
Adjust Options: 調整オプション:

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -138,6 +138,7 @@
Add to Selection Adicionar à Seleção
Add to Swatches Adicionar às Amostras
Additional Plug-ins Folder Pasta Adicional de Plug-ins
Additional Fonts Folder Pasta Adicional de Fontes
Adjust Adjoining Width Points Ajustar Pontos de Largura Adjacentes
Adjust Color Balance… Ajustar Equilíbrio de Cores…
Adjust Colors Ajustar Cores

Can't render this file because it contains an unexpected character in line 6 and column 47.

View File

@ -74,6 +74,7 @@
Add to Swatches Добавить в образцы
Add Used Colors Добавить использованные цвета
Additional Plug-ins Folder Папка дополнительных модулей
Additional Fonts Folder Папка дополнительных шрифтов
Adjust Adjoining Width Points Настроить смежные точки ширины
Adjust Color Balance… Настроить цветовой баланс…
Adjust Colors Настроить цвета

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -79,6 +79,7 @@
Add to Swatches 添加到色板
Add Used Colors 添加已用颜色
Additional Plug-ins Folder 附加增效工具文件夹
Additional Fonts Folder 附加字体文件夹
Adjust Adjoining Width Points 调整相邻宽度点
Adjust Color Balance… 调整色彩平衡…
Adjust Colors 调整颜色

Can't render this file because it contains an unexpected character in line 2 and column 73.

View File

@ -87,6 +87,7 @@
Add to Swatches 新增至色票
Add Used Colors 新增使用中的顏色
Additional Plug-ins Folder 額外的增效模組資料夾
Additional Fonts Folder 額外的字體資料夾
Adjust Adjoining Width Points 調整相鄰寬度點
Adjust Color Balance… 調整色彩平衡…
Adjust Colors 調整顏色

Can't render this file because it contains an unexpected character in line 6 and column 47.