|
Silnik substytucji OpenType GSUB Powierzchnia możliwości substytucji glifów (v2.119.43 - v2.119.50)
|
Kształtowanie arabskie Podzbiory CFF / OpenType |
|
Silnik OpenType GSUB (Glyph SUBstitution) w HotPDF pozwala kodowi wywołującemu odpytywać, sterować i osadzać każdy rodzaj substytucji glifów deklarowany przez font OpenType - ligatury, alternatywy stylistyczne, warianty kontekstowe, arabskie / indyjskie formy kształtowania, alternatywne formy CJK itd. Wszystkie OpenType GSUB LookupType od 1 do 8 są zaimplementowane i udostępnione jako powierzchnia zapytań o możliwości; kod wywołujący steruje emisją tekstu i decyduje, który glif zastępczy zapisać do strumienia zawartości strony.
Publiczne API type TGSUBStringArray = array of AnsiString;
// LookupType 1 - Single Substitution (jeden glif -> jeden glif) function GetSingleSubstituteGlyph(InputGID: Word; const FeatureTag: AnsiString): Word;
// LookupType 2 - Multiple Substitution (jeden glif -> sekwencja glifów) function GetMultipleSubstituteGlyphs(InputGID: Word; const FeatureTag: AnsiString; var OutGIDs: array of Word): Boolean;
// LookupType 3 - Alternate Substitution (jeden glif -> jedna z N alternatyw) function GetAlternateGlyphCount(InputGID: Word; const FeatureTag: AnsiString): Integer; function GetAlternateGlyph(InputGID: Word; const FeatureTag: AnsiString; AlternateIndex: Integer): Word;
// LookupType 4 - Ligature Substitution (N glifów -> jedna ligatura) 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;
// Wybór Script / LangSys (faza 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;
// Domknięcie subsettera TTF (faza 9) procedure MarkUnicodeGlyphUsed(GID: Word);
Opis Silnik aktywuje się po tym, jak
Kontrakt defensywny obowiązuje wszędzie: fonty bez tabeli GSUB, tagi feature inne niż 4-bajtowe, funkcje nieogłaszane przez wybrany script / language, GID-y nieobjęte żadną podtabelą oraz glify wejściowe ignorowane przez LookupFlag zwracają bezpieczne no-op (False / OutGID = InputGID / puste OutGIDs / ConsumedCount = 1), więc kod wywołujący nie dostaje wyjątków dla rutynowych przypadków „brak pasującej substytucji”.
Macierz LookupType LookupType 1 (Single Substitution) - jeden glif mapuje się na jeden zamiennik. Kanoniczne funkcje: LookupType 2 (Multiple Substitution) - jeden glif dzieli się na sekwencję glifów zastępczych. Kanoniczny użytkownik: LookupType 3 (Alternate Substitution) - jeden glif mapuje się na jedną z N alternatyw. Kanoniczne funkcje: LookupType 4 (Ligature Substitution) - N glifów wejściowych składa się w jedną ligaturę. Kanoniczne funkcje: LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - dopasowuje sekwencję glifów wejściowych i uruchamia zagnieżdżone lookupy w konkretnych pozycjach dopasowania. Zaimplementowane są wszystkie trzy warianty Format (1 sekwencja literalna, 2 sekwencja ClassDef, 3 sekwencja Coverage); dyspozytor SequenceLookupRecord ponownie wchodzi do LookupList i obsługuje zagnieżdżone lookupy Single / Multiple / Alternate (pierwszy) / Ligature z bieżącym śledzeniem MatchPositions. Kanoniczne funkcje: LookupType 7 (Extension Substitution) - czysta warstwa pośrednia, którą specyfikacja OpenType definiuje dla fontów, których podtabela substytucji leży poza 16-bitowym zasięgiem LookupList. Każde publiczne API przezroczysto podąża przez 32-bitową pośrednią Offset32 do rzeczywistej podtabeli LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Odblokowuje ciężkie fonty CJK / indyjskie (Noto Sans CJK, Noto Sans Devanagari), których GSUB przekracza 64 KB. Nie ma osobnego API - rozpakowanie jest automatyczne. LookupType 8 (Reverse Chained Contextual Single Substitution) - kontekstowa substytucja 1:1, której cechą wyróżniającą jest to, że kod wywołujący musi stosować ją w ODWROTNEJ kolejności skanowania po wieloglifowym ciągu (koniec -> początek), ponieważ każdy zamiennik może zależeć od PRZYSZŁEGO kontekstu lookahead, który nie mógł zostać jeszcze zastąpiony. Kanoniczne użycie: arabskie / syriackie / N'Ko / indyjskie alternatywy kontekstowe, których forma końcowa zależy od kolejnego glifu. Użyj
Wybór Script / LangSys Domyślnie silnik preferuje script
Semantyka strict-vs-fallback: nieznany
Respektowanie LookupFlag i GDEF Każde zapytanie odczytuje LookupFlag każdej tabeli Lookup (oraz opcjonalny końcowy uint16 markFilteringSet, gdy ustawione jest
Domknięcie subsettera TTF (MarkUnicodeGlyphUsed) Subsetter TTF HotPDF v2.84.0 wyprowadza zestaw użytych glifów z
Po wyemitowaniu dowolnego GID zwróconego przez
Typowy przepływ (łacińskie kapitaliki)
PDF.RegisterUnicodeTTF('myFont', 'C:\\Windows\\Fonts\\arial.ttf'); PDF.SetGSUBScript('latn'); PDF.SetGSUBLanguage(''); // domyślny LangSys SmallCapGID := PDF.GetSingleSubstituteGlyph(InputGID, 'smcp'); if SmallCapGID <> InputGID then begin // emituj SmallCapGID do strumienia zawartości strony... PDF.MarkUnicodeGlyphUsed(SmallCapGID); // wciągnij do podzbioru end;
Typowy przepływ (arabska ligatura LAM-ALEF)
PDF.SetGSUBScript('arab'); Run := [LamGID, FathaGID, AlefGID]; // GID-y po cmap if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then begin // emituj LigGID + przesuń o ConsumedCount PDF.MarkUnicodeGlyphUsed(LigGID); end;
Zakres i ograniczenia Silnik jest powierzchnią zapytań wyłącznie o możliwości: odpowiada na pytanie „co GSUB zrobiłby tutaj”, ale nie uruchamia automatycznego potoku kształtowania (układ klasy Harfbuzz, zmiana kolejności z uwzględnieniem klastrów dla pism indyjskich, rozwiązywanie BiDi, pozycjonowanie GPOS, przyłączanie znaków). Kod wywołujący odpowiada za sterowanie pętlą skanowania, wybór emitowanego zamiennika / alternatywy, wywołanie
Kształtowanie arabskie / perskie / urdu po stronie producenta (obowiązkowa ligatura LAM-ALEF + Arabic Presentation Forms-A) jest zaimplementowane jako osobny wbudowany potok, który uruchamia się automatycznie podczas emisji tekstu - zobacz kształtowanie arabskie / perskie / urdu.
Ślad wersji 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 + respektowanie LookupFlag (faza 4). v2.119.47 Contextual + Chained Contextual + dyspozytor SequenceLookupRecord (faza 5). v2.119.48 Reverse Chained Contextual - macierz LookupType 1-8 zamknięta (faza 6). v2.119.49 API wyboru Script / LangSys (faza 7). v2.119.50 domknięcie subsettera TTF przez
Zobacz też: Kształtowanie arabskie / perskie / urdu, Funkcje tworzenia podzbioru fontów CFF / OpenType, THotPDF.EnableFontSubsetting |