|
THotPDF.AssignSyntheticCodepointForGID / GetSyntheticCodepointForGID THotPDF PUA synthetic codepoint allocator (v2.119.68)
|
GSUB Engine Auto Shaping Pipeline Arabic Shaping |
|
為沒有自然 Unicode codepoint 可透過字型 cmap 抵達的 OpenType GSUB substitute GIDs,設定並查詢 Private Use Area(U+E000 - U+F8FF)synthetic codepoints。這補上 v2.119.43-66 GSUB query 與 refinement APIs 留下的 producer-side GID-level emission gap
Delphi 語法: function AssignSyntheticCodepointForGID(GID: Word; out SyntheticCP: Word): Boolean; function GetSyntheticCodepointForGID(GID: Word): Word;
Why the API exists v2.119.32-67 producer-side automatic shaping pipeline(Arabic / Latin / Devanagari)要求 GSUB engine 回傳的 substitute GIDs 可透過 Unicode codepoint 抵達;既有 hex-encoded text pipeline 輸出的是 codepoints 而非 GIDs,閱讀端會透過 embedded /CIDToGIDMap 將 codepoint 解析回 GID。對於可透過字型 cmap 取得自然 Unicode codepoint 的 substitute GIDs(Arabic Presentation Forms、Latin Standard Ligatures FB00-FB06),既有 pipeline 可正常運作
但落在 font-internal GIDs 上的 font-specific substitutes,例如多數 Devanagari cluster shapes、字型設計者只以 numbered GIDs 提供的 stylistic alternates、CJK ideographic variation sequences(IVS)、沒有對應 Presentation Form 的 discretionary ligatures,在字型 cmap 中完全沒有 codepoint。v2.119.68 之前,這些 GIDs 無法透過 producer-side hex pipeline 抵達;v2.119.68 允許呼叫端為任意 GID 在 Private Use Area 設定 synthetic codepoint,以補上此缺口
AssignSyntheticCodepointForGID semantics 為提供的 GID 設定下一個可用 PUA codepoint(從 U+E000 開始),並將設定鏡射到既有 producer-side hex pipeline + consumer-reader resolution chain 所依賴的每個 cache:
1. 2. 3.
Returns
GetSyntheticCodepointForGID semantics Pure-functional query of any existing assignment. Returns the synthetic codepoint allocated for
Allocator state lifecycle
成功時回傳 True,並將 SyntheticCP 設為設定的 codepoint。遇到下列任一防禦條件時回傳 False(且讓 SyntheticCP 保持 0):未註冊字型(從未呼叫 RegisterUnicodeTTF,或以空參數呼叫以重設狀態)、無效 GID(零或超出 cmap glyph count)、PUA range 耗盡(U+E000 - U+F8FF 的 6400 個 slots 全部已設定)、進入時 cache 尚未初始化
GetSyntheticCodepointForGID semantics 對任何既有 assignment 的 pure-functional query。若先前已呼叫 AssignSyntheticCodepointForGID(GID, ...),則回傳為 GID 設定的 synthetic codepoint;否則回傳 0(不是有效 PUA codepoint,因此也作為「no assignment」sentinel)。不會設定。可在任何 AssignSyntheticCodepointForGID 執行前安全呼叫
Allocator state lifecycle FUnicodeSyntheticCpForGID 與 next-available-PUA cursor(FUnicodeNextSyntheticCp)會在首次 AssignSyntheticCodepointForGID 呼叫時 lazy-allocate。cursor 起始為 0(uninitialised),第一次設定時跳到 $E000;後續設定會依序移動到 $E001、$E002、...、$F8FF。每次 RegisterUnicodeTTF('', nil) 都會將這兩個 fields 與其餘 per-font subset state 一起重設為 empty / 0,因此跨多份檔案重用 THotPDF instance 的呼叫端,每份檔案都會從新的 PUA cursor 開始
Typical workflow (Devanagari cluster shape)
PDF.RegisterUnicodeTTF('NotoDeva', 'NotoSansDevanagari-Regular.ttf'); PDF.ShapingFeatures := [sfIndicShaping]; PDF.SetGSUBScript('deva');
// Get a font-internal cluster GID through the GSUB engine ClusterGID := PDF.GetSingleSubstituteGlyph(BaseGID, 'nukt'); if ClusterGID <> BaseGID then begin // Check if cmap reaches the substitute - usually no for Indic // clusters, since cluster GIDs are font-internal // Allocate a synthetic codepoint that the producer-side // hex pipeline can emit if PDF.AssignSyntheticCodepointForGID(ClusterGID, SyntheticCP) then begin // SyntheticCP is now in the U+E000-F8FF range; emit it // through UnicodeTextOut just like a normal codepoint PDF.CurrentPage.UnicodeTextOut(X, Y, 0, UnicodeChar(SyntheticCP)); PDF.MarkUnicodeGlyphUsed(ClusterGID); end; end;
Idempotency example
Copy / paste behavior: PUA codepoints round-trip as themselves through copy / paste when the ToUnicode CMap declares them as identity mappings. Callers that want the source Unicode characters (the input run that produced the substitute) to round-trip instead can register a reverse mapping with PDF.AssignSyntheticCodepointForGID(150, CP1); // CP1 = $E000 PDF.AssignSyntheticCodepointForGID(151, CP2); // CP2 = $E001 PDF.AssignSyntheticCodepointForGID(150, CP3); // CP3 = $E000 (idempotent)
請參閱: OpenType GSUB Substitution Engine, Automatic Shaping Pipeline (Phase 8), Arabic / Persian / Urdu Shaping Support, Syriac / Mongolian / Devanagari Shaping, THotPDF.BeginTaggedContent |