OpenType GSUB değiştirme motoru

Glif değiştirme yetenek yüzeyi (v2.119.43 - v2.119.50)

 

Arapça şekillendirme  CFF / OpenType alt kümeleme

HotPDF içindeki OpenType GSUB (Glyph SUBstitution) motoru, çağıran kodun bir OpenType fontun bildirdiği her türlü glif değiştirmeyi sorgulamasına, yönlendirmesine ve gömmesine izin verir - ligatürler, stilistik alternatifler, bağlamsal varyantlar, Arapça / Hint yazıları için şekillendirme formları, CJK alternatif formları vb. OpenType GSUB LookupType 1'den 8'e kadar tüm türler uygulanır ve yalnızca yetenek sorgulama yüzeyi olarak sunulur; çağıran kod metin çıktısını yönetir ve sayfa içerik akışına hangi yedek glifin yazılacağına karar verir.

 

Genel API

type

  TGSUBStringArray = array of AnsiString;

 

// LookupType 1 - Single Substitution (bir glif -> bir glif)

function GetSingleSubstituteGlyph(InputGID: Word; const FeatureTag: AnsiString): Word;

 

// LookupType 2 - Multiple Substitution (bir glif -> glif dizisi)

function GetMultipleSubstituteGlyphs(InputGID: Word; const FeatureTag: AnsiString;

  var OutGIDs: array of Word): Boolean;

 

// LookupType 3 - Alternate Substitution (bir glif -> N alternatiften biri)

function GetAlternateGlyphCount(InputGID: Word; const FeatureTag: AnsiString): Integer;

function GetAlternateGlyph(InputGID: Word; const FeatureTag: AnsiString;

  AlternateIndex: Integer): Word;

 

// LookupType 4 - Ligature Substitution (N glif -> bir ligatür)

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 seçimi (faz 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 kapanışı (faz 9)

procedure MarkUnicodeGlyphUsed(GID: Word);

 

Açıklama

Motor, RegisterUnicodeTTF bir fontu ayrıştırıp GSUB / GDEF / cmap tablolarını önbelleğe aldıktan sonra etkinleşir. Her değiştirme sorgusu fontun ScriptList / LangSysList / FeatureList / LookupList zincirinde ilerler ve işi uygun LookupType işleyicisine dağıtır. Yukarıdaki 12 yöntem eksiksiz genel yüzeydir; diğer her şey (cmap dolaşımı, ScriptList ayrıştırma, Coverage tablo araması, ClassDef çözümleme, LookupFlag uyumu, Extension sarmalayıcı açma, SequenceLookupRecord iç içe dağıtımı) bu yüzeyin arkasında kalır.

 

Savunmacı sözleşme baştan sona geçerlidir: GSUB tablosu olmayan fontlar, 4 bayt olmayan feature tag'leri, seçilen script / language tarafından duyurulmayan özellikler, hiçbir alt tablonun kapsamadığı GID'ler ve LookupFlag tarafından yok sayılan giriş glifleri güvenli no-op döndürür (False / OutGID = InputGID / boş OutGIDs / ConsumedCount = 1), böylece çağıranlar rutin "değiştirme uygulanmaz" durumlarında istisna görmez.

 

LookupType matrisi

LookupType 1 (Single Substitution) - bir glif bir yedeğe eşlenir. Kanonik özellikler: LookupType 1 bağlı olduğunda salt, ss01-ss20, smcp, onum, liga ve bunları GSUB üzerinden süren fontlarda Arapça konumsal formlar init / medi / fina / isol. GetSingleSubstituteGlyph kullanın.

LookupType 2 (Multiple Substitution) - bir glif yedek gliflerden oluşan bir diziye ayrılır. Kanonik kullanıcı: ccmp Glyph Composition / Decomposition (önceden birleştirilmiş aksanlı Latin harfleri, sonraki mark konumlandırması için taban + birleştirici işaretlere ayrılır). GetMultipleSubstituteGlyphs kullanın.

LookupType 3 (Alternate Substitution) - bir glif N alternatiften birine eşlenir. Kanonik özellikler: aalt (Access All Alternates), Type 3 olarak bağlı olduğunda salt, titl (Titling Alternates), font tasarımcısı her yuva için birden fazla alternatif sunduğunda ss01-ss20 stilistik kümeleri. GetAlternateGlyphCount + GetAlternateGlyph kullanın.

LookupType 4 (Ligature Substitution) - N giriş glifi tek bir ligatüre katlanır. Kanonik özellikler: liga (Standard Ligatures: fi / fl / ffi / ffl), clig (Contextual Ligatures), dlig (Discretionary Ligatures), hlig (Historical Ligatures), rlig (Required Ligatures - Arapça LAM-ALEF ve benzerleri), Hint yazısı ligatürleri (akhn, pres, blws, psts). ApplyLigatureSubstitution kullanın.

LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - bir giriş glif dizisini eşleştirir ve eşleşme içindeki belirli konumlarda iç içe lookup'ları çalıştırır. Üç Format varyantının tamamı (1 literal dizi, 2 ClassDef dizisi, 3 Coverage dizisi) uygulanır; SequenceLookupRecord dağıtıcısı LookupList'e yeniden girer ve MatchPositions canlı takibiyle Single / Multiple / Alternate (ilk) / Ligature iç içe lookup'larını işler. Kanonik özellikler: rclt (Required Contextual Alternates - GSUB tarafından sürüldüğünde Arapça init/medi/fina/isol), clig, calt, Hint yazısı şekillendirme pres / blws / psts / half / pstf / cjct. ApplyContextualSubst kullanın (tek giriş noktası hem LookupType 5'i hem 6'yı kapsar).

LookupType 7 (Extension Substitution) - OpenType belirtiminin, değiştirme alt tablosu LookupList'in 16 bit erişiminin ötesinde kalan fontlar için tanımladığı saf dolaylama katmanı. Her genel API, gerçek LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8 alt tablosuna giden 32 bit Offset32 dolaylamasını saydam biçimde izler. GSUB'u 64 KB'ı aşan ağır CJK / Hint fontlarının (Noto Sans CJK, Noto Sans Devanagari) önünü açar. Ayrı API yoktur - açma otomatik yapılır.

LookupType 8 (Reverse Chained Contextual Single Substitution) - ayırt edici özelliği, çağıranların çok glifli bir çalışmada bunu TERS tarama sırasıyla (son -> baş) uygulamasını gerektiren bağlam duyarlı 1:1 değiştirmedir; çünkü her yedek henüz değiştirilmemiş olması gereken GELECEK lookahead bağlamına bağlı olabilir. Kanonik kullanım: son formu sonraki glife bağlı olan Arapça / Süryanice / N'Ko / Hint bağlamsal alternatifleri. ApplyReverseChainedContextualSubst kullanın; ters tarama döngüsünü çağıran kod yönetir.

 

Script / LangSys seçimi

Motor varsayılan olarak DFLT script'ini (veya fontun bildirdiği ilk script'i) ve varsayılan LangSys'i tercih eder. Sorguları belirli bir script / language çiftine sabitlemek için SetGSUBScript('latn' / 'arab' / 'cyrl' / 'hani' / 'kana' / 'deva' / 'beng' / 'taml' / etc.) ve SetGSUBLanguage('ENG ' / 'TUR ' / 'AZE ' / 'JAN ' / 'KOR ' / 'ARA ' / etc., 4 bayta kadar sonda boşlukla doldurulmuş) çağırın. Boş string varsayılan yol temelini geri yükler. Seçimler sorgular arasında kalıcıdır ve RegisterUnicodeTTF('', nil) ile temizlenir.

 

Strict-vs-fallback semantiği: bilinmeyen bir ScriptTag sonraki sorguların boş no-op sonuçlar döndürmesine neden olur (böylece çağıranlar seçtikleri script'in kullanılamadığını anlayabilir); bilinmeyen bir LangTag, OpenType geleneğine göre script'in varsayılan LangSys'ine düşer. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures yüklü fontun gerçekten duyurduğu öğeleri numaralandırır.

 

LookupFlag uyumu ve GDEF

Her sorgu, her Lookup tablosunun LookupFlag değerini (ve useMarkFilteringSet ayarlandığında isteğe bağlı sondaki markFilteringSet uint16 değerini) okur ve yok sayılacak şekilde işaretlenen giriş gliflerini atlar. Belirtimde tanımlanan bitlere uyulur: ignoreBaseGlyphs (0x0002, GDEF sınıf 1'i atla), ignoreLigatures (0x0004, sınıf 2'yi atla), ignoreMarks (0x0008, sınıf 3'ü atla), useMarkFilteringSet (0x0010) ve yüksek bayt markAttachmentType. ClassDef Format 1 + 2 birlikte ayrıştırılır; GDEF v1.0 / v1.1 / v1.2 başlıklarının tamamı kabul edilir. GDEF tablosu olmayan fontlar "hiçbir glif yok sayılmaz" davranışına düşer, böylece GDEF'siz font kullanan çağıranlar için çıktı bayt olarak aynı kalır.

 

TTF subsetter kapanışı (MarkUnicodeGlyphUsed)

HotPDF v2.84.0 TTF subsetter, kullanılan glif kümesini cmap üzerinden FUnicodeUsedCps değerinden türetir. GSUB yedek gliflerinin (stilistik alternatifler, ligatürler, bağlamsal varyantlar - yukarıdaki 7 sorgu API'sinin döndürdüğü her şey) genellikle cmap üzerinden onlara ulaşan codepoint'i yoktur; bu nedenle daha önce subsetter için görünmezdi ve tüketici okuyucu yerlerinde .notdef render ederdi.

 

GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst tarafından döndürülen herhangi bir GID'yi PDF metin akışına yazdıktan sonra, onu gömülü alt kümeye çekmek için yayımlanan her GID başına bir kez MarkUnicodeGlyphUsed(GID) çağırın. Yardımcı idempotent ve savunmacıdır (aralık dışı GID'ler sessizce düşürülür) ve v2.84.0 bileşik glif kapanışı geçişiyle entegredir: çağıranların yalnızca üst düzey yedek GID'yi işaretlemesi gerekir - bileşik bileşenler otomatik çekilir.

 

Tipik iş akışı (Latin küçük büyük harfler)

 

PDF.RegisterUnicodeTTF('myFont', 'C:\\Windows\\Fonts\\arial.ttf');

PDF.SetGSUBScript('latn');

PDF.SetGSUBLanguage('');  // varsayılan LangSys

SmallCapGID := PDF.GetSingleSubstituteGlyph(InputGID, 'smcp');

if SmallCapGID <> InputGID then

begin

  // SmallCapGID'yi sayfa içerik akışına yaz...

  PDF.MarkUnicodeGlyphUsed(SmallCapGID);  // alt kümeye çek

end;

 

Tipik iş akışı (Arapça LAM-ALEF ligatürü)

 

PDF.SetGSUBScript('arab');

Run := [LamGID, FathaGID, AlefGID];  // cmap sonrası GID'ler

if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then

begin

  // LigGID yaz + ConsumedCount kadar ilerle

  PDF.MarkUnicodeGlyphUsed(LigGID);

end;

 

Kapsam ve sınırlamalar

Motor yalnızca yetenek sorgulama yüzeyidir: "GSUB burada ne yapardı" sorusunu yanıtlar, ancak otomatik şekillendirme pipeline'ı çalıştırmaz (Harfbuzz sınıfı layout, Hint yazıları için cluster farkında yeniden sıralama, BiDi çözümleme, GPOS konumlandırma, mark attachment). Çağıranlar tarama döngüsünü yönetmekten, hangi yedek / alternatifin yazılacağını seçmekten, yazılan her yedek GID için MarkUnicodeGlyphUsed çağırmaktan ve fontun gerektirdiği GPOS / mark konumlandırmasını uygulamaktan sorumludur.

 

Üretici tarafındaki Arapça / Farsça / Urduca şekillendirme (zorunlu LAM-ALEF ligatürü + Arabic Presentation Forms-A), metin çıktısı sırasında otomatik çalışan ayrı bir yerleşik pipeline olarak uygulanır - bkz. Arapça / Farsça / Urduca şekillendirme.

 

Sürüm izi

v2.119.43 Single Substitution + faz 1. v2.119.44 Multiple + Alternate (faz 2). v2.119.45 Ligature (faz 3). v2.119.46 Extension + GDEF + LookupFlag uyumu (faz 4). v2.119.47 Contextual + Chained Contextual + SequenceLookupRecord dağıtıcısı (faz 5). v2.119.48 Reverse Chained Contextual - LookupType 1-8 matrisi kapandı (faz 6). v2.119.49 Script / LangSys seçim API'si (faz 7). v2.119.50 MarkUnicodeGlyphUsed üzerinden TTF subsetter kapanışı (faz 9; faz 8 üretici tarafı şekillendirme entegrasyon denemesiydi ve gelecek revizyonlar için 8a-8f'ye bölündü).

 

Ayrıca bkz.: Arapça / Farsça / Urduca şekillendirme, CFF / OpenType font alt kümeleme işlevleri, THotPDF.EnableFontSubsetting