OpenType GSUB-substitusjonsmotor

Flate for glyferstatning (v2.119.43 - v2.119.50)

 

Arabic Shaping  CFF / OpenType Subsetting

OpenType GSUB-motoren (Glyph SUBstitution) i HotPDF lar kallere spørre om, styre og bygge inn alle typer glyferstatning som en OpenType-font erklærer - ligaturer, stilistiske alternativer, kontekstuelle varianter, arabiske / indiske shaping-former, alternative CJK-former og så videre. Hver OpenType GSUB LookupType 1 til 8 er implementert og eksponert som en ren spørreflate for funksjoner; kalleren styrer tekstutdata og bestemmer hvilken substituert glyf som skal skrives til sideinnholdsstrømmen

 

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

 

Beskrivelse

Motoren aktiveres etter at RegisterUnicodeTTF har analysert en font og bufret GSUB / GDEF / cmap-tabellene. Hver substitusjonsforespørsel går gjennom fontens ScriptList / LangSysList / FeatureList / LookupList-kjede og sender den videre til riktig LookupType-handler. De 12 metodene over er hele den offentlige flaten; alt annet (cmap-gjennomgang, ScriptList-parsing, oppslag i Coverage-tabellen, ClassDef-oppløsning, LookupFlag-håndtering, utpakking av Extension-wrapper, nestet SequenceLookupRecord-distribusjon) ligger bak denne flaten

 

Defensiv kontrakt hele veien: fonter uten en GSUB-tabell, funksjonstagger som ikke er 4 byte, funksjoner som det valgte skriptet / språket ikke annonserer, GID-er som ingen undertabell dekker, og inngangsglyfer som ignoreres av LookupFlag, returnerer alle en trygg no-op (False / OutGID = InputGID / tomme OutGIDs / ConsumedCount = 1) slik at kallere aldri ser unntak i de vanlige tilfellene der ingen substitusjon gjelder

 

LookupType-matrise

LookupType 1 (enkelt substitusjon) - én glyf mappes til én erstatning. Kanoniske funksjoner: salt, ss01-ss20, smcp, onum, liga når LookupType 1 er koblet inn, pluss arabiske posisjonsformer init / medi / fina / isol i fonter som driver dem gjennom GSUB. Bruk GetSingleSubstituteGlyph

LookupType 2 (flergangs substitusjon) - én glyf deles i en sekvens av erstatningsglyfer. Kanonisk bruk: ccmp Glyph Composition / Decomposition, der forhåndssammensatte aksentuerte latinske bokstaver deles i base + kombinerende tegn for videre markposisjonering. Bruk GetMultipleSubstituteGlyphs

LookupType 3 (alternativ substitusjon) - én glyf mappes til én av N alternativer. Kanoniske funksjoner: aalt (Access All Alternates), salt når det er koblet som Type 3, titl (Titling Alternates), ss01-ss20 stilistiske sett når fontdesigneren tilbyr mer enn ett alternativ per plass. Bruk GetAlternateGlyphCount + GetAlternateGlyph

LookupType 4 (ligatursubstitusjon) - N inngående glyfer foldes inn i én ligatur. Kanoniske funksjoner: liga (Standard Ligatures: fi / fl / ffi / ffl), clig (Contextual Ligatures), dlig (Discretionary Ligatures), hlig (Historical Ligatures), rlig (Required Ligatures - arabisk LAM-ALEF og lignende), ligaturer for indiske skriftsystemer (akhn, pres, blws, psts). Bruk ApplyLigatureSubstitution

LookupType 5 (kontekstuell substitusjon) + LookupType 6 (kjedet kontekstuell substitusjon) - matcher en inngående glyfsekvens og sender nestede oppslag til bestemte posisjoner inne i treffet. Alle tre Format-variantene, 1 literal sequence, 2 ClassDef sequence og 3 Coverage sequence, er implementert; SequenceLookupRecord-dispatcheren går inn i LookupList på nytt og håndterer nestede oppslag av typen Single / Multiple / Alternate (first) / Ligature med levende MatchPositions-sporing. Kanoniske funksjoner: rclt (Required Contextual Alternates - arabiske init/medi/fina/isol når GSUB driver dem), clig, calt, indisk shaping pres / blws / psts / half / pstf / cjct. Bruk ApplyContextualSubst, der én inngang dekker både LookupType 5 og 6

LookupType 7 (utvidelses-substitusjon) - et rent indireksjonslag som OpenType-spesifikasjonen definerer for fonter der substitusjons-undertabellen ligger utenfor den 16-bit store rekkevidden til LookupList. Hver offentlige API følger den 32-bit store Offset32-indireksjonen transparent til den virkelige LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8-undertabellen. Låser opp tunge CJK / Indic-fonter (Noto Sans CJK, Noto Sans Devanagari) der GSUB overstiger 64 KB. Ingen separat API - avviklingen skjer automatisk

LookupType 8 (omvendt kjedet kontekstuell enkelt substitusjon) - kontekstbevisst 1:1-substitusjon der det avgjørende er at kalleren må bruke den i REVERSE skanrekkefølge over en fler-glyf-streng, fra slutt til start, fordi hver erstatning kan avhenge av fremtidig forhåndskikk-kontekst som ennå ikke må være substituert. Kanonisk bruk: arabiske / syriske / N'Ko / indiske kontekstuelle alternativer der sluttformen avhenger av den påfølgende glyfen. Bruk ApplyReverseChainedContextualSubst; kalleren styrer den omvendte skanløkken

 

Valg av Script / LangSys

Som standard foretrekker motoren DFLT-skriptet (eller det første skriptet fonten erklærer) og den normale LangSys. Kall SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / osv.) og SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / osv., med avsluttende mellomrom utfylt til 4 byte) for å låse forespørsler til et bestemt skript / språkpar. Tom streng gjenoppretter standardbanen. Valg vedvarer mellom forespørsler og nullstilles ved RegisterUnicodeTTF('', nil)

 

Streng-versus-fallbakke-semantikk: en ukjent ScriptTag gjør at senere spørsmål returnerer tomme no-op-resultater, slik at kallere kan oppdage at det valgte skriptet ikke er tilgjengelig; en ukjent LangTag faller tilbake til skriptets standard LangSys etter OpenType-konvensjon. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures lister opp det den innlastede fonten faktisk annonserer

 

LookupFlag-oppførsel og GDEF

Hvert spørsmål leser LookupFlag i hver Lookup-tabell, og den valgfrie avsluttende markFilteringSet uint16 når useMarkFilteringSet er satt, og hopper over inngående glyfer som er merket for ignorering. De spesifiserte bitene respekteres: ignoreBaseGlyphs (0x0002, hopp over GDEF-klasse 1), ignoreLigatures (0x0004, hopp over klasse 2), ignoreMarks (0x0008, hopp over klasse 3), useMarkFilteringSet (0x0010) og høybyte-verdien markAttachmentType. Både ClassDef Format 1 og 2 parses; GDEF v1.0 / v1.1 / v1.2-hoder aksepteres alle. Fonter uten GDEF-tabell faller tilbake til at ingen glyfer ignoreres, slik at utdata forblir byte-identisk for kallere som bruker GDEF-løse fonter

 

Lukking av TTF-underinndeler (MarkUnicodeGlyphUsed)

HotPDFs v2.84.0 TTF-underinndeler utleder settet med brukte glyfer fra FUnicodeUsedCps gjennom cmap. GSUB-erstatningsglyfer (stilistiske alternativer, ligaturer, kontekstuelle varianter - alt de 7 forespørsels-API-ene over returnerer) har vanligvis ikke noe kodepunkt som når dem via cmap, så de var tidligere usynlige for underinndeleren og leserprogrammet rendret .notdef i stedet

 

Etter at du har sendt ut en hvilken som helst GID som returneres av GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst inn i en PDF-tekststrøm, kaller du MarkUnicodeGlyphUsed(GID) én gang per utstedt GID for å trekke den inn i det innebygde delsettet. Hjelperen er idempotent, defensiv, GID-er utenfor område droppes stille, og den integreres med v2.84.0-lukkepass for sammensatte glyfer: kallere trenger bare å markere toppnivå-erstatnings-GID; komposittkomponenter trekkes inn automatisk

 

Typisk arbeidsflyt (latinske små kapitéler)

 

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;

 

Typisk arbeidsflyt (arabisk LAM-ALEF-ligatur)

 

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;

 

Omfang og begrensninger

Motoren er en ren spørreflate for funksjoner: den svarer på "hva ville GSUB gjort her", men den kjører ikke en automatisk shaping-pipeline (Harfbuzz-klasse layout, klyngebasert omorganisering for indisk, BiDi-oppløsning, GPOS-posisjonering, marktilknytning). Kallere har ansvar for å styre skanneløkken, velge hvilken substitusjon / alternativ som skal sendes ut, kalle MarkUnicodeGlyphUsed for hver utsendt substituert GID og bruke eventuell GPOS / mark-posisjonering fonten krever

 

Forming på produsentsiden for arabisk / persisk / urdu (obligatorisk LAM-ALEF-ligatur + Arabic Presentation Forms-A) er implementert som en egen innebygd pipeline som kjøres automatisk under tekstutdata - se arabisk / persisk / urdu-forming

 

Versjonsspor

v2.119.43 Enkelt substitusjon + fase 1. v2.119.44 Multiple + Alternate (fase 2). v2.119.45 Ligatur (fase 3). v2.119.46 Extension + GDEF + LookupFlag-håndtering (fase 4). v2.119.47 Kontekstuell + kjedet kontekstuell + SequenceLookupRecord-dispatcher (fase 5). v2.119.48 Omvendt kjedet kontekstuell - LookupType 1-8-matrisen er lukket (fase 6). v2.119.49 API for valg av Script / LangSys (fase 7). v2.119.50 TTF-subsetteren lukkes via MarkUnicodeGlyphUsed (fase 9; fase 8 var et integreringsspike for shaping på produsentsiden og ble delt i 8a-8f for fremtidige revisjoner)

 

Se også: Arabisk / persisk / urdu shaping, CFF / OpenType skriftdelsinnsettingsfunksjoner, THotPDF.EnableFontSubsetting