THotPDF.AssignSyntheticCodepointForGID / GetSyntheticCodepointForGID

THotPDF PUA synthetic codepoint allocator (v2.119.68)

 

GSUB エンジン  自動シェーピングパイプライン  アラビア語シェーピング

フォントの cmap を通じて到達可能な自然な Unicode コードポイントを持たない Openタイプ GSUB 置換 GID に対して、私用領域(Private Use Area: U+E000 - U+F8FF)の合成コードポイント(synthetic codepoints)を割り当ててクエリします。v2.119.43-66 の GSUB クエリおよび絞り込み API によって残された、プロデューサー側の GID レベルの出力ギャップを埋めます。

 

Delphi 構文:

function AssignSyntheticCodepointForGID(GID: Word; out SyntheticCP: Word): Boolean;

function GetSyntheticCodepointForGID(GID: Word): Word;

 

この API が存在する理由

v2.119.32-67 のプロデューサー側自動シェーピングパイプライン(アラビア語 / ラテン文字 / デーヴァナーガリー文字)では、GSUB エンジンから返される置換 GID が Unicode コードポイントを通じて到達可能である必要があります。既存の 16 進エンコードされたテキストパイプラインは GID ではなくコードポイントを出力し、コンシューマーリーダーは埋め込まれた /CIDToGIDMap を通じてコードポイントを GID に解決して戻します。フォントの cmap を通じて自然な Unicode コードポイントを持つ置換 GID(アラビア表示形、ラテン標準合字 FB00-FB06)の場合、既存のパイプラインは正常に機能します。

 

しかし、フォント内部の GID になるフォント固有の置換(ほとんどのデーヴァナーガリー文字のクラスター形状、フォントデザイナーが番号付きの GID としてのみ出荷する stylistic alternate、CJK 漢字異体字シーケンス(IVS)、対応する表示形を持たない discretionary ligature)は、フォントの cmap にコードポイントをまったく持っていません。v2.119.68 より前は、これらの GID はプロデューサー側の 16 進パイプラインを通じて到達できませんでしたが、v2.119.68 では、呼び出し元が任意の GID に対して私用領域に合成コードポイントを割り当てることができるようにすることで、そのギャップを埋めています。

 

AssignSyntheticCodepointForGID のセマンティクス

指定された GID に対して次に利用可能な PUA コードポイント(U+E000 から開始)を割り当て、既存のプロデューサー側 16 進パイプラインとコンシューマーリーダー解決チェーンが依存するすべてのキャッシュにその割り当てを反映(mirror)させます。

 

1. FUnicodeCpToGid[SyntheticCP] := GID - これにより、プロデューサー側の 16 進パイプラインはテキスト表示オペレーターに SyntheticCP を出力し、コンシューマーリーダーはレンダリング時に /CIDToGIDMap を通じて SyntheticCPGID に解決して戻します。

2. FAcroFormUnicodeAdvances[SyntheticCP] := em-fraction - これにより、AcroForm テキストフィールドコンテンツに合成コードポイントが現れたときに、v2.65 のワードラップ計算機能が正しい hmtx advance を見つけることができます。

3. FUnicodeSyntheticCpForGID[GID] := SyntheticCP - これは、繰り返し行われる AssignSyntheticCodepointForGID の呼び出しをべき等(idempotent)にするために GetSyntheticCodepointForGID によって使用される、GID ごとの逆引き参照テーブルです(同じ GID を使用した 2 回目の呼び出しでは、すでに割り当てられている SyntheticCP を返します)。

 

成功すると True を返し、SyntheticCP は割り当てられたコードポイントに設定されます。以下のいずれかの防御条件に該当する場合は False を返します(SyntheticCP は 0 のままになります)。フォントが登録されていない(RegisterUnicodeTTF が呼び出されたことがないか、状態をリセットするために空の引数で呼び出された)、無効な GID(ゼロまたは cmap のグリフ数を超えている)、PUA 範囲の枯渇(U+E000 から U+F8FF までの 6400 個のスロットすべてが割り当てられている)、エントリ時のキャッシュが初期化されていない。

 

GetSyntheticCodepointForGID のセマンティクス

既存の割り当てに対する純粋関数型のクエリ。AssignSyntheticCodepointForGID(GID, ...) が以前に呼び出されている場合は、GID に割り当てられた合成コードポイントを返します。それ以外の場合は 0 を返します(0 は有効な PUA コードポイントではないため、「割り当てなし」のセンチネルとしても機能します)。割り当ては行いません。AssignSyntheticCodepointForGID が実行される前に呼び出しても安全です。

 

アロケーター状態のライフサイクル

FUnicodeSyntheticCpForGID と、次に利用可能な PUA カーソル(FUnicode次へSyntheticCp)は、最初の AssignSyntheticCodepointForGID 呼び出し時に遅延割り当て(lazy-allocated)されます。カーソルは 0(未初期化)から始まり、最初の割り当て時に $E000 に繰り上げられます。その後の割り当てでは $E001$E002、...、$F8FF の順に進みます。どちらのフィールドも、フォントごとのサブセット状態の残りの部分とともに、RegisterUnicodeTTF('', nil) のたびに空 / 0 にリセットされるため、複数のドキュメントにわたって THotPDF インスタンスを再利用する呼び出し元は、各ドキュメントを新しい PUA カーソルで開始します。

 

典型的なワークフロー(デーヴァナーガリー文字のクラスター形状)

 

PDF.RegisterUnicodeTTF('NotoDeva', 'NotoSansDevanagari-Regular.ttf');

PDF.ShapingFeatures := [sfIndicShaping];

PDF.SetGSUBScript('deva');

 

// GSUB エンジンを通じてフォント内部のクラスター GID を取得します

ClusterGID := PDF.GetSingleSubstituteGlyph(BaseGID, 'nukt');

if ClusterGID <> BaseGID then

begin

  // Check if cmap reaches the substitute - usually no for Indic

  // clusters, since cluster GIDs are font-internal

  // Allocate a synthetic codepoint that the producer-side

  // hex pipeline can emit

  if PDF.AssignSyntheticCodepointForGID(ClusterGID, SyntheticCP) then

  begin

    // SyntheticCP is now in the U+E000-F8FF range; emit it

    // through UnicodeTextOut just like a normal codepoint

    PDF.CurrentPage.UnicodeTextOut(X, Y, 0, UnicodeChar(SyntheticCP));

    PDF.MarkUnicodeGlyphUsed(ClusterGID);

  end;

end;

 

べき等性(Idempotency)の例

 

PDF.AssignSyntheticCodepointForGID(150, CP1);  // CP1 = $E000

PDF.AssignSyntheticCodepointForGID(151, CP2);  // CP2 = $E001

PDF.AssignSyntheticCodepointForGID(150, CP3);  // CP3 = $E000 (idempotent)

CP4 := PDF.GetSyntheticCodepointForGID(150);  // CP4 = $E000

CP5 := PDF.GetSyntheticCodepointForGID(999);  // CP5 = 0 (no assignment)

 

コンシューマーリーダーの動作

コンシューマーリーダーはテキスト表示オペレーターで PUA コードポイントを確認し、ドキュメントに埋め込まれた /CIDToGIDMap を通じてターゲットの GID に解決し、埋め込まれたフォントプログラムを使用してその GID をレンダリングします。リーダーの観点からは、cmap が GID にルーティングする「自然な」Unicode コードポイントと、/CIDToGIDMapGID にルーティングする PUA 合成コードポイントの間に違いはありません。どちらも同じレンダリングされたグリフを生成します。

 

コピー / 貼り付けの動作: ToUnicode CMap が identity mapping として宣言している場合、PUA コードポイントはコピー / 貼り付けでそのまま往復します。代わりに元の Unicode 文字 (置換を生成した入力 run) を往復させたい呼び出し元は、RegisterToUnicodeReverseMapping で逆方向マッピングを登録するか、BeginTaggedContent を使って ActualText marked-content sequence プロパティを作成し、その括弧付きコンテンツ内に合成コードポイントを出力できます。HotPDF は、補助平面 Unicode 文字を含む RegisterUnicodeTTF ベースの AcroForm appearance stream に対して、同じ内部 CID パターンを自動的に使用します

 

フェーズ 8 ロードマップの終了

v2.119.68 / フェーズ 8c.6 により、フェーズ 8 の GSUB エンジンロードマップは終了します。すべての Lookupタイプ 1-8 クエリ API (フェーズ 1-6)、Script / LangSys 選択 API (フェーズ 7)、TTF サブセッタークロージャエントリポイント (フェーズ 9)、静的ポストパス(post-pass)合字フォールディング (v2.119.32 / 58 / 60 / 62)、オプトインの自動パイプライン (v2.119.59)、アラビア語 rlig + ラテン文字 liga / clig + rclt 自動出力 (フェーズ 8b / 8c.2 / 8b / GSUB 'rclt')、ToUnicode 逆マッピング (v2.119.61 / 62 / 65)、advance クエリ (v2.119.64)、デーヴァナーガリー文字などインド系の並べ替え(reorder)プレパス (v2.119.67)、そして今回の PUA 合成コードポイント GID レベル出力 (v2.119.68) はすべて、Openタイプ フォントが生成できるあらゆる種類の置換グリフを処理する、単一のプロデューサー側シェーピングサーフェスに統合されています。

 

See also: Openタイプ GSUB 置換エンジン, 自動シェーピングパイプライン(フェーズ 8), アラビア語 / ペルシア語 / ウルドゥー語シェーピングサポート, シリア文字 / モンゴル文字 / デーヴァナーガリー文字のシェーピング, THotPDF.BeginTaggedContent