OpenType GSUB Substitution Engine

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

 

Arabic Shaping  CFF / OpenType Subsetting

HotPDF viduje esantis OpenType GSUB (Glyph SUBstitution) variklis leidžia kūrėjams teirautis, valdyti ir įterpti bet kokį glifų pakeitimą, kurį deklaruoja OpenType šriftas - ligatūras, stilistinius alternatyvius variantus, kontekstinius variantus, Arabic / Indic formavimo formas, CJK alternatyvias formas ir t. t. Įgyvendintos visos OpenType GSUB LookupType nuo 1 iki 8, o paviršius pateikiamas kaip tik galimybių tikrinimo sąsaja; kūrėjas pats valdo teksto išvedimą ir nusprendžia, kurį pakaitinį glifą rašyti į puslapio turinio srautą

 

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);

 

Aprašas

Variklis aktyvuojamas po to, kai RegisterUnicodeTTF išparsina šriftą ir į talpyklą įrašo jo GSUB / GDEF / cmap lenteles. Kiekviena pakeitimo užklausa pereina per šrifto ScriptList / LangSysList / FeatureList / LookupList grandinę ir nukreipiama į atitinkamą LookupType tvarkyklę. Toliau nurodyti 12 metodų sudaro visą viešą paviršių; visa kita (cmap peržiūra, ScriptList analizė, Coverage lentelės paieška, ClassDef sprendimas, LookupFlag paisymas, Extension apvalkalo išskleidimas, SequenceLookupRecord įdėtinė dispatch logika) lieka už jo

 

Visoje vietoje laikomasi gynybinės sutarties: šriftai be GSUB lentelės, ne 4 baitų funkcijų žymos, funkcijos, kurių pasirinktas scriptas / kalba nepaskelbia, GID, kurių neapima jokia po lentelė, ir LookupFlag ignoruojami įvesties glifai visi grąžina saugų no-op (False / OutGID = InputGID / tušti OutGIDs / ConsumedCount = 1), kad kviestinė pusė įprastais atvejais "substitucija netaikoma" nematytų išimčių

 

LookupType matrix

LookupType 1 (Single Substitution) - vienas glifas susiejamas su vienu pakaitalu. Kanoninės funkcijos: salt, ss01-ss20, smcp, onum, liga, kai LookupType 1 prijungtas, taip pat init / medi / fina / isol arabų pozicinės formos šriftuose, kurie jas valdo per GSUB. Naudokite GetSingleSubstituteGlyph

LookupType 2 (Kelių pakaitalų) - vienas glifas padalijamas į pakaitinių glifų seką. Kanoninis atvejis: ccmp glifų komponavimas / išskaidymas (prie šrifto sukurti lotyniški su kirčiais simboliai išskiriami į pagrindą ir derinimo žymes tolesniam žymių pozicionavimui). Naudokite GetMultipleSubstituteGlyphs

LookupType 3 (Alternate Substitution) - vienas glifas susiejamas su vienu iš N alternatyvų. Kanoninės funkcijos: aalt (Access All Alternates), salt, kai prijungtas kaip Type 3, titl (Titling Alternates), ss01-ss20 stilistiniai rinkiniai, kai šrifto kūrėjas siūlo daugiau nei vieną alternatyvą vienai vietai. Naudokite 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) - atitinka įvesties glifų seką ir vykdo įdėtus lookup'us konkrečiose atitikmens vietose. Įgyvendinti visi trys Format variantai (1 pažodinė seka, 2 ClassDef seka, 3 Coverage seka); SequenceLookupRecord dispatcher'is pakartotinai įeina į LookupList ir su gyvu MatchPositions stebėjimu apdoroja Single / Multiple / Alternate (pirmą) / Ligature įdėtus lookup'us. Kanoninės funkcijos: rclt (Required Contextual Alternates - arabų init/medi/fina/isol, kai valdoma per GSUB), clig, calt, indiškas formavimas pres / blws / psts / half / pstf / cjct. Naudokite ApplyContextualSubst (vienas įėjimo taškas apima ir LookupType 5, ir 6)

LookupType 7 (Extension Substitution) - grynas netiesioginis sluoksnis, kurį OpenType specifikacija apibrėžia šriftams, kurių substitucijos po lentelė yra už 16 bitų LookupList pasiekiamumo ribos. Kiekviena vieša API skaidriai seka 32 bitų Offset32 netiesioginę nuorodą į tikrąją LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8 po lentelę. Atblokuoja sunkius CJK / Indic šriftus (Noto Sans CJK, Noto Sans Devanagari), kurių GSUB viršija 64 KB. Atskiros API nėra - išvyniojimas vyksta automatiškai

LookupType 8 (Reverse Chained Contextual Single Substitution) - konteksto priklausomas 1:1 pakeitimas, kurio skiriamasis bruožas yra tas, kad kviestinė pusė turi jį taikyti REVERSE nuskaitymo tvarka kelių glifų sekoje (nuo galo į pradžią), nes kiekvienas pakaitalas gali priklausyti nuo būsimų lookahead kontekstų, kurie dar neturi būti pakeisti. Tipinis naudojimas: arabų / sirų / N'Ko / Indic kontekstinės alternatyvos, kurių galutinė forma priklauso nuo paskesnio glifo. Naudokite ApplyReverseChainedContextualSubst; atvirkštinę nuskaitymo kilpą valdo kviestinė pusė

 

Script / LangSys selection

Pagal numatymą variklis renkasi DFLT scriptą (arba pirmąjį šrifto deklaruotą scriptą) ir numatytąjį LangSys. Norėdami užfiksuoti konkrečią script / language porą, kvieskite SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / t. t.) ir SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / t. t., su tarpais iki 4 baitų). Tuščia eilutė atkuria numatytąjį kelio pagrindą. Pasirinkimai išlieka tarp užklausų ir išvalomi per RegisterUnicodeTTF('', nil)

 

Strict-vs-fallback semantika: nežinomas ScriptTag daro taip, kad vėlesnės užklausos grąžina tuščius no-op rezultatus (kad kviestinė pusė galėtų aptikti, jog pasirinktas scriptas neprieinamas); nežinomas LangTag grįžta prie šrifto numatytojo LangSys pagal OpenType konvenciją. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures išvardija, ką įkeltas šriftas iš tikrųjų skelbia

 

LookupFlag honor and GDEF

Kiekviena užklausa skaito kiekvienos Lookup lentelės LookupFlag (ir pasirinktinį galinį markFilteringSet uint16, kai nustatytas useMarkFilteringSet) ir praleidžia įvesties glifus, pažymėtus ignoravimui. Gerbiami specifikacijoje apibrėžti bitai: ignoreBaseGlyphs (0x0002, praleisti GDEF klasę 1), ignoreLigatures (0x0004, praleisti klasę 2), ignoreMarks (0x0008, praleisti klasę 3), useMarkFilteringSet (0x0010) ir aukštasis baitas markAttachmentType. ClassDef Format 1 ir 2 abu analizuojami; priimamos GDEF v1.0 / v1.1 / v1.2 antraštės. Šriftai be GDEF lentelės grįžta prie "nė vienas glifas neignoruoja", kad išvestis liktų baitas į baitą identiška GDEF neturintiems šriftams

 

TTF subsetter closure (MarkUnicodeGlyphUsed)

HotPDF v2.84.0 TTF pogrupio kūrėjas savo naudojamų glifų rinkinį išveda iš FUnicodeUsedCps per cmap. GSUB pakaitiniai glifai (stilistinės alternatyvos, junginiai, kontekstiniai variantai - viskas, ką grąžina 7 aukščiau esančios užklausų API) paprastai neturi kodo taško, kuris juos pasiektų per cmap, todėl anksčiau jie pogrupio kūrėjui buvo nematomi, o vartotojo skaitytuvas jų vietoje rodydavo .notdef

 

Išvedę į PDF teksto srautą bet kurį GID, grąžintą GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst, vieną kartą kiekvienam išvestam GID kvieskite MarkUnicodeGlyphUsed(GID), kad jis būtų įtrauktas į įterptą pogrupį. Pagalbinė funkcija yra idempotentinė, atspari klaidoms (už ribų esantys GID tyliai atmetami) ir integruojasi su v2.84.0 sudėtinių glifų uždarymo etapu: kviestinė pusė turi pažymėti tik viršutinio lygio pakaitinį GID - sudėtiniai komponentai įtraukiami automatiškai

 

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];  // post-cmap GIDs

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

begin

  // emit LigGID + advance by ConsumedCount

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Scope and limitations

Variklis yra tik galimybių tikrinimo sąsaja: jis atsako „ką čia darytų GSUB“, bet nevykdo automatinės formavimo grandinės (Harfbuzz klasės išdėstymo, klasterius suvokiančio Indic pertvarkymo, BiDi sprendimo, GPOS pozicionavimo, mark attachment). Kūrėjai patys atsako už nuskaitymo ciklo valdymą, pasirinkimą, kurį pakaitinį / alternatyvų variantą išvesti, MarkUnicodeGlyphUsed kvietimą kiekvienam išvedamam pakaitiniam GID ir bet kokį GPOS / mark pozicionavimą, kurio reikia šriftui

 

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 Viengubas pakaitalas + 1 etapas, v2.119.44 Kelių pasirinkimų + Alternatyva + 2 etapas, v2.119.45 Ligatūra + 3 etapas, v2.119.46 Pratęsimas + GDEF + LookupFlag pagerinimas + 4 etapas, v2.119.47 Kontekstinis + grandininis kontekstinis + SequenceLookupRecord perdavėjas + 5 etapas, v2.119.48 Atvirkštinis grandininis kontekstinis - LookupType 1-8 matrica uždaryta + 6 etapas, v2.119.49 Skripto / LangSys pasirinkimo API + 7 etapas, v2.119.50 TTF rinkinio uždarymo užtikrinimas per MarkUnicodeGlyphUsed + 9 etapas; 8 etapas buvo kūrėjo pusės formavimo integracijos proveržis, suskaidytas į 8a-8f būsimuose pakeitimuose

 

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