OpenType GSUB-substitutionsmotor

Kapacitetsyta för glyfsubstitution (v2.119.43 - v2.119.50)

 

Arabisk formning  CFF / OpenType-subsetting

OpenType GSUB-motorn (Glyph SUBstitution) i HotPDF låter anropare fråga, styra och bädda in varje typ av glyfsubstitution som ett OpenType-typsnitt deklarerar - ligaturer, stilistiska alternativ, kontextuella varianter, arabiska / indiska formningsformer, alternativa CJK-former och så vidare. Varje OpenType GSUB LookupType 1 till 8 är implementerad och exponerad som en ren kapacitetsfrågeyta; anroparen styr textemissionen och väljer vilken ersättningsglyf som ska skrivas till sidans innehållsström.

 

Offentligt API

type

  TGSUBStringArray = array of AnsiString;

 

// LookupType 1 - Single Substitution (en glyf -> en glyf)

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

 

// LookupType 2 - Multiple Substitution (en glyf -> glyfsekvens)

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

  var OutGIDs: array of Word): Boolean;

 

// LookupType 3 - Alternate Substitution (en glyf -> ett av N alternativ)

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

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

  AlternateIndex: Integer): Word;

 

// LookupType 4 - Ligature Substitution (N glyfer -> en ligatur)

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;

 

// Val av Script / LangSys (fas 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-subsettarens slutning (fas 9)

procedure MarkUnicodeGlyphUsed(GID: Word);

 

Beskrivning

Motorn aktiveras efter att RegisterUnicodeTTF har tolkat ett typsnitt och cachelagrat dess GSUB / GDEF / cmap-tabeller. Varje substitutionsfråga går igenom typsnittets ScriptList / LangSysList / FeatureList / LookupList-kedja och skickar vidare till rätt LookupType-hanterare. De 12 metoderna ovan är hela den offentliga ytan; allt annat (cmap-genomgång, ScriptList-tolkning, Coverage-tabellsökning, ClassDef-upplösning, LookupFlag-respekt, uppackning av Extension-omslag, nästlad SequenceLookupRecord-dispatch) ligger bakom den ytan.

 

Defensivt kontrakt genomgående: typsnitt utan GSUB-tabell, feature-taggar som inte är 4 byte, funktioner som valt script / språk inte annonserar, GID:er som ingen undertabell täcker och ingångsglyfer som ignoreras av LookupFlag returnerar alla ett säkert no-op (False / OutGID = InputGID / tomma OutGIDs / ConsumedCount = 1), så anropare aldrig får undantag för rutinfall där "ingen substitution gäller".

 

LookupType-matris

LookupType 1 (Single Substitution) - en glyf mappas till en ersättare. Kanoniska funktioner: salt, ss01-ss20, smcp, onum, liga när LookupType 1 är kopplad, plus arabiska positionsformer init / medi / fina / isol i typsnitt som driver dem via GSUB. Använd GetSingleSubstituteGlyph.

LookupType 2 (Multiple Substitution) - en glyf delas upp i en sekvens av ersättningsglyfer. Kanonisk användare: ccmp Glyph Composition / Decomposition (förkomponerade accentuerade latinska bokstäver delas upp i bas + kombinerande tecken för senare märkespositionering). Använd GetMultipleSubstituteGlyphs.

LookupType 3 (Alternate Substitution) - en glyf mappas till ett av N alternativ. Kanoniska funktioner: aalt (Access All Alternates), salt när den är kopplad som Type 3, titl (Titling Alternates), stilistiska uppsättningar ss01-ss20 när typsnittsdesignern erbjuder mer än ett alternativ per plats. Använd GetAlternateGlyphCount + GetAlternateGlyph.

LookupType 4 (Ligature Substitution) - N ingångsglyfer viks ihop till en ligatur. Kanoniska funktioner: liga (Standard Ligatures: fi / fl / ffi / ffl), clig (Contextual Ligatures), dlig (Discretionary Ligatures), hlig (Historical Ligatures), rlig (Required Ligatures - arabiska LAM-ALEF och liknande), ligaturer för indiska skript (akhn, pres, blws, psts). Använd ApplyLigatureSubstitution.

LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - matchar en ingångsglyfsekvens och skickar nästlade lookupar till specifika positioner i matchningen. Alla tre Format-varianter (1 literal sekvens, 2 ClassDef-sekvens, 3 Coverage-sekvens) är implementerade; SequenceLookupRecord-dispatchern går in i LookupList igen och hanterar nästlade Single / Multiple / Alternate (första) / Ligature-lookupar med live-spårning av MatchPositions. Kanoniska funktioner: rclt (Required Contextual Alternates - arabiska init/medi/fina/isol när de drivs av GSUB), clig, calt, indisk formning pres / blws / psts / half / pstf / cjct. Använd ApplyContextualSubst (en ingångspunkt täcker både LookupType 5 och 6).

LookupType 7 (Extension Substitution) - rent indirektionslager som OpenType-specifikationen definierar för typsnitt vars substitutionsundertabell ligger utanför LookupListens 16-bitars räckvidd. Varje offentligt API följer transparent 32-bitars Offset32-indirektionen till den verkliga LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8-undertabellen. Det låser upp tunga CJK / indiska typsnitt (Noto Sans CJK, Noto Sans Devanagari) vars GSUB överstiger 64 KB. Inget separat API - uppackningen är automatisk.

LookupType 8 (Reverse Chained Contextual Single Substitution) - kontextmedveten 1:1-substitution vars särskilda egenskap är att anropare måste använda den i OMVÄND skanningsordning över en flerglyfskörning (slut -> start), eftersom varje ersättare kan bero på FRAMTIDA lookahead-kontext som ännu inte får ha substituerats. Kanonisk användning: arabiska / syriska / N'Ko / indiska kontextuella alternativ vars slutform beror på följande glyf. Använd ApplyReverseChainedContextualSubst; anroparen driver den omvända skanningsloopen.

 

Val av Script / LangSys

Som standard föredrar motorn scriptet DFLT (eller det första script som typsnittet deklarerar) och standard-LangSys. Anropa SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / etc.) och SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / etc., utfyllt med avslutande blanksteg till 4 byte) för att fästa frågor vid ett specifikt script / språk-par. En tom sträng återställer standardvägens baslinje. Valen ligger kvar mellan frågor och rensas av RegisterUnicodeTTF('', nil).

 

Strict-vs-fallback-semantik: en okänd ScriptTag gör att efterföljande frågor returnerar tomma no-op-resultat (så anropare kan upptäcka att valt script saknas); en okänd LangTag faller tillbaka till scriptets standard-LangSys enligt OpenType-konventionen. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures räknar upp vad det inlästa typsnittet faktiskt annonserar.

 

LookupFlag-respekt och GDEF

Varje fråga läser varje Lookup-tabells LookupFlag (och valfri avslutande markFilteringSet uint16 när useMarkFilteringSet är satt) och hoppar över ingångsglyfer som är flaggade för ignorering. De specdefinierade bitarna respekteras: ignoreBaseGlyphs (0x0002, hoppa över GDEF-klass 1), ignoreLigatures (0x0004, hoppa över klass 2), ignoreMarks (0x0008, hoppa över klass 3), useMarkFilteringSet (0x0010) och det höga byte-värdet markAttachmentType. ClassDef Format 1 + 2 tolkas båda; GDEF v1.0 / v1.1 / v1.2-huvuden accepteras alla. Typsnitt utan GDEF-tabell faller tillbaka till "ingen glyf ignoreras", så utdata förblir byte-identiska för anropare som använder typsnitt utan GDEF.

 

TTF-subsettarens slutning (MarkUnicodeGlyphUsed)

HotPDF:s TTF-subsetter i v2.84.0 härleder sin uppsättning använda glyfer från FUnicodeUsedCps via cmap. GSUB-ersättningsglyfer (stilistiska alternativ, ligaturer, kontextuella varianter - allt som de 7 fråge-API:erna ovan returnerar) saknar normalt en codepoint som når dem via cmap, så de var tidigare osynliga för subsettern och läsarprogrammet renderade .notdef i deras ställe.

 

Efter att du har emitterat någon GID som returneras av GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst till en PDF-textström, anropa MarkUnicodeGlyphUsed(GID) en gång per emitterad GID för att dra in den i den inbäddade delmängden. Hjälparen är idempotent, defensiv (GID:er utanför intervallet släpps tyst) och integreras med v2.84.0-passagen för sammansatt glyfslutning: anropare behöver bara markera den översta ersättnings-GID:n - sammansatta komponenter dras in automatiskt.

 

Typiskt arbetsflöde (latinska kapitäler)

 

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

PDF.SetGSUBScript('latn');

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

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

if SmallCapGID <> InputGID then

begin

  // emittera SmallCapGID till sidans innehållsström...

  PDF.MarkUnicodeGlyphUsed(SmallCapGID);  // dra in i delmängden

end;

 

Typiskt arbetsflöde (arabisk LAM-ALEF-ligatur)

 

PDF.SetGSUBScript('arab');

Run := [LamGID, FathaGID, AlefGID];  // GID:er efter cmap

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

begin

  // emittera LigGID + avancera med ConsumedCount

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Omfattning och begränsningar

Motorn är en ren kapacitetsfrågeyta: den svarar på "vad skulle GSUB göra här", men den kör ingen automatisk formningspipeline (layout i Harfbuzz-klass, klustermedveten omordning för indiska skript, BiDi-upplösning, GPOS-positionering, mark attachment). Anropare ansvarar för att driva skanningsloopen, välja vilken ersättare / alternativ glyf som ska emitteras, anropa MarkUnicodeGlyphUsed för varje emitterad ersättnings-GID och tillämpa all GPOS / mark-positionering som typsnittet kräver.

 

Producentstyrd arabisk / persisk / urdu-formning (obligatorisk LAM-ALEF-ligatur + Arabic Presentation Forms-A) är implementerad som en separat inbyggd pipeline som körs automatiskt under textemission - se arabisk / persisk / urdu-formning.

 

Versionsspår

v2.119.43 Single Substitution + fas 1. v2.119.44 Multiple + Alternate (fas 2). v2.119.45 Ligature (fas 3). v2.119.46 Extension + GDEF + LookupFlag-respekt (fas 4). v2.119.47 Contextual + Chained Contextual + SequenceLookupRecord-dispatcher (fas 5). v2.119.48 Reverse Chained Contextual - LookupType 1-8-matrisen stängd (fas 6). v2.119.49 API för val av Script / LangSys (fas 7). v2.119.50 TTF-subsettarens slutning via MarkUnicodeGlyphUsed (fas 9; fas 8 var en producentstyrd formningsintegrationsspik och delades upp i 8a-8f för framtida revisioner).

 

Se även: Arabisk / persisk / urdu-formning, Funktioner för CFF / OpenType-typsnittssubsetting, THotPDF.EnableFontSubsetting