DONG GOI bo font Noto theo app: khong thoa hiep font he thong o bat ky tang nao
Build Windows portable / build (push) Canceled after 0s

User yeu cau: khach hang khong co font chuan san — phan mem phai tu chuan bi
font, khong duoc thay bang font "gan giong". Truoc do font nhung cua PDF da
dung cho o sua (build 35), nhung con 3 khe ho roi ve font he thong: font
khong nhung trong PDF, font CFF khong va duoc, va KY TU MOI GO VAO khong co
trong subset (subset chi chua glyph da dung).

- scripts/fetch-fonts.ps1: tai 10 file Noto hinted static (Sans/Serif/Mono,
  du Regular/Bold/Italic/BoldItalic, phu tieng Viet, ~6.7MB) + OFL license
  vao fonts/ (gitignore; CI cache theo hash script).
- CI: fetch fonts + dong fonts/ vao zip portable (canh exe).
- Tauri: main() dat FOFREEXIT_FONTS_PATH (fonts/ canh exe, dev thi goc
  workspace); command app_font_data(kind) tra base64 (whitelist 10 kind).
- UI: FontFace "ff-app-{sans|serif|mono}" dang ky theo weight/style, dung
  GIUA stack: font nhung cua PDF -> Noto dong goi -> stack he thong (luoi
  cuoi). Phan loai serif/sans/mono tu cssFontStack. Nap truoc cung font
  nhung khi vao trang sua.
- Engine find_font_bytes (duong ghi file/reflow can font coverage): uu tien
  tuyet doi fonts/ dong goi qua env — ket qua LUU ra giong nhau tren moi may
  (truoc: lay Arial/Segoe cua Windows, may khach thieu font la khac ket qua).

E2E ke tiep (build 36): go ky tu ngoai subset trong o sua -> 100% glyph phai
tu font custom (nhung/dong goi), 0 glyph he thong.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 12:12:26 +07:00
co-authored by Claude Fable 5
parent f6c1bc2070
commit f10cb7df2b
6 changed files with 174 additions and 6 deletions
+42
View File
@@ -703,6 +703,31 @@ fn edit_list_objects(path: String, page: u16, password: Option<String>) -> Resul
.collect())
}
/// Bytes (base64) của font ĐÓNG GÓI theo app (Noto) — lưới đỡ WYSIWYG cho ô
/// sửa: glyph không có trong subset nhúng (ký tự mới gõ) hay font không
/// nhúng đều rơi về font này, KHÔNG rơi về font hệ điều hành.
#[tauri::command]
fn app_font_data(kind: String) -> Result<String, String> {
let name = match kind.as_str() {
"sans-regular" => "NotoSans-Regular.ttf",
"sans-bold" => "NotoSans-Bold.ttf",
"sans-italic" => "NotoSans-Italic.ttf",
"sans-bolditalic" => "NotoSans-BoldItalic.ttf",
"mono-regular" => "NotoSansMono-Regular.ttf",
"mono-bold" => "NotoSansMono-Bold.ttf",
"serif-regular" => "NotoSerif-Regular.ttf",
"serif-bold" => "NotoSerif-Bold.ttf",
"serif-italic" => "NotoSerif-Italic.ttf",
"serif-bolditalic" => "NotoSerif-BoldItalic.ttf",
_ => return Err(format!("kind font không hợp lệ: {kind}")),
};
let dir = std::env::var("FOFREEXIT_FONTS_PATH")
.map_err(|_| "app không kèm bộ font (thiếu thư mục fonts/)".to_string())?;
let bytes = std::fs::read(std::path::Path::new(&dir).join(name))
.map_err(|e| format!("đọc font {name}: {e}"))?;
Ok(base64::engine::general_purpose::STANDARD.encode(&bytes))
}
/// Bytes font NHÚNG của 1 text run (base64) — UI đăng ký FontFace để ô sửa
/// hiển thị đúng font tài liệu thay vì font hệ thống gần giống.
#[tauri::command]
@@ -1408,6 +1433,22 @@ fn pick_image(app: tauri::AppHandle) -> Option<String> {
}
fn main() {
// Bộ font ĐÓNG GÓI theo app (Noto): fonts/ cạnh exe (bản portable) hoặc ở
// gốc workspace (dev). Engine (find_font_bytes) + command app_font_data
// đọc qua env — hiển thị/ghi file giống nhau trên mọi máy khách.
let exe_fonts = std::env::current_exe()
.ok()
.and_then(|p| p.parent().map(|d| d.join("fonts")));
let fonts_dir = match exe_fonts {
Some(d) if d.join("NotoSans-Regular.ttf").exists() => Some(d),
_ => {
let w = workspace_root().join("fonts");
if w.join("NotoSans-Regular.ttf").exists() { Some(w) } else { None }
}
};
if let Some(d) = fonts_dir {
std::env::set_var("FOFREEXIT_FONTS_PATH", &d);
}
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.invoke_handler(tauri::generate_handler![
@@ -1435,6 +1476,7 @@ fn main() {
preview_header_footer,
edit_list_objects,
edit_font_data,
app_font_data,
edit_apply,
edit_apply_to_temp,
edit_preview,