|
OpenType GSUB Substitution Engine Glyph substitution capability surface (v2.119.43 - v2.119.50)
|
Arabic Shaping CFF / OpenType Subsetting |
|
O motor OpenType GSUB (Glyph SUBstitution) dentro do HotPDF permite aos chamadores consultar, controlar e incorporar todo o tipo de substituição de glifos que um tipo de letra OpenType declara - ligaduras, alternativas estilísticas, variantes contextuais, formas de formação árabe / Indic, formas alternativas CJK e assim por diante. Todos os LookupType 1 a 8 do OpenType GSUB estão implementados e expostos como superfície de consulta apenas de capacidades; o chamador controla a emissão de texto e decide qual o glifo substituto a escrever no fluxo de conteúdo da página
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);
Descrição O motor é ativado depois de
Contrato defensivo em toda a extensão: tipos de letra sem tabela GSUB, tags de funcionalidade que não tenham 4 bytes, funcionalidades que o script/idioma selecionado não anuncia, GIDs sem subtable cobertura e glyphs de entrada ignorados por LookupFlag devolvem todos um no-op seguro (False / OutGID = InputGID / empty OutGIDs / ConsumedCount = 1). Assim, os chamadores nunca veem exceções em casos rotineiros de "nenhuma substituição se aplica"
LookupType matrix LookupType 1 (Single Substitution) - um glifo mapeia para um substituto. Funcionalidades canónicas: salt, ss01-ss20, smcp, onum, liga quando LookupType 1 é ligado, além das formas posicionais árabes init / medi / fina / isol em tipos de letra que as encaminham através de GSUB. Use GetSingleSubstituteGlyph LookupType 2 (Substituição Múltipla) - um glifo divide-se numa sequência de glifos substitutos. Utilização típica: LookupType 3 (Alternate Substitution) - um glifo mapeia para um de N alternates. Funcionalidades canónicas: aalt (Access All Alternates), salt quando ligado como Type 3, titl (Titling Alternates), conjuntos estilísticos ss01-ss20 quando o designer da fonte oferece mais de um alternativo por posição. Use GetAlternateGlyphCount + GetAlternateGlyph LookupType 4 (Ligature Substitution) - N input glyphs fold into one ligature. Canonical features: LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution) - corresponde a uma sequência de glifos de entrada e despacha lookups aninhados em posições específicas dentro da correspondência. As três variantes de Format (1 sequência literal, 2 sequência ClassDef, 3 sequência Coverage) estão implementadas; o dispatcher SequenceLookupRecord reentra no LookupList e trata lookups aninhados Single / Multiple / Alternate (first) / Ligature com tracking ativo de MatchPositions. Funcionalidades canónicas: rclt (Required Contextual Alternates - formas árabes init/medi/fina/isol quando conduzidas por GSUB), clig, calt, shaping Indic pres / blws / psts / half / pstf / cjct. Use ApplyContextualSubst (um ponto de entrada cobre tanto LookupType 5 como 6) LookupType 7 (Extension Substitution) - camada pura de indireção que a especificação OpenType define para tipos de letra cuja subtable de substituição vive para além do alcance de 16 bits do LookupList. Todas as APIs públicas seguem transparentemente a indireção Offset32 de 32 bits para a verdadeira subtable LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Desbloqueia tipos de letra CJK / Indic pesados (Noto Sans CJK, Noto Sans Devanagari) cuja GSUB excede 64 KB. Não existe API separada - o unwrap é automático 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 Por predefinição o motor prefere o script
Semântica strict-vs-fallback: um ScriptTag desconhecido faz com que as consultas seguintes devolvam resultados vazios de no-op (para que os chamadores possam detetar que o script escolhido não está disponível); um LangTag desconhecido recua para o LangSys predefinido do script de acordo com a convenção OpenType. GetGSUBScripts / GetGSUBLanguages / GetGSUBFeatures enumeram o que o tipo de letra carregado realmente anuncia
LookupFlag honor and GDEF Cada consulta lê o LookupFlag de cada tabela Lookup (e o trailing markFilteringSet uint16 opcional quando useMarkFilteringSet está definido) e ignora os glifos de entrada marcados para ignore. Os bits definidos pela especificação são respeitados: ignoreBaseGlyphs (0x0002, ignora GDEF class 1), ignoreLigatures (0x0004, ignora class 2), ignoreMarks (0x0008, ignora class 3), useMarkFilteringSet (0x0010) e o byte alto markAttachmentType. ClassDef Format 1 + 2 são ambos analisados; cabeçalhos GDEF v1.0 / v1.1 / v1.2 são todos aceites. Tipos de letra sem tabela GDEF regressam a "nenhum glifo é ignorado" para que a saída permaneça byte-identical para chamadores que usam tipos de letra sem GDEF
TTF subsetter closure (MarkUnicodeGlyphUsed) O subsetter TTF v2.84.0 do HotPDF deriva o conjunto de glifos usados de FUnicodeUsedCps através do cmap. Os glifos substitutos GSUB (alternates estilísticos, ligaduras, variantes contextuais - tudo o que as 7 APIs de consulta acima devolvem) normalmente não têm qualquer codepoint a alcançá-los via cmap, pelo que antes eram invisíveis para o subsetter e o leitor consumidor renderizava .notdef no seu lugar
Depois de emitir qualquer GID devolvido por GetSingleSubstituteGlyph / GetMultipleSubstituteGlyphs / GetAlternateGlyph / ApplyLigatureSubstitution / ApplyContextualSubst / ApplyReverseChainedContextualSubst num fluxo de texto PDF, chame MarkUnicodeGlyphUsed(GID) uma vez por cada GID emitido para o incluir no subset incorporado. O auxiliar é idempotente, defensivo (GIDs fora do intervalo são descartados silenciosamente) e integra-se com a passagem de fecho de glifos compostos do v2.84.0: os chamadores só precisam de marcar o GID substituto de topo - os componentes compostos são puxados automaticamente
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'); Exemplo: if PDF.ApplyLigatureSubstitution(Run, 0, 'rlig', LigGID, ConsumedCount) then begin // emit LigGID + advance by ConsumedCount PDF.MarkUnicodeGlyphUsed(LigGID); end;
Scope and limitations O motor é uma superfície de consulta apenas de capacidades: responde a «what would GSUB do here», mas não executa um pipeline automático de formação (disposição ao nível Harfbuzz, reordenação consciente de agrupamentos para Indic, resolução BiDi, posicionamento GPOS, ancoragem de marcas). Os chamadores são responsáveis por conduzir o ciclo de varrimento, escolher qual o substituto / alternativa a emitir, chamar
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 Substituição única + Fase 1. v2.119.44 Múltipla + Alternativa (Fase 2). v2.119.45 Ligadura (Fase 3). v2.119.46 Extensão + GDEF + observância de LookupFlag (Fase 4). v2.119.47 Contextual + Contextual em cadeia + despachador SequenceLookupRecord (Fase 5). v2.119.48 Reverse Chained Contextual - matriz LookupType 1-8 encerrada (Fase 6). v2.119.49 API de selecção Script / LangSys (Fase 7). v2.119.50 Fecho de subsetter TTF via
See also: Arabic / Persian / Urdu Shaping, CFF / OpenType Font Subsetting Functions, THotPDF.EnableFontSubsetting |