|
THotPDF.AssignSyntheticCodepointForGID / GetSyntheticCodepointForGID THotPDF PUA synthetic codepoint allocator (v2.119.68)
|
GSUB Engine Auto Shaping Pipeline Arabic Shaping |
|
Выделяет и запрашивает synthetic codepoints из Private Use Area (U+E000 - U+F8FF) для OpenType GSUB substitute GIDs, у которых нет естественного Unicode codepoint, достижимого через cmap шрифта. Закрывает producer-side GID-level emission gap, оставленный GSUB query и refinement APIs v2.119.43-66
Delphi syntax: function AssignSyntheticCodepointForGID(GID: Word; out SyntheticCP: Word): Boolean; function GetSyntheticCodepointForGID(GID: Word): Word;
Why the API exists Producer-side automatic shaping pipeline v2.119.32-67 (Arabic / Latin / Devanagari) требует, чтобы substitute GIDs, возвращенные GSUB engine, были достижимы через Unicode codepoint: существующий hex-encoded text pipeline выводит codepoints, а не GIDs, и consumer reader разрешает codepoint обратно в GID через embedded /CIDToGIDMap. Для substitute GIDs с естественным Unicode codepoint через cmap шрифта существующий pipeline работает нормально
Но font-specific substitutes, попадающие на font-internal GIDs — большинство Devanagari cluster shapes, stylistic alternates, которые designer шрифта поставляет только как numbered GIDs, CJK ideographic variation sequences (IVS), discretionary ligatures без Presentation Form — вообще не имеют codepoint в cmap шрифта. До v2.119.68 эти GIDs были недостижимы через producer-side hex pipeline; v2.119.68 закрывает пробел, позволяя callers выделять synthetic codepoint в Private Use Area для любого GID
AssignSyntheticCodepointForGID semantics Выделяет следующий доступный PUA codepoint (начиная с U+E000) для указанного GID и зеркалирует assignment во все caches, от которых зависит существующая цепочка producer-side hex pipeline + consumer-reader resolution
1. 2. 3.
При успехе возвращает True и устанавливает SyntheticCP в выделенный codepoint. Возвращает False (оставляя SyntheticCP равным 0) при защитных условиях: font не зарегистрирован, GID недействителен, PUA range исчерпан или cache не инициализирован на входе
GetSyntheticCodepointForGID semantics Чистый запрос любого существующего assignment. Возвращает synthetic codepoint, выделенный для GID, если AssignSyntheticCodepointForGID(GID, ...) уже вызывался; иначе возвращает 0, что не является допустимым PUA codepoint и служит sentinel «no assignment». Не выделяет. Безопасно до первого AssignSyntheticCodepointForGID
Allocator state lifecycle FUnicodeSyntheticCpForGID и cursor next-available-PUA (FUnicodeNextSyntheticCp) lazy-allocates при первом вызове AssignSyntheticCodepointForGID. Cursor начинается с 0 (uninitialised), при первом allocation переходит к $E000, затем движется через $E001, $E002, ..., $F8FF. Оба поля сбрасываются на empty / 0 при каждом RegisterUnicodeTTF('', nil) вместе с остальным per-font subset state
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
PDF.AssignSyntheticCodepointForGID(150, CP1); // CP1 = $E000 PDF.AssignSyntheticCodepointForGID(151, CP2); // CP2 = $E001 PDF.AssignSyntheticCodepointForGID(150, CP3); // CP3 = $E000 (idempotent) CP4 := PDF.GetSyntheticCodepointForGID(150); // CP4 = $E000 CP5 := PDF.GetSyntheticCodepointForGID(999); // CP5 = 0 (no assignment)
Consumer-reader behaviour Consumer reader видит PUA codepoint в text-showing operator и разрешает его через document-embedded /CIDToGIDMap в target GID, затем рендерит этот GID встроенной font program. С точки зрения reader нет различия между natural Unicode codepoint, который cmap ведет к GID, и PUA synthetic codepoint, который /CIDToGIDMap ведет к GID
Поведение copy / paste: PUA codepoints round-trip как сами себя, когда ToUnicode CMap объявляет их identity mappings. Callers, которым нужен round-trip в исходные Unicode characters, могут зарегистрировать reverse mapping через RegisterToUnicodeReverseMapping или создать ActualText marked-content sequence properties через BeginTaggedContent и вывести synthetic codepoints внутри bracketed content
Phase 8 roadmap closure v2.119.68 / Phase 8c.6 закрывает roadmap Phase 8 GSUB engine: LookupType 1-8 query API, Script / LangSys selection API, TTF subsetter closure entry point, static post-pass ligature folding, opt-in automatic pipeline, Arabic rlig + Latin liga / clig + rclt automatic emission, ToUnicode reverse-mapping, advance query, Devanagari Indic reorder pre-pass и теперь PUA synthetic codepoint GID-level emit интегрированы в одну producer-side shaping surface
См. также: OpenType GSUB Substitution Engine, Automatic Shaping Pipeline (Phase 8), Arabic / Persian / Urdu Shaping Support, Syriac / Mongolian / Devanagari Shaping, THotPDF.BeginTaggedContent |