# Fonts [English](FONTS.md) ## 結構 ```text core/fonts/ 穩定框架邏輯 catalog/impe-fonts-catalog.tex modules/fonts/ 特殊字體支持模組 assets/fonts/ 本地字體庫(不由 Git 追蹤) ``` 公開的字體子系統入口為: ```text core/fonts/impe-fonts-system.tex ``` ## 分工 ### `core/fonts/` 這一層負責穩定機制: - defaults - 樣式 fallback 解析 - writing model - script / behavior 處理 - 宣告介面 - family registry 行為 目前的 core 檔案分工如下: - `impe-fonts-system.tex` 字體子系統的公開入口。它會載入 defaults 層、family registry,以及 `catalog/impe-fonts-catalog.tex`。 - `impe-fonts-defaults.tex` 載入內部各層邏輯,並定義 scope、script class、fallback mode、writing model、behavior、backend 等預設值。 - `impe-fonts-style.tex` 負責樣式 fallback 鏈的解析,例如 `bold`、`italic`、`bolditalic`、`sans*`、`mono*`。 - `impe-fonts-writing.tex` 定義並驗證 writing model 相關欄位:inline axis、inline direction、block progression。 - `impe-fonts-script.tex` 套用 core 預設值,並驗證 `scriptclass`、`preservespaces`、backend 等 script-class 相關狀態。 - `impe-fonts-behavior.tex` 定義 inline / block 行為路由,目前包括一般行為、RTL 行為與藏文斷行行為 hook。 - `impe-fonts-interface.tex` 主要的宣告引擎。它負責解析 family 註冊欄位、解析實際字體選項、定義 public commands,並且內建 `layout = vertical` route。 - `impe-fonts-registry.tex` 保存底層 declaration entry,之後再把它們轉成可使用的 local / global family。 - `impe-fonts-registry-modes.tex` 追蹤 family 的載入模式(`local` / `global`),並負責 on-demand family activation。 - `impe-fonts-externalized.tex` 提供穩定的 externalized render 管線,包括快取命名、外部子文件生成、shell-out 與 PDF 嵌回。它透過 `texlua` 呼叫可攜的 `impe-externalized-render.lua` helper,並從 `PATH` 解析指定的 TeX 引擎。 - `impe-fonts-helpers.tex` 提供字體框架共用的小型 helper primitive。 ### `catalog/impe-fonts-catalog.tex` 這是集中式字體註冊表。 它負責宣告: - family id - command 名稱 - 字體檔案路徑 - script / language / feature 中介資料 - 真正的 local / global 模式 - 可選的內建 layout route 與特殊模組 hook ### `modules/fonts/` 這一層現在只保留那些不屬於穩定 generic core、而且帶有 script-specific 實作的特殊字體支持模組。 目前模組包括: - `impe-font-pahlavi.tex` Pahlavi 專用的 shaping routing - `impe-font-khitan_small.tex` 契丹小字的線性輸出與明確堆疊命令 - `impe-font-mlmodern.tex` `mlmodern` family 的 NFSS/package 整合 補充說明: - `layout = vertical` 現在已經內建在 `core/fonts/impe-fonts-interface.tex` - 一般 OpenType shaping 由 `script`、`language`、`features` 這些註冊欄位統一表達 - 對於只需要標準 fontspec shaping 的新 family,正常情況下應該只改註冊,不需要再往 `modules/fonts/` 新增檔案 ## 宣告模型 字體層支援: - 全域綁定 - 區域 command family - 以 `\FontRegisterFamily` 為中心的集中註冊 ### 普通區域 Family 這是一般使用者新增 family 時的目標格式。普通區域 family 使用 `assets/fonts/` 下的一個目錄,不預留未來全域行為: ```tex \FontRegisterFamily{ id = test, defaultmode = local, local = { command = TEST, name = test_local, path = \CatalogFontRoot/test/, regular = test_font.ttf, bold = test_font_bold.ttf, italic = test_font_italic.ttf, bolditalic = test_font_bolditalic.ttf, sans = test_sans.ttf, sansbold = test_sans_bold.ttf, sansitalic = test_sans_italic.ttf, sansbolditalic = test_sans_bolditalic.ttf, script = Devanagari, language = Sanskrit, features = { RawFeature = { script=deva } }, fallbackmode = soft } } ``` 通常只需要 `command`、`name`、`path`、`regular`。其他樣式欄位可以省略,系統會依 core fallback 鏈處理。`sans*` 字體會在 local 命令中自動映射;`mono*` 保留給 global / system family 或明確的進階註冊。 普通區域 family 不應包含: - `globalkind` / `globalstatus` - 與主 `path` 相同的 style-specific path 欄位 - `maptextsf` / `maptexttt` - `scriptclass`,CJK 路由除外 - `inlinebehavior`、`blockbehavior` 或 `blockalign`,core 維護的 script-specific behavior 條目除外 - vertical / externalized 欄位 - `mono` / `monobold` ### 全域 Family 只有真正帶有 `global = {...}` 區塊的 family 才能透過明確的 `globalfonts` override 載入。大部分可作為全域字體的 family 是 Latin / CJK / system 類 family,例如 `cmu`、`noto`、`times`、`gentium`、`charis`、`libertinus`、`japanese`、`shanggu`、`sim`。`hindi`、`sanskrit`、`tibetan` 這類 complex-script global 會用 `unicodeblocks` 限定 Unicode 區段,因此只在對應文字區段切換字體,不會改掉 Latin、漢字或其他文字。`hindi` range global 使用 Devanagari 區段,但不啟用 Sanskrit 專用斷行規則。`sanskrit` range global 會為 Devanagari 基礎區段加入 akshara-aware 斷行,並保留 virama 後接 consonant 時不斷行。Tibetan range global 也會保留核心 tsheg 行為:只有 `U+0F0B` / `U+0F0C` 後面接藏文字母 / 符號時才允許斷行,且不允許在藏文標點前斷行。如果某個 family 沒有 `global` 區塊卻被要求以 global mode 載入,registry 會直接回報「no global mode」錯誤,而不是依賴預留狀態佔位。 `cmu` 與 `times` 是 system / bundled 例外:它們可以直接使用字體名稱,不一定需要 `path = \CatalogFontRoot//`。 ### CJK / 內部路由 `scriptclass = cjk` 是內部路由提示,用於選擇 xeCJK 路徑。包含 `japanese` 在內的 CJK global family 會透過 xeCJK 替換文件的 CJK main / sans / mono 通道,而不是使用 Unicode range intercharacter switching。一般非 CJK family 不需要 `scriptclass`;OpenType shaping 應透過 `script`、`language`、`features` 表達。 在自動範圍路由中,日文字體與朝鮮文字體只會分別接管其專屬文字(假名與諺文)以及 CJK 標點;共用漢字仍使用文件的 CJK 字體,讓中文字體保持優先。需要明確採用日文或朝鮮文漢字字形時,可分別使用局部命令 `\JP{...}`、`\KR{...}`。越南漢喃字體同樣只作局部選用,需要時使用 `\HN{...}`。 ### Shaping、Layout 與特殊模組 `script`、`language`、`features = { RawFeature = { script=... } }` 是標準 fontspec / OpenType shaping 選項,不是特殊模組。 `layout = vertical` 會選擇 core 內建的 vertical layout route,用於現有蒙古文、滿文、古回鶻文一類條目。它的參數包括: - `verticalstrategy` - `verticalrotation` - `verticalorigin` - `verticaltopcorrection` `specialmodule` 保留給 `modules/fonts/` 下的外部或自定義 TeX 支持模組,例如: - `pahlavi` - `khitan_small` - 本地擴展建立的自定義模組名 為了向後相容,core 仍會把舊的 `specialmodule = vertical` 宣告視為 `layout = vertical`,並發出 deprecation warning。新的 catalog 條目和生成條目不應再寫 `specialmodule = vertical`。 ## 註冊語法 字體 family 目前集中註冊在: ```text catalog/impe-fonts-catalog.tex ``` 現行模型以 `\FontRegisterFamily{...}` 宣告為中心。 普通區域條目例如: ```tex \FontRegisterFamily{ id = hebrew, defaultmode = local, local = { command = HE, name = hebrew_local, path = \CatalogFontRoot/hebrew/, regular = NotoSerifHebrew-Regular.ttf, bold = NotoSerifHebrew-Bold.ttf, script = Hebrew } } ``` 實際上: - `command` 定義區域命令名稱,寫法不帶前導反斜線 - `path` 指向字體所在目錄 - `regular` / `bold` / `italic` / `bolditalic` 指向具體字體檔 - `local = {...}` 會建立區域命令 family - `global = {...}` 會把 family 綁定進文件全域預設 - `unicodeblocks = {...}` 會讓 global 綁定透過 XeLaTeX Unicode block transitions 限定區段,而不是替換整個 main/sans/mono 字體棧 - `layout = vertical` 會選擇內建 vertical layout route - `verticalstrategy` / `verticalrotation` / `verticalorigin` / `verticaltopcorrection` 會配置 `layout = vertical` - `specialmodule` 只在需要外部或自定義 TeX module route 時才需要 - 標準 OpenType shaping 應使用 `script`、`language`、`features` 表達,而不是另外做泛用 shaping module ### 路由優先級與擴展性 明確的局部命令在其大括號作用域內具有最終優先級。IMPE 的 Unicode-range transition 會在該作用域內暫停,因此 `\HI{...}` 之類的命令不會再被另一個 全域 Devanagari owner 接管;離開作用域後會恢復自動路由。 range 路由只為實際已配置的 XeTeX interchar class 與段落邊界 class 建立 transition,並在文檔開始時補登其他套件較晚配置的 class。同一 family 擁有的相鄰 Unicode block 之間仍保留空 transition,使 shaping run 可以連續。 載入 `thai` family 時,IMPE 會選用 XeTeX 的 ICU `th_TH` 斷行 locale, 讓沒有空格的泰文長句取得字典式斷行位置,而不必手工插入斷點。 ## 最小示例 自動載入 family 的例子: ```tex \UseTemplateSet{ fonts = {cmu,shanggu,hebrew,arabic} } \HE{שלום} \AR{السلام} ``` 明確指定全域模式的例子: ```tex \UseFont{libertinus}[global] ``` 這代表: - 無 mode 的 `fonts = {...}` 會依每個 family 的註冊行為載入 - `cmu` 與 `shanggu` 會採用其註冊的 global 行為 - `hebrew` 與 `arabic` 會建立其註冊的 local 命令 - 只有刻意覆寫註冊行為時才使用明確的 `[global]` mode ## 已註冊 Families 目前 catalog 中已註冊的 family 如下。`fonts = {...}` 會依各 family 註冊的 自動行為載入;`globalfonts = {...}` 是明確的 global 綁定要求,family 沒有 global 定義時會直接報錯。 | Family id | Local 命令 | 預設模式 | 提供 global | 說明 | |---|---|---|---|---| | `cmu` | `-` | `global` | 是 | CMU 拉丁字族;不提供 bundled local 命令 | | `noto` | `NOT` | `local` | 是 | Noto 拉丁字族 | | `times` | `TIM` | `local` | 是 | Windows Times/Arial/Consolas 組合 | | `gentium` | `GEN` | `local` | 是 | Gentium Plus 拉丁字族 | | `charis` | `CHA` | `local` | 是 | Charis SIL 拉丁字族 | | `libertinus` | `LIB` | `local` | 是 | TeX Live Libertinus Serif/Sans/Mono 字族 | | `mlmodern` | `MLM` | `local` | 否 | MLModern 傳統 package 路線;數學由 `math` feature 跟隨 | | `anatolian` | `CA` | `local` | 否 | Carian | | `coptic` | `CO` | `local` | 否 | 科普特文 | | `bopomofo` | `ZY` | `local` | 否 | 注音 / Bopomofo | | `cuneiform` | `CU` | `local` | 否 | 楔形文字 | | `glagolitic` | `GL` | `local` | 否 | 格拉哥里字母 | | `italic` | `OI` | `local` | 否 | 古意大利字母 | | `hungarian` | `OH` | `local` | 否 | 古匈牙利字母 | | `runic` | `RU` | `local` | 否 | 如尼字母 | | `armenian` | `HY` | `local` | 否 | 亞美尼亞文 | | `hindi` | `HI` | `local` | 是 | 印地語;global 只套用於 Devanagari Unicode 區段,不啟用 Sanskrit 專用斷行規則 | | `sanskrit` | `SA` | `local` | 是 | 梵語;global 只套用於 Devanagari 與 Vedic Unicode 區段 | | `devanagari` | `DEV` | `local` | 否 | 通用天城體 family | | `tamil` | `TA` | `local` | 否 | 泰米爾文 | | `brahmi` | `BR` | `local` | 否 | 婆羅米文 | | `georgian` | `KA` | `local` | 否 | 格魯吉亞文 | | `tibetan` | `TI` | `local` | 是 | 藏文;global 只套用於 Tibetan Unicode 區段 | | `arabic` | `AR` | `local` | 否 | 阿拉伯文 | | `urdu` | `UR` | `local` | 否 | 烏爾都文 | | `aramaic` | `IA` | `local` | 否 | 帝國亞蘭文 | | `nabataean` | `NB` | `local` | 否 | 納巴泰文 | | `hebrew` | `HE` | `local` | 否 | 希伯來文 | | `syriac` | `SY` | `local` | 否 | 敘利亞文 | | `syriac_eastern` | `SYE` | `local` | 否 | 東敘利亞文 | | `kharosthi` | `KH` | `local` | 否 | 佉盧文 | | `khitan_small` | `KHS` | `local` | 否 | 契丹小字 | | `pahlavi_parthian` | `PAR` | `local` | 否 | 碑銘帕提亞文 | | `pahlavi_inscriptional` | `PAH` | `local` | 否 | 碑銘巴列維文 | | `pahlavi_psalter` | `PSP` | `local` | 否 | 詩篇巴列維文 | | `avestan` | `AV` | `local` | 否 | 阿維斯陀文 | | `manichaean` | `MA` | `local` | 否 | 摩尼文字 | | `phoenician` | `PH` | `local` | 否 | 腓尼基文 | | `samaritan` | `SM` | `local` | 否 | 撒馬利亞文 | | `sogdian` | `SG` | `local` | 否 | 粟特文 | | `sogdian_old` | `SGO` | `local` | 否 | 古粟特文 | | `chinese_simplified` | `SC` | `local` | 否 | 簡體中文 | | `chinese_traditional` | `TC` | `local` | 否 | 繁體中文 | | `japanese` | `JP` | `local` | 是 | 日文;global 使用 xeCJK 的 CJK 字體通道 | | `wenjin` | `WJ` | `local` | 是 | 文津宋體,P0 爲主字體,P2/P3 作 xeCJK fallback | | `shanggu` | `-` | `global` | 是 | 漢字全域 CJK family | | `sim` | `-` | `global` | 是 | Windows CJK 字族 | | `korean` | `KR` | `local` | 否 | 韓文 | | `tangut` | `TG` | `local` | 否 | 西夏文 | | `mongolian` | `MO` | `local` | 否 | 蒙古文 | | `mongolian_baiti` | `MOb` | `local` | 否 | Mongolian Baiti | | `manchu` | `MC` | `local` | 否 | 滿文 | | `segoe` | `SEG` | `local` | 否 | Segoe UI Historic | | `thai` | `TH` | `local` | 否 | 泰文 | | `turkic` | `OT` | `local` | 否 | 古突厥文 | | `uyghur` | `UY` | `local` | 否 | 古回鶻文 | | `vietnamese_quocngu` | `VI` | `local` | 否 | 越南語國語字 | | `vietnamese_hannom` | `HN` | `local` | 否 | 越南漢喃 | 目前阿拉伯字母相關 family 的分工為: - `arabic`:regular/bold 使用 Naskh,italic/bolditalic 使用 Ruqaa,`sans` / `sansbold` 使用 Noto Sans Arabic,`sansitalic` / `sansbolditalic` 使用 Noto Kufi Arabic;它不再宣告 local `mono*` 字體。 - `urdu`:Nastaliq 僅保留給烏爾都文 family 使用。 若 local 命令欄位為 `-`,表示該 family 在目前 catalog 中是純 global 用途。 ## 字體映射說明 這一節只列出那些不是單純 `regular` / `bold` / `italic` / `bolditalic` 對應的 family。若某個 family 只是一般四態字體檔映射,則不在此重複展開。 - `shanggu` 這是全域 Han/CJK family,不是 local 命令 family,主要負責中文向版面中的漢字主文字通道。 - `sim` 這是 Windows 側的全域 CJK fallback family,作用同樣是全域 Han/CJK 綁定,而不是 local 命令 family。 - `times` 不是單一字族,而是混合 Windows 字體: `regular` / `bold` / `italic` / `bolditalic` 來自 Times New Roman, `sans*` 來自 Arial, `mono*` 來自 Consolas。 - `arabic` `regular` / `bold` 使用 Naskh,`italic` / `bolditalic` 使用 Ruqaa,`sans` / `sansbold` 使用 Noto Sans Arabic,`sansitalic` / `sansbolditalic` 使用 Noto Kufi Arabic。它不再宣告 local `mono*` 字體。 - `urdu` Nastaliq 僅作為烏爾都文 family 的專用字體,不與 `arabic` 共用。 - `khitan_small` `\KHS{...}` 是 showcase 使用的線性 local-font 命令; `\KHSstack{...}` 與 `\KHSstackblock{...}` 會呼叫明確的 cluster composer。 輸入時以空格分隔 cluster;Type B 會在首字後插入 `U+16FE4 KHITAN SMALL SCRIPT FILLER`。 ## 字體庫模型 IMPE LaTeX System 現在把 Git 倉庫與實際字體庫分開: - Git 倉庫本身維持 source-only - `assets/fonts/` 被視為工作樹中的本地字體庫 - 本地編譯與本地生成的 `full` release 可以把這套字體庫帶進去 - 公開 `git push` 則不需要攜帶字體檔本體 這樣可以同時保留: - 輕量的公開倉庫 - 完整的本地工作環境 - 在需要時由本地生成完整 `full` 安裝包 ## 本地字體庫路徑 目前的工作模型是: - 公開 Git 倉庫維持 source-only - 本地字體庫放在工作樹中的 `assets/fonts/` - 本地開發與本地 `full` release 打包都從這個位置讀字體 也就是說,預設本地路徑是: ```text assets/fonts/ ``` 如果這個目錄不存在: - 一般倉庫開發仍可繼續 - `core` release 仍可正常生成 - `full` release 會直接報出明確錯誤,而不是靜默產生一個不完整套件 ## Bundled 與 Non-Bundled 字體 IMPE LaTeX System 使用的字體並不都以同一種方式提供。 其中尤其需要注意: - `cmu` 字體族並不存放於 `assets/fonts/` 中 - 它通常來自 TeX 發行版安裝,或使用者本地字體環境 - 官方頁面: https://cm-unicode.sourceforge.io/ 至於第三方字體的授權全文與再分發說明,請見: - `font_licenses/` ## Fallback 行為 IMPE LaTeX System 目前支援兩種字體 fallback 模式: - `strict` 找不到字體時視為錯誤。 - `soft` 找不到字體時發出 warning,並退回 LaTeX 預設字族。 目前預設值是 `soft`。 在 `soft` 模式下: - 區域字體命令會退回 `\rmfamily`、`\sffamily`、`\ttfamily` 等 LaTeX 預設字族 - 全域宣告若無法解析目標字體,則不覆寫目前 LaTeX 的預設字體 這樣既能保住編譯流程,也能在 log 中明確看到缺字體狀態。 ## 目前的 Layout 與特殊模組模型 現在 catalog 區分標準 shaping、core layout route 與外部 TeX module: - `script`、`language`、`features` 是標準 fontspec shaping 欄位 - `layout = vertical` 會選擇 `core/fonts/impe-fonts-interface.tex` 內建的 vertical layout route - `verticalstrategy`、`verticalrotation`、`verticalorigin`、`verticaltopcorrection` 是 `layout = vertical` 的參數 - `specialmodule = pahlavi`、`specialmodule = khitan_small` 與 `specialmodule = mlmodern` 會從 `modules/fonts/` 載入 script-specific 或 package-specific 支援模組 - 自定義擴展模組也透過 `specialmodule = ` 表達 這代表: - 已經沒有額外的 dispatch table 檔案 - 一般 shaping 由 `script`、`language`、`features` 組裝成 fontspec 選項 - 內建 vertical 能力由 `core/fonts/impe-fonts-interface.tex` 處理,不再寫成 `specialmodule` - 只有真正 script-specific 或使用者提供的 TeX 邏輯才繼續留在 `modules/fonts/` - Pahlavi 的特殊處理只掛在實際需要的 family 上,例如 `pahlavi_psalter`;Parthian 與 Inscriptional Pahlavi 在 RawFeature 足夠時仍維持標準 fontspec 註冊 ## 蒙古文區域字體映射與分發說明 目前 `mongolian` 的區域字體族映射如下: - `regular = mnglwhiteotf.ttf` - `italic = mnglwritingotf.ttf` - `bold = mngltitleotf.ttf` - `bolditalic = mnglartotf.ttf` - `sans = NotoSansMongolian-Regular.ttf` 其中: - `MO` 是普通的線性蒙古文字體命令 - `MOv` 是建立在同一字體族之上的豎排變體 `manchu` 採用同樣的 vertical 模型: - `MC` 是普通線性命令 - `MCv` 是豎排變體 `uyghur` 也採用 vertical 路線: - `UY` 是橫排 RTL 命令 - `UYv` 是豎排、由左往右排列的變體 另外新增兩個本地專用字體註冊: - `mongolian_baiti` 對應 `\MOb` - `regular = monbaiti.ttf` - 微軟字體,只供本地使用 - `segoe` 對應 `\SEG` - `regular = seguihis.ttf` - 微軟字體,只供本地使用 重要的再分發說明: - 上述四款 `mngl*.ttf` 字體目前只保留作本地使用 - 由於其授權/可再分發狀態目前仍不夠明確,**不會**放進公開的 `full` release 套件 - 如需使用,請使用者自行由原始來源取得: http://www.mongolfont.com/cn/font/index.html - `assets/fonts/mongolian_baiti/monbaiti.ttf` 屬於微軟字體,**不會**放進公開的 `full` release 套件 - 參考頁面: https://learn.microsoft.com/zh-tw/typography/font-list/mongolian-baiti - `assets/fonts/segoe/seguihis.ttf` 屬於微軟字體,**不會**放進公開的 `full` release 套件 - 參考頁面: https://learn.microsoft.com/en-us/typography/font-list/segoe-ui-historic ## Syriac 區域字體映射 `syriac` family 使用: - `regular = SyrCOMEdessa.otf` - `bold = SyrCOMMidyat.otf` - `italic = SyrCOMJerusalem.otf` - `bolditalic = SyrCOMJerusalemBold.otf` - `sans = NotoSansSyriac-Regular.ttf` - `sansbold = NotoSansSyriac-Bold.ttf` - `sansitalic = NotoSansSyriacWestern-Regular.ttf` - `sansbolditalic = NotoSansSyriacWestern-Bold.ttf` `syriac_eastern` family 使用: - `regular = SyrCOMAdiabene.otf` - `bold = SyrCOMCtesiphon.otf` - `italic = SyrCOMJerusalem.otf` - `bolditalic = SyrCOMJerusalemBold.otf` - `sans = NotoSansSyriacEastern-Regular.ttf` - `sansbold = NotoSansSyriacEastern-Bold.ttf` - `sansitalic = NotoSansSyriacWestern-Regular.ttf` - `sansbolditalic = NotoSansSyriacWestern-Bold.ttf` 目前 `SyrCOM*.otf` 的授權全文已整理到 `font_licenses/` 目錄中。 ## 稽核範圍 標準公開字體稽核位於 `manual/showcase/impe-showcase.tex`;聚焦的自動檢查則位於 `tests/`。