|
Arabic / Persian / Urdu Shaping Support Producer-side shaping pipeline (v2.85.0 - v2.119.68)
|
OpenType GSUB Engine CFF / OpenType Subsetting |
|
HotPDF 會在 producer-side 執行 shaping pipeline,在 PDF 文字輸出時將 Unicode 輸入的阿拉伯文、波斯文與烏爾都文 runs 摺疊為 Arabic Presentation Forms,因此閱讀端會收到可直接 render 的 positional / ligature glyphs,不需要自行具備 Harfbuzz-class shaper
What the pipeline does Positional shaping(v2.85.0):每個 Arabic base letter 最多有四種 positional forms:isolated(isol)、initial(init)、medial(medi)、final(fina)。HotPDF 會檢查每個阿拉伯字元的 join class 及其相鄰字元的 join classes,然後在輸出前將輸入 codepoint 對應到適當的 Arabic Presentation Forms-B(U+FE70 - U+FEFC)glyph。Non-joining letters、joiners、transparent characters(combining marks)與 Tatweel kashida 都會依 Unicode Arabic Shaping algorithm 處理
LAM-ALEF 必要連字(v2.119.32):阿拉伯 Unicode 成形規格要求任何 LAM(U+0644)後面緊接 ALEF(U+0627 一般形、U+0622 上方 madda、U+0623 上方 hamza、U+0625 下方 hamza)時,必須摺疊為單一連字字形(U+FEFB - U+FEFC 的獨立形與結尾形,並搭配適當變體)。這是阿拉伯文字排版中少數不可選的連字之一,也是正確性要求;若以分離字形呈現,母語讀者會立即看出文字格式錯誤。HotPDF 會在輸出期間執行此摺疊,因此呼叫端不需要在自己的成形流程中加入額外 shaping engine
Persian / Urdu core 9 letters(v2.119.35):波斯文與烏爾都文以不在 Arabic Presentation Forms-B block(U+FE70 - U+FEFC)中的字母擴充阿拉伯文。最常用的 9 個這類字母,包括 PEH(U+067E)、TCHEH(U+0686)、JEH(U+0698)、KEH(U+06A9 / U+06AF)、GAF(U+06AF)、NOON GHUNNA(U+06BA)、HEH DOACHASHMEE(U+06BE)、YEH BARREE(U+06D2)與 HEH GOAL(U+06C1),在 Arabic Presentation Forms-A(U+FB50 - U+FDFF)中有 presentation forms。HotPDF 現在會在 positional shaping 期間將這些字母對應到適當 Forms-A glyph,因此波斯文與烏爾都文在任何閱讀端都能以正確的 init / medi / fina / isol forms render
Arabic Extended-A + Supplement(v2.119.52、v2.119.56):joining-class table 現在涵蓋其餘 Arabic Extended-A characters(ALEF WASLA / NOON GHUNNA / HEH variants)、Arabic Supplement U+0750-U+077F,以及較高的 Arabic Extended-A U+08A0-U+08FF 範圍。具有 static Presentation Forms-A encoding 的字元會透過既有 4-position shaper 對應;沒有對應的字元(多數 Extended-A)只取得 joining-class classification,因此即使該字元本身原樣傳遞,相鄰字元仍可正確 shaping。v2.119.56 修正了 v2.119.52 引入的兩個錯誤 Forms-A mappings(U+06C2 / U+06C3)
Persian / Urdu Form-B full coverage(v2.119.57):joining-class table 擴充到完整 U+0672-U+06D5 範圍(約 80 個字元,涵蓋 REH / DAL / SEEN / SAD / TAH / AIN / FEH / QAF / KAF / GAF / LAM / NOON / HEH / WAW / YEH variants),並新增 26 個 Presentation Forms-A mappings(15 個 D-class 4-form + 11 個 R-class 2-form)。特別是烏爾都文標準 'h' HEH DOACHASHMEE(U+06BE → FBAA-FBAD)與詞尾 yeh YEH BARREE(U+06D2 → FBAE-FBAF),現在已正確對應到 Forms-A slots;這些 slots 曾被 v2.119.52 的 ALEF WASLA / NOON GHUNNA 暫時修正誤用。Static Forms-A coverage 現在涵蓋 40+ 個 source characters
YEH-HAMZA + vowel ligature post-pass(v2.119.58):positional shaping 後加入 _ApplyArabicShaping 的 post-pass,涵蓋 Forms-A block U+FBEA-U+FBFB 中的 8 組 ligature pairs:YEH-HAMZA + ALEF / AE / WAW / U / OE / YU / E / ALEF MAKSURA。每組會輸出 isolated form(FBEA / FBEC / FBEE / FBF0 / FBF2 / FBF4 / FBF6 / FBF9)加上 base+1 final form。starting / medial form slots FBF8 / FBFB 透過 sfArabicGSUB opt-in 留給 GSUB engine。建立於與 v2.119.32 LAM-ALEF 相同的 skeleton
Allah ligature (v2.119.60): the four-character sequence ALEF + LAM + LAM + HEH folds into U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM. Implemented as a codepoint-level static post-pass after v2.119.32 LAM-ALEF and v2.119.58 YEH-HAMZA in the
Bismillah phrase ligature (v2.119.62): the standard 22-codepoint Bismillah phrase "بسم الله الرحمن الرحيم" folds into a single glyph U+FDFD ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM. Runs as the very first pre-pass in
Public Query Helpers
How callers invoke it 先用
Font requirements The font registered via
Allah ligature(v2.119.60):四字元序列 ALEF + LAM + LAM + HEH 會摺疊為 U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM。實作為 _ApplyArabicShaping chain 中 v2.119.32 LAM-ALEF 與 v2.119.58 YEH-HAMZA 之後的 codepoint-level static post-pass
Bismillah phrase ligature(v2.119.62):標準 22-codepoint Bismillah phrase「بسم الله الرحمن الرحيم」會摺疊為單一 glyph U+FDFD ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM。它作為 _ApplyArabicShaping 中最先執行的 pre-pass(早於 LAM-ALEF),因此已摺疊的 Bismillah glyph 會以一個 codepoint 進入後續 pipeline,不會再被 downstream substitutions 改動
Public Query Helpers GetArabicJoiningClass 會回傳 static Arabic shaper 使用的 Unicode joining class。GetArabicPosition 會將 run 中的一個字元解析為 isolated、initial、medial 或 final 位置,讓呼叫端可在輸出文字前檢查或鏡像相同的 shaping decisions
Typical workflow
PDF.RegisterUnicodeTTF('NotoArab', 'NotoSansArabic-Regular.ttf'); PDF.AutoShapeArabic:= True; PDF.BeginDoc; PDF.CurrentPage.SetFont('NotoArab', [], 14); PDF.CurrentPage.RtLTextOut(100, 700, 0, UnicodeString(#$0645#$0631#$062D#$0628#$0627)); // "marhaba" (hello) PDF.EndDoc;
Automatic Phase 8 pipeline integration (v2.119.59 - v2.119.68) v2.119.59 introduced the opt-in
設定 sfArabicGSUB 時,static Unicode Presentation Forms shaper 會被略過,改用字型自己的 GSUB rules。當這些 glyphs 無法從 font cmap 取得時,HotPDF 會透過 synthetic codepoints 輸出 native contextual glyph IDs、保持 embedded subset 封閉,並為 copy and paste 寫入 ToUnicode reverse mappings。若呼叫端希望 static shaper 繼續處理字型 GSUB declarations 未涵蓋的 codepoints,應保持 sfArabicGSUB 關閉並依賴 static post-pass chain
ToUnicode CMap ligature reverse mapping (v2.119.61, v2.119.62, v2.119.65) The Adobe-Identity-UCS ToUnicode CMap emitted by
PUA synthetic codepoint emit (v2.119.68) AssignSyntheticCodepointForGID(GID; out CP): Boolean + GetSyntheticCodepointForGID(GID): Word 讓 producer code 可輸出沒有自然 Unicode codepoint 可透過 font cmap 抵達的 GSUB substitute GIDs。allocator 會在 Private Use Area(U+E000 - U+F8FF,6400 個 slots)分配 codepoints,並將設定鏡射到 FUnicodeCpToGid(讓閱讀端的 /CIDToGIDMap 可把 synthetic CP 解析回 target GID)、FAcroFormUnicodeAdvances(讓 v2.65 word-wrap 找到正確 em-fraction),以及 per-GID reverse-lookup table(讓重複設定請求具備冪等性)。這適用於 GSUB 引入但 cmap 無法抵達的 Devanagari cluster shapes、stylistic alternates 與 CJK ideographic variation sequences
Relationship to the OpenType GSUB engine 上述 static post-pass shaper(v2.85.0 + v2.119.32 / 58 / 60 / 62)預設獨立於 OpenType GSUB engine。透過 ShapingFeatures 啟用 sfArabicGSUB 時,GSUB engine 會成為 producer-side emission path 的一部分:HotPDF 會查詢 cmap 以建立 base GID array,對該 glyph run 套用 native Arabic positional 與 contextual GSUB lookups,為沒有 Unicode Presentation Form 的 substitute glyph IDs 分配 synthetic codepoints,並呼叫 MarkUnicodeGlyphUsed 讓 substitute glyphs 保留在 embedded font subset 內
對於沒有 Unicode codepoint 的 substitute glyphs,呼叫端可將 ShapingFeatures 與 v2.119.68 PUA synthetic-codepoint allocator 搭配使用,讓 substitute GID 仍可透過標準 hex pipeline 抵達。對字型 GSUB declarations 未涵蓋的 codepoints,static post-pass chain 仍是預設 fallback
Scope and limitations BiDi algorithm 仍不屬於本頁範圍:呼叫端仍需要自行排列混合 LTR 與 RTL runs,或使用獨立的 BiDi library。GPOS、Indic/Tibetan/Mongolian、Hebrew、N'Ko、Adlam、Thai/Lao 與 Javanese 支援現在位於各自的 opt-in shaping flag 與 API 頁面,因此本頁只聚焦 static 與 GSUB-based Arabic shaping
請參閱: OpenType GSUB Substitution Engine, Automatic Shaping Pipeline (Phase 8), Syriac / Mongolian / Devanagari Shaping, THotPDF.AssignSyntheticCodepointForGID, THPDFPage.RtLTextOut, THPDFPage.UnicodeTextOut, CFF / OpenType Font Subsetting |