|
OpenType GSUB Substitution Engine Glyph substitution capability surface (v2.119.43 - v2.119.50)
|
Arabic Shaping CFF / OpenType Subsetting |
|
Le moteur OpenType GSUB (Glyph SUBstitution) intégré à HotPDF permet aux appelants d’interroger, de piloter et d’embarquer tout type de substitution de glyphe déclaré par une police OpenType - ligatures, variantes stylistiques, variantes contextuelles, formes de façonnage Arabic / Indic, formes alternatives CJK, et ainsi de suite. Tous les LookupType OpenType GSUB de 1 à 8 sont implémentés et exposés comme surface de requête de capacités uniquement ; l’appelant pilote l’émission du texte et décide quel glyphe substitut écrire dans le flux de contenu de la page
API publique 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);
Description Le moteur s’active après que
Contrat défensif de bout en bout : les polices sans table GSUB, les tags de fonctionnalités non 4-octets, les fonctionnalités que le script / langage choisi n’annonce pas, les GIDs couverts par aucune sous-table et les glyphes d’entrée ignorés via LookupFlag renvoient tous un no-op sûr (False / OutGID = InputGID / OutGIDs vide / ConsumedCount = 1), si bien que les appelants ne voient jamais d’exception pour les cas bénins de « aucune substitution applicable ».
Tableau des LookupType LookupType 1 (Single Substitution) - un glyphe est remplacé par un seul glyphe de substitution. Fonctions canoniques : LookupType 2 (Multiple Substitution) - un glyphe se découpe en une séquence de glyphes de substitution. Cas d’usage canonique : LookupType 3 (Alternate Substitution) - un glyphe est remplacé par l’une des N alternatives. Fonctions canoniques : LookupType 4 (Ligature Substitution) - N glyphes d’entrée se fondent en une seule ligature. Fonctions canoniques : LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - rapproche une séquence de glyphes d’entrée et dispatche des lookups imbriqués à des positions précises dans la correspondance. Les trois variantes de Format (1 séquence littérale, 2 séquence ClassDef, 3 séquence Coverage) sont implémentées ; le dispatcher SequenceLookupRecord ré-entre dans la LookupList et gère les lookups imbriqués Single / Multiple / Alternate (premier) / Ligature avec suivi en direct des MatchPositions. Fonctionnalités canoniques : LookupType 7 (Extension Substitution) - couche d’indirection pure que la spécification OpenType définit pour les polices dont la sous-table de substitution vit au-delà de la portée 16 bits de la LookupList. Chaque API publique suit de façon transparente l’indirection Offset32 32 bits vers la vraie sous-table LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Débloque les grosses polices CJK / Indic (Noto Sans CJK, Noto Sans Devanagari) dont le GSUB dépasse 64 Ko. Aucune API séparée - le déballage est automatique. LookupType 8 (Reverse Chained Contextual Single Substitution) - substitution contextuelle 1:1 dont la particularité est que les appelants doivent l’appliquer en ordre d’analyse inversé sur une séquence multi-glyphe (fin -> début) car chaque substitution peut dépendre d’un contexte de regard en avant futur qui ne doit pas encore avoir été substitué. Cas d’usage canonique : alternatives contextuelles arabe / syriaque / N'Ko / Indic dont la forme finale dépend du glyphe suivant. Utilisez
Sélection du script / LangSys Par défaut, le moteur privilégie le script
Sémantique strict versus repli: un
Prise en compte de LookupFlag et GDEF Chaque requête lit le LookupFlag de chaque table Lookup (ainsi que le markFilteringSet uint16 optionnel en fin de table lorsque
Closure du subsetter TTF (MarkUnicodeGlyphUsed) Le sous-ensemble TTF v2.84.0 de HotPDF déduit son ensemble de glyphes utilisés à partir de
Après avoir émis dans un flux texte PDF tout GID renvoyé par
Type de flux (petites capitales latines)
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;
Workflow type (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;
Portée et limites Le moteur reste une surface de requête de capacités uniquement : il répond à la question "que ferait GSUB ici", mais n’exécute pas de pipeline de façonnage automatique (mise en page de type Harfbuzz, réordonnancement sensible aux clusters pour Indic, résolution BiDi, positionnement GPOS, attache des marques). Les appelants doivent piloter la boucle de balayage, choisir quelle substitution / variante émettre, appeler
Le façonnage côté producteur pour l’arabe / le persan / l’ourdou (ligature obligatoire LAM-ALEF + Arabic Presentation Forms-A) est implémenté comme un pipeline intégré distinct qui s’exécute automatiquement pendant l’émission du texte - voir Arabic / Persian / Urdu Shaping
Version trace v2.119.43 Single Substitution + Phase 1. v2.119.44 Multiple + Alternate (Phase 2). v2.119.45 Ligature (Phase 3). v2.119.46 Extension + GDEF + respect de LookupFlag (Phase 4). v2.119.47 répartiteur Contextual + Chained Contextual + SequenceLookupRecord (Phase 5). v2.119.48 Reverse Chained Contextual - matrice LookupType 1-8 fermée (Phase 6). v2.119.49 API de sélection Script / LangSys (Phase 7). v2.119.50 clôture du sous-ensemble TTF via
Voir aussi: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting |