|
Motor de sustitución OpenType GSUB Glyph substitution capability surface (v2.119.43 - v2.119.50)
|
Arabic Shaping CFF / OpenType Subsetting |
|
El motor OpenType GSUB (Glyph SUBstitution) dentro de HotPDF permite que los llamadores consulten, controlen e incrusten todo tipo de sustitución de glifos declarada por una fuente OpenType: ligaduras, alternativos estilísticos, variantes contextuales, formas de conformación Arabic / Indic, formas alternativas CJK, etc. Cada OpenType GSUB LookupType 1 a 8 está implementado y expuesto como superficie de consulta de capacidades; el llamador controla la emisión de texto y decide qué glifo sustituto escribir en el flujo de contenido de la 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);
Descripción El motor se activa después de que RegisterUnicodeTTF analiza una fuente y almacena en caché sus tablas GSUB / GDEF / cmap. Cada consulta de sustitución recorre la cadena ScriptList / LangSysList / FeatureList / LookupList de la fuente y despacha al manejador LookupType adecuado. Los 12 métodos anteriores constituyen toda la superficie pública; todo lo demás (recorrido cmap, análisis de ScriptList, búsqueda en tabla Coverage, resolución ClassDef, respeto de LookupFlag, desempaquetado de Extension wrapper y despacho anidado de SequenceLookupRecord) queda detrás de esa superficie
Contrato defensivo en toda la API: las fuentes sin tabla GSUB, los feature tags que no tienen 4 bytes, las features no anunciadas por el script / idioma seleccionado, los GID que ninguna subtabla cubre y los glifos de entrada ignorados por LookupFlag devuelven todos un no-op seguro (False / OutGID = InputGID / OutGIDs vacío / ConsumedCount = 1), de modo que los llamadores nunca ven excepciones en casos rutinarios de "no se aplica sustitución"
LookupType matrix LookupType 1 (Single Substitution): un glifo se asigna a un sustituto. Features canónicas: LookupType 2 (Multiple Substitution): un glifo se divide en una secuencia de glifos sustitutos. Uso canónico: LookupType 3 (Alternate Substitution): un glifo se asigna a uno de N alternativos. Features canónicas: LookupType 4 (Ligature Substitution) - N input glyphs fold into one ligature. Canonical features: LookupType 5 (Contextual Substitution) + LookupType 6 (Chained Contextual Substitution): coincide con una secuencia de glifos de entrada y despacha lookups anidados en posiciones específicas dentro de la coincidencia. Las tres variantes Format (1 secuencia literal, 2 secuencia ClassDef, 3 secuencia Coverage) están implementadas; el despachador SequenceLookupRecord vuelve a entrar en LookupList y maneja lookups anidados Single / Multiple / Alternate (primero) / Ligature con seguimiento activo de MatchPositions. Features canónicas: LookupType 7 (Extension Substitution): capa de indirección pura que la especificación OpenType define para fuentes cuya subtabla de sustitución queda fuera del alcance de 16 bits de LookupList. Todas las API públicas siguen de forma transparente la indirección Offset32 de 32 bits hasta la subtabla real LookupType 1 / 2 / 3 / 4 / 5 / 6 / 8. Esto desbloquea fuentes CJK / índicas pesadas (Noto Sans CJK, Noto Sans Devanagari) cuyo GSUB supera 64 KB. No hay API separada: el desempaquetado es 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 De forma predeterminada, el motor prefiere el script
Semántica strict-vs-fallback: un
LookupFlag honor and GDEF Cada consulta lee el LookupFlag de cada tabla Lookup (y el uint16 final opcional markFilteringSet cuando
TTF subsetter closure (MarkUnicodeGlyphUsed) El subsetter TTF de HotPDF v2.84.0 deriva su conjunto de glifos usados desde
Después de emitir cualquier GID devuelto por
Flujo de trabajo típico (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;
Flujo de trabajo típico (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;
Ámbito y limitaciones El motor es una superficie de consulta de capacidades: responde "qué haría GSUB aquí", pero no ejecuta una canalización automática de conformación (maquetación de clase Harfbuzz, reordenamiento Indic con conocimiento de clústeres, resolución BiDi, posicionamiento GPOS, adjunto de marcas). Los llamadores son responsables de controlar el bucle de exploración, elegir qué sustituto / alternativo emitir, llamar a MarkUnicodeGlyphUsed por cada GID sustituto emitido y aplicar cualquier posicionamiento GPOS / de marcas que requiera la fuente
El shaping árabe / persa / urdu del lado productor (ligadura obligatoria LAM-ALEF + Arabic Presentation Forms-A) está implementado como una canalización integrada separada que se ejecuta automáticamente durante la emisión de texto; consulte 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 + respeto de LookupFlag (Phase 4). v2.119.47 Contextual + Chained Contextual + despachador SequenceLookupRecord (Phase 5). v2.119.48 Reverse Chained Contextual: matriz LookupType 1-8 cerrada (Phase 6). v2.119.49 API de selección Script / LangSys (Phase 7). v2.119.50 cierre del subsetter TTF mediante
Véase también: Arabic / Persian / Urdu Shaping, Subconjunto de fuentes CFF / OpenType Functions, THotPDF.EnableFontSubsetting |