|
Motorul de substituție OpenType GSUB Suprafață de capabilități pentru substituția glifelor (v2.119.43 - v2.119.50)
|
Arabic Shaping CFF / OpenType Subsetting |
|
Motorul OpenType GSUB (Glyph SUBstitution) din HotPDF le permite apelanților să interogheze, să conducă și să încorporeze orice tip de substituție de glif declarată de un font OpenType - ligaturi, alternative stilistice, variante contextuale, forme de formare arabă / Indic, forme alternative CJK și așa mai departe. Toate LookupType-urile OpenType GSUB de la 1 la 8 sunt implementate și expuse ca o suprafață de interogare orientată doar pe capabilități; apelantul conduce emiterea textului și decide ce glif substitut să scrie în fluxul de conținut al paginii
API public 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);
Descriere Motorul se activează după ce
Contract defensiv peste tot: fonturile fără tabel GSUB, feature tag-urile care nu au 4 octeți, funcțiile pe care scriptul / limba selectată nu le declară, GID-urile acoperite de niciun subtable și glifele de intrare ignorate de LookupFlag se întorc toate ca no-op sigur (False / OutGID = InputGID / OutGIDs goale / ConsumedCount = 1), astfel încât apelanții să nu vadă niciodată excepții pentru cazurile de rutină de tipul "nu se aplică nicio substituție"
Matricea LookupType LookupType 1 (Single Substitution) - un glif se mapează la un singur substitut. Funcții canonice: LookupType 2 (Multiple Substitution) - un glif se descompune într-o secvență de glife substitut. Utilizare canonica: LookupType 3 (Alternate Substitution) - un glif se mapează la una dintre N alternative. Funcții canonice: LookupType 4 (Ligature Substitution) - N glife de intrare se comasează într-o ligatură. Funcții canonice: LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - potrivește o secvență de glife de intrare și redirecționează interogări imbricate către poziții specifice din interiorul potrivirii. Sunt implementate toate cele trei variante de Format (1 secvență literală, 2 secvență ClassDef, 3 secvență Coverage); dispatcher-ul SequenceLookupRecord reia LookupList și tratează interogări imbricate Single / Multiple / Alternate (first) / Ligature cu urmărirea în timp real a MatchPositions. Funcții canonice: LookupType 7 (Extension Substitution) - un strat pur de indirection pe care specificația OpenType îl definește pentru fonturile a căror sub-tabelă de substituție se află dincolo de raza de 16 biți a LookupList. Fiecare API public urmărește transparent indirectionarea Offset32 pe 32 de biți către sub-tabela reală LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Deblochează fonturi grele CJK / Indic (Noto Sans CJK, Noto Sans Devanagari) ale căror GSUB depășesc 64 KB. Fără API separat - despachetarea este automată LookupType 8 (Reverse Chained Contextual Single Substitution) - substituție context-aware 1:1 al cărei aspect distinctiv este că apelanții trebuie să o aplice în ordine de scanare INVERSĂ peste o secvență cu mai multe glife (sfârșit -> început), deoarece fiecare substitut poate depinde de contextul de anticipare din VIITOR care nu trebuie să fi fost substituit încă. Utilizare canonică: alternative contextuale arabe / siriace / N'Ko / Indic ale căror forme finale depind de gliful următor. Folosiți
Selectarea Script / LangSys În mod implicit, motorul preferă scriptul
Semantica strict-vs-fallback: un
Respectarea LookupFlag și GDEF Fiecare interogare citește LookupFlag-ul fiecărei tabele Lookup (și markFilteringSet-ul opțional de 16 biți de la final când
Închiderea subsetter-ului TTF (MarkUnicodeGlyphUsed) Subsetter-ul TTF din HotPDF v2.84.0 își derivă setul de glife folosite din
După emiterea oricărui GID returnat de
Flux tipic de lucru (majuscule mici latine)
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;
Flux tipic de lucru (ligatura arabă LAM-ALEF)
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;
Domeniu și limitări Motorul este o suprafață de interogare doar pentru capabilități: răspunde la întrebarea „ce ar face GSUB aici”, dar nu rulează un pipeline automat de shaping (layout de clasă Harfbuzz, reordonare conștientă de clustere pentru Indic, rezolvare BiDi, poziționare GPOS, atașare de mark-uri). Apelanții sunt responsabili să conducă bucla de scanare, să aleagă ce substitut / alternativă să emită, să apeleze
Shaping-ul arab / persan / urdu pe partea producătorului (ligatura obligatorie LAM-ALEF + Arabic Presentation Forms-A) este implementat ca un pipeline intern separat care rulează automat în timpul emiterii textului - vezi Arabic / Persian / Urdu Shaping
Istoric versiuni 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 + respectarea LookupFlag (Faza 4). v2.119.47 Contextual + Chained Contextual + dispecer SequenceLookupRecord (Faza 5). v2.119.48 Reverse Chained Contextual - matricea LookupType 1-8 închisă (Faza 6). v2.119.49 API de selecție Script / LangSys (Faza 7). v2.119.50 închiderea subsetterului TTF prin
See also: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting |