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ćuje pozivateljima da upituju, upravljaju i ugrađuju svaku vrstu zamjene glifova koju OpenType font deklarira - ligature, stilističke alternative, kontekstualne varijante, arapske / Indic oblike oblikovanja, CJK alternativne oblike i tako dalje. Svaki OpenType GSUB LookupType od 1 do 8 implementiran je i izložen kao površina za upit samo o mogućnostima; pozivatelj upravlja emitiranjem teksta i odlučuje koji zamjenski glif zapisati u content stream stranice

 

Javni 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 spremi njegove GSUB / GDEF / cmap tablice. Svaki upit za zamjenu prolazi kroz lanac ScriptList / LangSysList / FeatureList / LookupList fonta i predaje se odgovarajućem LookupType rukovatelju. Dvanaest metoda iznad potpuna su javna površina; sve ostalo (obilazak cmapa, parsiranje ScriptLista, lookup Coverage tablice, razrješenje ClassDef, poštivanje LookupFlag, odmotavanje Extension omotača, ugniježđeni dispatch SequenceLookupRecorda) živi iza te površine

 

Defenzivni ugovor vrijedi posvuda: fontovi bez GSUB tablice, značajke s oznakom koja nije duga četiri bajta, značajke koje odabrana skripta / jezik ne oglašava, GID-ovi koje nijedna podtablica ne pokriva i ulazni glifovi koje LookupFlag ignorira svi vraćaju siguran no-op (False / OutGID = InputGID / empty OutGIDs / ConsumedCount = 1), pa pozivatelji nikada ne vide iznimke za rutinske slučajeve "no substitution applies"

 

Matrica LookupType

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

LookupType 2 (Multiple Substitution) - jedan glif se rastavlja u niz zamjenskih glifova. Kanonska upotreba: ccmp Glyph Composition / Decomposition (unaprijed složena naglašena latinična slova rastavljaju se na osnovu + kombinirajuće oznake za daljnje pozicioniranje oznaka). Koristite GetMultipleSubstituteGlyphs

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

LookupType 4 (Ligature Substitution) - N ulaznih glifova spaja se u jednu ligaturu. Kanonske značajke: liga (Standard Ligatures: fi / fl / ffi / ffl), clig (Contextual Ligatures), dlig (Discretionary Ligatures), hlig (Historical Ligatures), rlig (Required Ligatures - Arabic LAM-ALEF i slično), ligature indic skripti (akhn, pres, blws, psts). Koristite ApplyLigatureSubstitution

LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - podudara se s ulaznim slijedom glifova i poziva ugniježđene upite na određenim pozicijama unutar podudaranja. Implementirane su sve tri Format varijante (1 literalni slijed, 2 ClassDef slijed, 3 Coverage slijed); dispatcher SequenceLookupRecord ponovno ulazi u LookupList i obrađuje ugniježđene upite Single / Multiple / Alternate (prvi) / Ligature uz aktivno praćenje MatchPositions. Kanonske značajke: rclt (Required Contextual Alternates - arapski init/medi/fina/isol kada ih vodi GSUB), clig, calt, Indic shaping pres / blws / psts / half / pstf / cjct. Koristite ApplyContextualSubst (jedna ulazna točka pokriva i LookupType 5 i 6)

LookupType 7 (Extension Substitution) - čisti sloj indirekcije koji OpenType specifikacija definira za fontove čija se podtablica zamjene nalazi izvan 16-bitnog dosega LookupLista. Svaki javni API transparentno prati 32-bitnu indirekciju Offset32 do stvarne podtablice LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Otključava teške CJK / Indic fontove (Noto Sans CJK, Noto Sans Devanagari) čiji GSUB prelazi 64 KB. Nema zasebnog API-ja - otpakiranje je automatsko

LookupType 8 (Reverse Chained Contextual Single Substitution) - kontekstno svjesna 1:1 zamjena čija je ključna značajka da je pozivatelji moraju primijeniti u REVERSE redoslijedu skeniranja preko višeglifnog niza (kraj -> početak) jer svaka zamjena može ovisiti o budućem kontekstu pogledom unaprijed koji još ne smije biti zamijenjen. Kanonska uporaba: arapske / sirijske / N'Ko / Indic kontekstualne alternative čiji završni oblik ovisi o sljedećem glifu. Koristite ApplyReverseChainedContextualSubst; pozivatelj vodi obrnuti scan loop

 

Odabir skripte / LangSysa

Po zadanom engine preferira skriptu DFLT (ili prvu skriptu koju font deklarira) i zadani 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) kako biste upite prikovali na određeni par skripta / jezika. Prazan niz vraća zadanu početnu vrijednost. Odabiri ostaju između upita i brišu se na RegisterUnicodeTTF('', nil)

 

Semantika strict-vs-fallback: nepoznati ScriptTag uzrokuje da sljedeći upiti vraćaju prazne no-op rezultate (tako da pozivatelji mogu otkriti da odabrana skripta nije dostupna); nepoznati LangTag pada natrag na zadani LangSys skripte prema OpenType konvenciji. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures nabrajaju ono što učitani font doista oglašava

 

Poštivanje LookupFlag i GDEF

Svaki upit čita LookupFlag svake Lookup tablice (i opcionalni završni markFilteringSet uint16 kada je useMarkFilteringSet postavljen) i preskače ulazne glifove označene za ignoriranje. Poštuju se bitovi definirani specifikacijom: ignoreBaseGlyphs (0x0002, preskoči GDEF klasu 1), ignoreLigatures (0x0004, preskoči klasu 2), ignoreMarks (0x0008, preskoči klasu 3), useMarkFilteringSet (0x0010) i visoki bajt markAttachmentType. Oba ClassDef formata 1 + 2 su parsirana; GDEF zaglavlja v1.0 / v1.1 / v1.2 sva se prihvaćaju. Fontovi bez GDEF tablice padaju na "nijedan glif nije ignoriran", pa izlaz ostaje byte-identičan za pozivatelje koji koriste fontove bez GDEF-a

 

Zatvaranje TTF podskupa (MarkUnicodeGlyphUsed)

HotPDF-ov v2.84.0 TTF subsetter izvodi skup upotrijebljenih glifova iz FUnicodeUsedCps kroz cmap. GSUB zamjenski glifovi (stilističke alternative, ligature, kontekstualne varijante - sve što vraća 7 gore navedenih API-ja za upit) obično nemaju codepoint koji do njih vodi kroz cmap, pa su prije bili nevidljivi subsetteru i čitač potrošač je umjesto njih prikazivao .notdef

Nakon što se bilo koji GID vraćen kroz GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst emitira u PDF text stream, pozovite MarkUnicodeGlyphUsed(GID) jednom po emitiranom GID-u kako biste ga povukli u ugrađeni subset. Pomoćna funkcija je idempotentna, defenzivna (GID-ovi izvan raspona tiho se odbacuju) i integrira se s v2.84.0 prolazom zatvaranja složenih glifova: pozivatelji trebaju označiti samo top-level zamjenski GID - sastavni dijelovi 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');

Primjer: Run := [LamGID, FathaGID, AlefGID];  // GID-ovi nakon cmap

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

begin

  // emit LigGID + advance by ConsumedCount

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Opseg i ograničenja

Engine je površina za upite samo o mogućnostima: odgovara na pitanje "što bi GSUB ovdje napravio", ali ne pokreće automatski shaping pipeline (raspored klase Harfbuzz, klasterski svjesno premještanje za Indic, BiDi razrješenje, GPOS pozicioniranje, prianjanje oznaka). Pozivatelji su odgovorni za upravljanje scan loopom, odabir koje zamjene / alternative emitirate, pozivanje MarkUnicodeGlyphUsed za svaki emitirani zamjenski GID i primjenu svakog GPOS / mark pozicioniranja koje font traži

 

Oblikovanje arapskog / perzijskog / urdskog na strani proizvođača (obvezna ligatura LAM-ALEF + Arabic Presentation Forms-A) implementirano je kao zaseban ugrađeni pipeline koji se automatski pokreće tijekom emitiranja teksta - pogledajte Oblikovanje arapskog / perzijskog / urdskog

 

Trag verzija

v2.119.43 Single Substitution + faza 1. v2.119.44 Multiple + Alternate (faza 2). v2.119.45 Ligature (faza 3). v2.119.46 Extension + GDEF + poštivanje LookupFlag (faza 4). v2.119.47 Contextual + Chained Contextual + SequenceLookupRecord dispatcher (faza 5). v2.119.48 Reverse Chained Contextual - matrica LookupType 1-8 zatvorena (faza 6). v2.119.49 API za odabir Script / LangSys (faza 7). v2.119.50 zatvaranje TTF subsettera kroz MarkUnicodeGlyphUsed (faza 9; faza 8 bila je probni skok integracije oblikovanja na strani proizvođača i podijeljena je u 8a-8f za buduće revizije)

 

Vidi također: Oblikovanje arapskog / perzijskog / urdskog, CFF / OpenType funkcije podskupova fontova, THotPDF.EnableFontSubsetting