THotPDF.AssignSyntheticCodepointForGID / GetSyntheticCodepointForGID

THotPDF PUA synthetic codepoint allocator (v2.119.68)

 

GSUB Engine  Auto Shaping Pipeline  Arabic Shaping

Font의 cmap을 통해 도달할 수 있는 natural Unicode codepoint가 없는 OpenType GSUB substitute GID를 위해 Private Use Area(U+E000 - U+F8FF) synthetic codepoint를 allocate하고 query합니다. v2.119.43-66 GSUB query 및 refinement API가 남긴 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 GID가 Unicode codepoint를 통해 도달 가능해야 합니다. 기존 hex-encoded text pipeline은 GID가 아니라 codepoint를 emit하고, consumer reader는 embedded /CIDToGIDMap을 통해 codepoint를 다시 GID로 resolve합니다. Font의 cmap을 통해 natural Unicode codepoint가 있는 substitute GID(Arabic Presentation Forms, Latin Standard Ligatures FB00-FB06)는 기존 pipeline이 잘 동작합니다

 

하지만 font-internal GID에 위치하는 font-specific substitute, 즉 대부분의 Devanagari cluster shape, font designer가 numbered GID로만 제공하는 stylistic alternate, CJK ideographic variation sequence(IVS), 대응하는 Presentation Form이 없는 discretionary ligature는 font cmap에 codepoint가 전혀 없습니다. v2.119.68 이전에는 이러한 GID에 producer-side hex pipeline으로 도달할 수 없었습니다. v2.119.68은 호출자가 모든 GID에 대해 Private Use Area의 synthetic codepoint를 allocate할 수 있게 하여 이 gap을 닫습니다

 

AssignSyntheticCodepointForGID semantics

제공된 GID에 대해 다음 사용 가능한 PUA codepoint(U+E000부터 시작)를 allocate하고, 기존 producer-side hex pipeline + consumer-reader resolution chain이 의존하는 모든 cache에 해당 assignment를 mirror합니다

 

1. FUnicodeCpToGid[SyntheticCP] := GID - so the producer-side hex pipeline emits SyntheticCP into the text-showing operator and the consumer reader resolves SyntheticCP back to GID through /CIDToGIDMap at render time.

2. FAcroFormUnicodeAdvances[SyntheticCP] := em-fraction - so the v2.65 word-wrap calculator finds the correct hmtx advance for the synthetic codepoint when it appears in AcroForm text-field content.

3. FUnicodeSyntheticCpForGID[GID] := SyntheticCP - the per-GID reverse-lookup table used by GetSyntheticCodepointForGID to make repeat AssignSyntheticCodepointForGID calls idempotent (the second call with the same GID returns the already-allocated SyntheticCP).

 

성공하면 SyntheticCP가 allocate된 codepoint로 설정된 상태에서 True를 반환합니다. 다음 defensive condition 중 하나에서는 False를 반환하고 SyntheticCP를 0으로 둡니다. Font가 등록되지 않음(RegisterUnicodeTTF가 호출되지 않았거나 state reset을 위해 빈 argument로 호출됨), invalid GID(0이거나 cmap glyph count를 벗어남), PUA range exhausted(U+E000 - U+F8FF의 6400 slot 모두 allocate됨), entry 시 cache가 uninitialised 상태

 

GetSyntheticCodepointForGID semantics

기존 assignment에 대한 pure-functional query입니다. 이전에 AssignSyntheticCodepointForGID(GID, ...)가 호출되었다면 GID에 allocate된 synthetic codepoint를 반환하고, 그렇지 않으면 0을 반환합니다(0은 valid PUA codepoint가 아니므로 "no assignment" sentinel로도 쓰입니다). Allocate하지 않습니다. 어떤 AssignSyntheticCodepointForGID도 실행되기 전에 호출해도 안전합니다

 

Allocator state lifecycle

FUnicodeSyntheticCpForGID와 next-available-PUA cursor(FUnicodeNextSyntheticCp)는 첫 AssignSyntheticCodepointForGID 호출에서 lazy-allocated됩니다. Cursor는 0(uninitialised)에서 시작해 첫 allocation 때 $E000으로 올라가며, 이후 allocation은 $E001, $E002, ..., $F8FF로 진행됩니다. 두 field는 매 RegisterUnicodeTTF('', nil)에서 나머지 per-font subset state와 함께 empty / 0으로 reset되므로, 여러 문서에 같은 THotPDF instance를 재사용하는 호출자도 각 문서를 fresh 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

 

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 behavior

Consumer reader는 text-showing operator 안의 PUA codepoint를 보고 document-embedded /CIDToGIDMap을 통해 target GID로 resolve한 뒤 embedded font program으로 해당 GID를 렌더링합니다. Reader 관점에서는 cmap이 GID로 route하는 "natural" Unicode codepoint와 /CIDToGIDMap이 GID로 route하는 PUA synthetic codepoint 사이에 차이가 없습니다. 둘 다 같은 rendered glyph를 생성합니다

 

Copy / paste behavior: ToUnicode CMap이 PUA codepoint를 identity mapping으로 선언하면 PUA codepoint는 copy / paste를 통해 자기 자신으로 round-trip됩니다. 대신 source Unicode character(substitute를 만든 input run)를 round-trip하려는 호출자는 RegisterToUnicodeReverseMapping으로 reverse mapping을 등록하거나, BeginTaggedContent를 통해 ActualText marked-content sequence property를 작성하고 bracketed content 안에 synthetic codepoint를 emit할 수 있습니다. HotPDF는 supplementary-plane Unicode character를 포함하는 RegisterUnicodeTTF-backed AcroForm appearance stream에 같은 internal-CID pattern을 자동으로 사용합니다

 

Phase 8 roadmap closure

v2.119.68 / Phase 8c.6은 Phase 8 GSUB engine roadmap을 닫습니다. 모든 LookupType 1-8 query API(Phase 1-6), Script / LangSys selection API(Phase 7), TTF subsetter closure entry point(Phase 9), static post-pass ligature folding(v2.119.32 / 58 / 60 / 62), opt-in automatic pipeline(v2.119.59), Arabic rlig + Latin liga / clig + rclt automatic emission(Phase 8b / 8c.2 / 8b / GSUB 'rclt'), ToUnicode reverse-mapping(v2.119.61 / 62 / 65), advance query(v2.119.64), Devanagari Indic reorder pre-pass(v2.119.67), 그리고 이제 PUA synthetic codepoint GID-level emit(v2.119.68)이 모두 OpenType font가 만들 수 있는 모든 종류의 substitute glyph를 처리하는 하나의 producer-side shaping surface로 통합됩니다

 

참조: OpenType GSUB Substitution Engine, Automatic Shaping Pipeline (Phase 8), Arabic / Persian / Urdu Shaping Support, Syriac / Mongolian / Devanagari Shaping, THotPDF.BeginTaggedContent