|
OpenType GSUB Substitution Engine Glyph substitution capability surface (v2.119.43 - v2.119.50)
|
Arabic Shaping CFF / OpenType Subsetting |
|
OpenType GSUB (Glyph SUBstitution) engine unutar HotPDF-a omogućava pozivaocima da ispituju, upravljaju i ugrađuju svaku vrstu zamene glifa koju OpenType font deklarše - ligature, stilske alternative, kontekstualne varijante, Arabic / Indic oblike oblikovanja, CJK alternativne oblike i slično Svaki OpenType GSUB LookupType od 1 do 8 je implementiran i izložen kao capability-only query surface; pozivalac upravlja emitovanjem teksta i odlučuje koji zamenski glif da upiše u strim sadržaja stranice
Public 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);
Opis Engine se aktivira nakon što RegisterUnicodeTTF parsira font i kešira njegove GSUB / GDEF / cmap tabele Svaki upit za zamenu prolazi kroz lanac ScriptList / LangSysList / FeatureList / LookupList fonta i prosleđuje ga odgovarajućem LookupType handleru Gornjih 12 metoda predstavlja kompletnu javnu površinu; sve ostalo (cmap prolaz, ScriptList parsiranje, Coverage lookup, ClassDef razrešenje, poštovanje LookupFlag, odmotavanje Extension omotača, ugnježdeno prosleđivanje SequenceLookupRecord) živi iza te površine
Defensive contract throughout: fontovi bez GSUB tabele, feature tagovi koji nisu 4 bajta, features koje izabrana skripta / jezik ne oglašava, GID-ovi koje nijedan subtable ne pokriva i input glifovi koje LookupFlag ignoriše svi vraćaju bezbedan no-op (False / OutGID = InputGID / empty OutGIDs / ConsumedCount = 1) tako da pozivaoci nikada ne vide izuzetke za rutinske slučajeve „nema primenjene zamene”
LookupType matrix LookupType 1 (Single Substitution) - jedan glif se mapira na jedan zamenski glif Kanonske funkcije: salt, ss01-ss20, smcp, onum, liga kada je LookupType 1 povezan, plus init / medi / fina / isol arapski pozicioni oblici u fontovima koji ih vode kroz GSUB Koristite GetSingleSubstituteGlyph LookupType 2 (Multiple Substitution) - jedan glif se deli na sekvencu zamenjivačkih glifova. Canonical user: ccmp Glyph Composition / Decomposition (latinična slova sa akcentima u kombinovanoj formi podeljena na osnovni glif + kombinovani znaci za kasnije postavljanje oznaka). Koristite GetMultipleSubstituteGlyphs LookupType 3 (Alternate Substitution) - jedan glif se mapira na jedan od N alternativnih glifova. Kanonske funkcije: aalt (Access All Alternates), salt kada je povezan kao Type 3, titl (Titling Alternates), ss01-ss20 stilistički setovi kada dizajner fonta nudi više od jedne alternative po slotu. Koristite GetAlternateGlyphCount + GetAlternateGlyph LookupType 4 (Ligature Substitution) - N input glyphs fold into one ligature. Canonical features: LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - poklapa ulazni niz glifova i prosleđuje ugnježdene lookup-ove na tačno određenim pozicijama unutar poklapanja. Implementirane su sve tri Format varijante (1 literalni niz, 2 ClassDef niz, 3 Coverage niz); SequenceLookupRecord dispatcher ponovo ulazi u LookupList i obrađuje ugnježdene lookup-ove Single / Multiple / Alternate (prvi) / Ligature uz aktivno praćenje MatchPositions. Kanonske funkcije: rclt (Required Contextual Alternates - Arabic init/medi/fina/isol kada je GSUB-driven), clig, calt, Indic shaping pres / blws / psts / half / pstf / cjct. Koristite ApplyContextualSubst (jedna ulazna tačka pokriva i LookupType 5 i 6) LookupType 7 (Extension Substitution) - čisti sloj indirekcije koji OpenType specifikacija definiše za fontove čija se podtabela zamene nalazi van 16-bitnog dometa LookupList-a. Svaki javni API transparentno prati 32-bitnu Offset32 indirekciju do stvarne LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8 podtabele. Otključava teške CJK / Indic fontove (Noto Sans CJK, Noto Sans Devanagari) čiji GSUB prelazi 64 KB. Nema zasebnog API-ja - odmotavanje je automatsko LookupType 8 (Reverse Chained Contextual Single Substitution) - context-aware 1:1 substitution whose distinguishing feature is that callers must apply it in REVERSE scan order over a multi-glyph run (end -> start) because each substitute may depend on FUTURE lookahead context that must not have been substituted yet. Canonical use: Arabic / Syriac / N'Ko / Indic contextual alternates whose final form depends on the following glyph. Use
Script / LangSys selection Podrazumevano engine preferira
Strict-vs-fallback semantika: nepoznat ScriptTag čini da naredni upiti vraćaju prazne no-op rezultate (tako da pozivaoci mogu da otkriju da izabrana skripta nije dostupna); nepoznat LangTag pada nazad na podrazumevani LangSys te skripte po OpenType konvenciji. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures nabraja ono što učitani font zaista oglašava
LookupFlag honor and GDEF Svaki upit čita LookupFlag svake Lookup tabele (i opcioni završni markFilteringSet uint16 kada je useMarkFilteringSet postavljen) i preskače ulazne glifove označene za ignore. Poštuju se bitovi definisani specifikacijom: ignoreBaseGlyphs (0x0002, preskače GDEF klasu 1), ignoreLigatures (0x0004, preskače klasu 2), ignoreMarks (0x0008, preskače klasu 3), useMarkFilteringSet (0x0010) i visokobajtni markAttachmentType. ClassDef Format 1 + 2 se oba parsiraju; GDEF v1.0 / v1.1 / v1.2 zaglavlja se sva prihvataju. Fontovi bez GDEF tabele padaju na "nijedan glif nije ignorisan" tako da izlaz ostaje byte-identičan za pozivaoce koji koriste GDEF-less fontove
TTF subsetter closure (MarkUnicodeGlyphUsed) HotPDF-ov v2.84.0 TTF subsetter izvodi svoj skup korišćenih glifova iz FUnicodeUsedCps kroz cmap. GSUB zamenski glifovi (stilističke alternative, ligature, kontekstualne varijante - sve što 7 gore navedenih query API-ja vraća) obično nemaju codepoint koji do njih stiže kroz cmap, pa su ranije bili nevidljivi subsetter-u i čitač je prikazivao .notdef na njihovom mestu
Nakon što u PDF tekst strim emitujete bilo koji GID koji vrate GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst, pozovite MarkUnicodeGlyphUsed(GID) jednom po emitovanom GID-u da biste ga ubacili u ugrađeni subset. Pomoćnik je idempotentan, odbramben (GID-ovi van opsega se tiho odbacuju) i integriše se sa v2.84.0 composite-glyph closure prolazom: pozivaocu je dovoljno da označi samo top-level zamenski GID - kompozitne komponente se automatski povlače
Typical workflow (Latin small caps)
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;
Typical workflow (Arabic LAM-ALEF ligature)
PDF.SetGSUBScript('arab'); Run := [LamGID, FathaGID, AlefGID]; // GID-ovi posle cmap-a if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then begin // emit LigGID + advance by ConsumedCount PDF.MarkUnicodeGlyphUsed(LigGID); end;
Scope and limitations Engine je capability-only query surface: odgovara na pitanje "šta bi GSUB ovde uradio", ali ne pokreće automatski pipeline oblikovanja (Harfbuzz-klasa rasporeda, rearanžiranje za Indic svesno klastera, BiDi razrešenje, GPOS pozicioniranje, pričvršćivanje oznaka). Pozivaoci su odgovorni za vođenje scan petlje, izbor koji zamenski / alternativni glif da emituju, pozivanje
Producer-side Arabic / Persian / Urdu shaping (LAM-ALEF mandatory ligature + Arabic Presentation Forms-A) is implemented as a separate built-in pipeline that runs automatically during text emission - see 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 + respektovanje LookupFlag (Phase 4). v2.119.47 Contextual + Chained Contextual + dispatcher SequenceLookupRecord (Phase 5). v2.119.48 Reverse Chained Contextual - zatvorena LookupType 1-8 matrica (Phase 6). v2.119.49 Script / LangSys API za izbor (Phase 7). v2.119.50 zatvaranje TTF subsetter-a preko MarkUnicodeGlyphUsed (Phase 9; Phase 8 je bio spike integracije producer-side shaping-a i podeljen je u 8a-8f za buduće revizije)
See also: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting |