OpenType GSUB Substitution Engine

Funktionsoverflade til glyph-substitution (v2.119.43 - v2.119.50)

 

Arabic Shaping  CFF / OpenType Subsetting

OpenType GSUB (Glyph SUBstitution) motoren inde i HotPDF lader kaldere forespørge, styre og indlejre enhver form for glyph-substitution, som en OpenType-skrifttype erklærer - ligaturer, stilistiske alternativer, kontekstuelle varianter, arabiske / indiske formningsformer, alternative CJK-former og så videre. Hver OpenType GSUB LookupType 1 til 8 er implementeret og blotlagt som en funktionsoverflade, der kun dækker forespørgsler; kalderen styrer tekstemission og beslutter, hvilken erstatnings-glyph der skal skrives til sidens indholdsstrøm

 

Offentlig API

type

TGSUBStringArray =array of AnsiString;

 

// LookupType 1 - Enkelt substitution (én glyph -> én glyph)

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

 

// LookupType 2 - Flere substitutioner (én glyph -> sekvens af glyffer)

function GetMultipleSubstituteGlyphs(InputGID: Word; FeatureTag: AnsiString; OutGIDs: array of Word): Boolean;const FeatureTag: AnsiString;

  var OutGIDs:array of Word): Boolean;

 

// LookupType 3 - Alternativ substitution (én glyph -> én af N alternativer)

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

function GetAlternateGlyph(InputGID: Word; FeatureTag: AnsiString; AlternateIndex: Integer): Word;const FeatureTag: AnsiString;

AlternateIndex: Integer): Word;

 

// LookupType 4 - Ligatursubstitution (N glyffer -> én ligatur)

function ApplyLigatureSubstitution(const InputGIDs:array of Word;

StartIndex: Integer; FeatureTag: AnsiString; OutGID: Word; ConsumedCount: Integer): Boolean;const FeatureTag: AnsiString;

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

 

// LookupType 5 + 6 - Kontekstuel / Kædet kontekstuel substitution

function ApplyContextualSubst(const InputGIDs:array of Word;

StartIndex: Integer; FeatureTag: AnsiString; OutGIDs: array of ConsumedLen: Integer): Boolean;const FeatureTag: AnsiString;

  var OutGIDs:array of Word;

  out ConsumedLen: Integer): Boolean;

 

// LookupType 8 - Omvendt kædet kontekstuel enkelt substitution

function ApplyReverseChainedContextualSubst(const InputGIDs:array of Word;

StartIndex: Integer; FeatureTag: AnsiString; OutGID: Word): Boolean;const FeatureTag: AnsiString;

  out OutGID: Word): Boolean;

 

// Script / LangSys valg (Fase 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-undersætsafslutning (Fase 9)

procedure MarkUnicodeGlyphUsed(GID: Word);

 

Beskrivelse

Motoren aktiveres efterRegisterUnicodeTTFhar parseret en skrifttype og cachet dens GSUB / GDEF / cmap tabeller. Hver substitutionsforespørgsel gennemgår skrifttypens ScriptList / LangSysList / FeatureList / LookupList kæde og sender til den relevante LookupType-handler. De 12 metoder ovenfor er den komplette offentlige overflade; alt andet (cmap walkthrough, ScriptList-parsering, Coverage-tabelopslag, ClassDef-opløsning, overholdelse af LookupFlag, udpakning af Extension-indpakning, SequenceLookupRecord indlejret afsendelse) lever bag denne overflade

 

Defensiv kontrakt overalt: skrifttyper uden en GSUB-tabel, ikke-4-byte funktionstags, funktioner, som det valgte script / sprog ikke reklamerer med, GID'er, som ingen undertabel dækker, og LookupFlag-ignorerede inputglyffer returnerer alle en sikker no-op (False / OutGID = InputGID / tomme OutGIDs / ConsumedCount = 1), så kaldere aldrig ser undtagelser for rutinemæssige "ingen substitution gælder" tilfælde

 

LookupType-matrix

LookupType 1 (Enkelt substitution)- én glyph kortlægges til én erstatning. Kanoniske funktioner:salt, ss01-ss20, smcp, onum, liganår LookupType 1 er forbundet, plusinit / medi / fina / isolarabiske positionsformer i skrifttyper, der styrer dem via GSUB. BrugGetSingleSubstituteGlyph.

LookupType 2 (Flere substitutioner)- én glyph opdeles i en sekvens af erstatningsglyffer. Kanonisk bruger:ccmpGlyph-komposition / dekomposition (prækomponerede accentuerede latinske bogstaver opdeles i basis + kombinerende mærker til efterfølgende mærke-positionering). BrugGetMultipleSubstituteGlyphs.

LookupType 3 (Alternativ substitution)- én glyph kortlægges til en af N alternativer. Kanoniske funktioner:aalt(Access All Alternates),saltnår forbundet som Type 3,titl(Titling Alternates),ss01-ss20stilistiske sæt, når skrifttypedesignener tilbyder mere end et alternativ pr. plads. BrugGetAlternateGlyphCount + GetAlternateGlyph.

LookupType 4 (Ligatursubstitution)- N inputglyffer folder til én ligatur. Kanoniske funktioner:liga(Standard Ligatures: fi / fl / ffi / ffl),clig(Contextual Ligatures),dlig(Discretionary Ligatures),hlig(Historical Ligatures),rlig(Required Ligatures - arabisk LAM-ALEF og lignende), indiske skrifttypeligaturer (akhn, pres, blws, psts). Use ApplyLigatureSubstitution.

LookupType 5 (Kontekstuel substitution) + LookupType 6 (Kædet kontekstuel substitution)- matcher en input-glyphsekvens og sender indlejrede opslag på specifikke positioner inde i matchet. Alle tre formatvarianter (1 bogstavelig sekvens, 2 ClassDef-sekvens, 3 Coverage-sekvens) er implementeret; SequenceLookupRecord-afsenderen genindtaster LookupList og håndterer indlejrede Single / Multiple / Alternate (første) / Ligature opslag med live MatchPositions sporing. Kanoniske funktioner:rclt(Required Contextual Alternates - arabisk init/medi/fina/isol når de er GSUB-drevne),clig, calt, indisk formningpres / blws / psts / half / pstf / cjct. Use ApplyContextualSubst(ét indgangspunkt dækker både LookupType 5 og 6)

LookupType 7 (udvidelsessubstitution) er et rent indirektionslag, som OpenType-specifikationen definerer til skrifttyper, hvis substitutionsundertabel ligger uden for 16-bit-området i LookupList. Hvert offentligt API følger gennemsigtigt 32-bit Offset32-indirektionen til den reelle LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8-undertabel. Det låser op for tunge CJK- og indiske skrifttyper (Noto Sans CJK, Noto Sans Devanagari), hvis GSUB overstiger 64 KB. Der er intet separat API; udpakningen er automatisk

LookupType 8 (Omvendt kædet kontekstuel enkelt substitution)- kontekstbevidst 1:1 substitution, hvis adskillende kendetegn er, at kaldere skal anvende det i OMVENDT scanningsrækkefølge over en multigli-kørsel (slut -> start), fordi hver erstatning kan afhænge af FREMTIDIG lookahead-kontekst, som endnu ikke må være substitueret. Kanonisk brug: arabisk / syrisk / N'Ko / indiske kontekstuelle alternativer, hvis endelige form afhænger af den følgende glyph. BrugApplyReverseChainedContextualSubst; kalderen styrer den omvendte scanningsløkke

 

Script / LangSys valg

Som standard foretrækker motorenDFLTscript (eller det første script, skrifttypen erklærer) og standard LangSys. KaldSetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / etc.) and SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / etc., trailing-space padded to 4 bytes)for at fastlåse forespørgsler til et specifikt script- / sprogpar. En tom streng gendanner default-path baselinjen. Valg fortsætter på tværs af forespørgsler og ryddes vedRegisterUnicodeTTF('', nil).

 

Strikte-versus-fallback semantik: et ukendtScriptTagfår efterfølgende forespørgsel til at returnere tomme no-op resultater (så kaldere kan detektere, at deres valgte script ikke er tilgængeligt); et ukendtLangTagfalder tilbage på scriptets standard LangSys i henhold til OpenType-konventionenGetGSUBScripts / GetGSUBLanguages / GetGSUBFeaturesblotlægger, hvad den indlæste skrifttype faktisk reklamerer med

 

Overholdelse af LookupFlag og GDEF

Denne forespørgsel læser hver Lookup-tabels LookupFlag og den valgfrie efterfølgende markFilteringSet uint16, når useMarkFilteringSet er indstillet, og udelader inputglyffer, der er markeret som ignorerede. De specifikationsdefinerede bits respekteres: ignoreBaseGlyphs (0x0002, udelad GDEF-klasse 1), ignoreLigatures (0x0004, udelad klasse 2), ignoreMarks (0x0008, udelad klasse 3), useMarkFilteringSet (0x0010) og den høje byte markAttachmentType. ClassDef Format 1 + 2 parses begge; GDEF v1.0 / v1.1 / v1.2-headere accepteres alle. Skrifttyper uden GDEF-tabel falder tilbage til 'ingen glyph ignoreres', så outputtet forbliver byte-identisk hos kaldere med GDEF-løse skrifttyper

 

TTF-undersætsafslutning (MarkUnicodeGlyphUsed)

HotPDF's v2.84.0 TTF-undersæt afleder sit brugte glyph-sæt fraFUnicodeUsedCpsvia cmap. GSUB-erstatningsglyffer (stilistiske alternativer, ligaturer, kontekstuelle varianter - alt, hvad de 7 forespørgsels-API'er ovenfor returnerer) har typisk intet kodepunkt, der når dem via cmap, så de var tidligere usynlige for undersættet, og forbrugerlæseren gengav.notdefi deres sted

 

Efter emission af enhver GID returneret afGetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubsttil en PDF-tekstrøm, kaldesMarkUnicodeGlyphUsed(GID)en gang pr. emitteret GID for at trække det ind i det indlejrede undersæt. Hjælperen er idempotent, defensiv (GID'er uden for området droppes tavst) og integreres med v2.84.0 sammensatte glyph-afslutningspassagen: kaldere behøver kun at markere top-niveau erstatnings-GID'en - sammensatte komponenter trækkes automatisk med

 

Typisk arbejdsgang (latinske små bogstaver)

 

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

PDF.SetGSUBScript('latn');

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

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

ifSmallCapGID <> InputGIDthen

begin

  // udsend SmallCapGID i sidens indholdsstrøm

PDF.MarkUnicodeGlyphUsed(SmallCapGID);// træk ind i undersæt

end;

 

Typisk arbejdsgang (arabisk LAM-ALEF ligatur)

 

PDF.SetGSUBScript('arab');

Run := [LamGID, FathaGID, AlefGID];// post-cmap GID'er

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

begin

  // emit LigGID + fremføring med ConsumedCount

PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Omfang og begrænsninger

Motoren er kun en forespørgselsflade til funktioner: den svarer på 'hvad ville GSUB gøre her', men kører ikke en automatisk formningspipeline med Harfbuzz-klasse layout, klyngebevidst omorganisering til indiske skrifter, BiDi-løsning, GPOS-positionering eller mærkevedhæftning. Kaldere styrer selv scanningsløkken, vælger hvilken erstatning eller alternativ der udsendes, kalder MarkUnicodeGlyphUsed for hver emitteret erstatnings-GID og anvender den GPOS- eller mærkepositionering, som skrifttypen kræver

 

Producentside-formning af arabisk / persisk / urdu (obligatorisk LAM-ALEF ligatur + arabisk Presentation Forms-A) er implementeret som en separat indbygget pipeline, der kører automatisk under tekstemission - seArabic / Persian / Urdu Shaping.

 

Versionsspor

v2.119.43 Enkelt substitution + Fase 1. v2.119.44 Flere + Alternativ (Fase 2). v2.119.45 Ligatur (Fase 3). v2.119.46 Udvidelse + GDEF + LookupFlag overholdelse (Fase 4). v2.119.47 Kontekstuel + Kædet kontekstuel + SequenceLookupRecord-afsender (Fase 5). v2.119.48 Omvendt kædet kontekstuel - LookupType 1-8 matrix lukket (Fase 6). v2.119.49 Script / LangSys valg API (Fase 7). v2.119.50 TTF-undersætsafslutning viaMarkUnicodeGlyphUsed(Fase 9; Fase 8 var en integrationstest på producentsiden af formningspipeline og blev opdelt i 8a-8f til fremtidige revisioner)

 

Se også: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting