OpenType GSUB Substitution Engine

Glyph substitution capability surface (v2.119.43 - v2.119.50)

 

Arabic Shaping  CFF / OpenType Subsetting

OpenType GSUB (Glyph SUBstitution) engine unutar HotPDF-a omogućava pozivaocima da ispituju, upravljaju i ugrađuju svaku vrstu zamene glifa koju OpenType font deklarše - ligature, stilske alternative, kontekstualne varijante, Arabic / Indic oblike oblikovanja, CJK alternativne oblike i slično Svaki OpenType GSUB LookupType od 1 do 8 je implementiran i izložen kao capability-only query surface; pozivalac upravlja emitovanjem teksta i odlučuje koji zamenski glif da upiše u strim sadržaja stranice

 

Public API

type

  TGSUBStringArray = array of AnsiString;

 

// LookupType 1 - Single Substitution (one glyph -> one glyph)

function GetSingleSubstituteGlyph(InputGID: Word; const FeatureTag: AnsiString): Word;

 

// LookupType 2 - Multiple Substitution (one glyph -> sequence of glyphs)

function GetMultipleSubstituteGlyphs(InputGID: Word; const FeatureTag: AnsiString;

  var OutGIDs: array of Word): Boolean;

 

// LookupType 3 - Alternate Substitution (one glyph -> one of N alternates)

function GetAlternateGlyphCount(InputGID: Word; const FeatureTag: AnsiString): Integer;

function GetAlternateGlyph(InputGID: Word; const FeatureTag: AnsiString;

  AlternateIndex: Integer): Word;

 

// LookupType 4 - Ligature Substitution (N glyphs -> one ligature)

function ApplyLigatureSubstitution(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  out OutGID: Word; out ConsumedCount: Integer): Boolean;

 

// LookupType 5 + 6 - Contextual / Chained Contextual Substitution

function ApplyContextualSubst(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  var OutGIDs: array of Word;

  out ConsumedLen: Integer): Boolean;

 

// LookupType 8 - Reverse Chained Contextual Single Substitution

function ApplyReverseChainedContextualSubst(const InputGIDs: array of Word;

  StartIndex: Integer; const FeatureTag: AnsiString;

  out OutGID: Word): Boolean;

 

// Script / LangSys selection (Phase 7)

procedure SetGSUBScript(const ScriptTag: AnsiString);

procedure SetGSUBLanguage(const LangTag: AnsiString);

function GetGSUBScripts: TGSUBStringArray;

function GetGSUBLanguages(const ScriptTag: AnsiString): TGSUBStringArray;

function GetGSUBFeatures(const ScriptTag, LangTag: AnsiString): TGSUBStringArray;

 

// TTF subsetter closure (Phase 9)

procedure MarkUnicodeGlyphUsed(GID: Word);

 

Opis

Engine se aktivira nakon što RegisterUnicodeTTF parsira font i kešira njegove GSUB / GDEF / cmap tabele Svaki upit za zamenu prolazi kroz lanac ScriptList / LangSysList / FeatureList / LookupList fonta i prosleđuje ga odgovarajućem LookupType handleru Gornjih 12 metoda predstavlja kompletnu javnu površinu; sve ostalo (cmap prolaz, ScriptList parsiranje, Coverage lookup, ClassDef razrešenje, poštovanje LookupFlag, odmotavanje Extension omotača, ugnježdeno prosleđivanje SequenceLookupRecord) živi iza te površine

 

Defensive contract throughout: fontovi bez GSUB tabele, feature tagovi koji nisu 4 bajta, features koje izabrana skripta / jezik ne oglašava, GID-ovi koje nijedan subtable ne pokriva i input glifovi koje LookupFlag ignoriše svi vraćaju bezbedan no-op (False / OutGID = InputGID / empty OutGIDs / ConsumedCount = 1) tako da pozivaoci nikada ne vide izuzetke za rutinske slučajeve „nema primenjene zamene”

 

LookupType matrix

LookupType 1 (Single Substitution) - jedan glif se mapira na jedan zamenski glif Kanonske funkcije: salt, ss01-ss20, smcp, onum, liga kada je LookupType 1 povezan, plus init / medi / fina / isol arapski pozicioni oblici u fontovima koji ih vode kroz GSUB Koristite GetSingleSubstituteGlyph

LookupType 2 (Multiple Substitution) - jedan glif se deli na sekvencu zamenjivačkih glifova. Canonical user: ccmp Glyph Composition / Decomposition (latinična slova sa akcentima u kombinovanoj formi podeljena na osnovni glif + kombinovani znaci za kasnije postavljanje oznaka). Koristite GetMultipleSubstituteGlyphs

LookupType 3 (Alternate Substitution) - jedan glif se mapira na jedan od N alternativnih glifova. Kanonske funkcije: aalt (Access All Alternates), salt kada je povezan kao Type 3, titl (Titling Alternates), ss01-ss20 stilistički setovi kada dizajner fonta nudi više od jedne alternative po slotu. Koristite GetAlternateGlyphCount + GetAlternateGlyph

LookupType 4 (Ligature Substitution) - N input glyphs fold into one ligature. Canonical features: liga (Standard Ligatures: fi / fl / ffi / ffl), clig (Contextual Ligatures), dlig (Discretionary Ligatures), hlig (Historical Ligatures), rlig (Required Ligatures - Arabic LAM-ALEF and similar), Indic script ligatures (akhn, pres, blws, psts). Use ApplyLigatureSubstitution.

LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - poklapa ulazni niz glifova i prosleđuje ugnježdene lookup-ove na tačno određenim pozicijama unutar poklapanja. Implementirane su sve tri Format varijante (1 literalni niz, 2 ClassDef niz, 3 Coverage niz); SequenceLookupRecord dispatcher ponovo ulazi u LookupList i obrađuje ugnježdene lookup-ove Single / Multiple / Alternate (prvi) / Ligature uz aktivno praćenje MatchPositions. Kanonske funkcije: rclt (Required Contextual Alternates - Arabic init/medi/fina/isol kada je GSUB-driven), clig, calt, Indic shaping pres / blws / psts / half / pstf / cjct. Koristite ApplyContextualSubst (jedna ulazna tačka pokriva i LookupType 5 i 6)

LookupType 7 (Extension Substitution) - čisti sloj indirekcije koji OpenType specifikacija definiše za fontove čija se podtabela zamene nalazi van 16-bitnog dometa LookupList-a. Svaki javni API transparentno prati 32-bitnu Offset32 indirekciju do stvarne LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8 podtabele. Otključava teške CJK / Indic fontove (Noto Sans CJK, Noto Sans Devanagari) čiji GSUB prelazi 64 KB. Nema zasebnog API-ja - odmotavanje je automatsko

LookupType 8 (Reverse Chained Contextual Single Substitution) - context-aware 1:1 substitution whose distinguishing feature is that callers must apply it in REVERSE scan order over a multi-glyph run (end -> start) because each substitute may depend on FUTURE lookahead context that must not have been substituted yet. Canonical use: Arabic / Syriac / N'Ko / Indic contextual alternates whose final form depends on the following glyph. Use ApplyReverseChainedContextualSubst; the caller drives the reverse scan loop.

 

Script / LangSys selection

Podrazumevano engine preferira DFLT skriptu (ili prvu skriptu koju font deklarše) i podrazumevani LangSys. Pozovite SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / etc.) i SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / etc., trailing-space padded to 4 bytes) da biste zaključali upite na određeni par skripta / jezik. Prazan string vraća podrazumevanu putanju. Izbori ostaju između upita i brišu se na RegisterUnicodeTTF('', nil)

 

Strict-vs-fallback semantika: nepoznat ScriptTag čini da naredni upiti vraćaju prazne no-op rezultate (tako da pozivaoci mogu da otkriju da izabrana skripta nije dostupna); nepoznat LangTag pada nazad na podrazumevani LangSys te skripte po OpenType konvenciji. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures nabraja ono što učitani font zaista oglašava

 

LookupFlag honor and GDEF

Svaki upit čita LookupFlag svake Lookup tabele (i opcioni završni markFilteringSet uint16 kada je useMarkFilteringSet postavljen) i preskače ulazne glifove označene za ignore. Poštuju se bitovi definisani specifikacijom: ignoreBaseGlyphs (0x0002, preskače GDEF klasu 1), ignoreLigatures (0x0004, preskače klasu 2), ignoreMarks (0x0008, preskače klasu 3), useMarkFilteringSet (0x0010) i visokobajtni markAttachmentType. ClassDef Format 1 + 2 se oba parsiraju; GDEF v1.0 / v1.1 / v1.2 zaglavlja se sva prihvataju. Fontovi bez GDEF tabele padaju na "nijedan glif nije ignorisan" tako da izlaz ostaje byte-identičan za pozivaoce koji koriste GDEF-less fontove

 

TTF subsetter closure (MarkUnicodeGlyphUsed)

HotPDF-ov v2.84.0 TTF subsetter izvodi svoj skup korišćenih glifova iz FUnicodeUsedCps kroz cmap. GSUB zamenski glifovi (stilističke alternative, ligature, kontekstualne varijante - sve što 7 gore navedenih query API-ja vraća) obično nemaju codepoint koji do njih stiže kroz cmap, pa su ranije bili nevidljivi subsetter-u i čitač je prikazivao .notdef na njihovom mestu

 

Nakon što u PDF tekst strim emitujete bilo koji GID koji vrate GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst, pozovite MarkUnicodeGlyphUsed(GID) jednom po emitovanom GID-u da biste ga ubacili u ugrađeni subset. Pomoćnik je idempotentan, odbramben (GID-ovi van opsega se tiho odbacuju) i integriše se sa v2.84.0 composite-glyph closure prolazom: pozivaocu je dovoljno da označi samo top-level zamenski GID - kompozitne komponente se automatski povlače

 

Typical workflow (Latin small caps)

 

PDF.RegisterUnicodeTTF('myFont', 'C:\\Windows\\Fonts\\arial.ttf');

PDF.SetGSUBScript('latn');

PDF.SetGSUBLanguage('');  // default LangSys

SmallCapGID := PDF.GetSingleSubstituteGlyph(InputGID, 'smcp');

if SmallCapGID <> InputGID then

begin

  // emit SmallCapGID into the page content stream...

  PDF.MarkUnicodeGlyphUsed(SmallCapGID);  // pull into subset

end;

 

Typical workflow (Arabic LAM-ALEF ligature)

 

PDF.SetGSUBScript('arab');

Run := [LamGID, FathaGID, AlefGID];  // GID-ovi posle cmap-a

if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then

begin

  // emit LigGID + advance by ConsumedCount

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Scope and limitations

Engine je capability-only query surface: odgovara na pitanje "šta bi GSUB ovde uradio", ali ne pokreće automatski pipeline oblikovanja (Harfbuzz-klasa rasporeda, rearanžiranje za Indic svesno klastera, BiDi razrešenje, GPOS pozicioniranje, pričvršćivanje oznaka). Pozivaoci su odgovorni za vođenje scan petlje, izbor koji zamenski / alternativni glif da emituju, pozivanje MarkUnicodeGlyphUsed za svaki emitovani zamenski GID i primenu bilo kog GPOS / mark pozicioniranja koje font zahteva

 

Producer-side Arabic / Persian / Urdu shaping (LAM-ALEF mandatory ligature + Arabic Presentation Forms-A) is implemented as a separate built-in pipeline that runs automatically during text emission - see Arabic / Persian / Urdu Shaping.

 

Version trace

v2.119.43 Single Substitution + Phase 1. v2.119.44 Multiple + Alternate (Phase 2). v2.119.45 Ligature (Phase 3). v2.119.46 Extension + GDEF + respektovanje LookupFlag (Phase 4). v2.119.47 Contextual + Chained Contextual + dispatcher SequenceLookupRecord (Phase 5). v2.119.48 Reverse Chained Contextual - zatvorena LookupType 1-8 matrica (Phase 6). v2.119.49 Script / LangSys API za izbor (Phase 7). v2.119.50 zatvaranje TTF subsetter-a preko MarkUnicodeGlyphUsed (Phase 9; Phase 8 je bio spike integracije producer-side shaping-a i podeljen je u 8a-8f za buduće revizije)

 

See also: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting