インクリメンタルフォント転送

W3C 勧告候補草案,

この文書の詳細情報
このバージョン:
https://www.w3.org/TR/2026/CRD-IFT-20261013/
公開済みの最新バージョン:
https://www.w3.org/TR/IFT/
編集者草案:
https://w3c.github.io/IFT/Overview.html
履歴:
https://www.w3.org/standards/history/IFT/
フィードバック:
public-webfonts-wg@w3.org 件名を「[IFT] … メッセージの件名 …」とする(アーカイブ)
GitHub
実装報告書:
https://wpt.fyi/results/IFT
編集者:
Chris Lilley(W3C)
(Google Inc.)
(Adobe Inc.)

概要

この仕様は、フォントを段階的に転送する方法を定義する。 サーバーからクライアントへの転送において、クライアントはフォントのうち 実際に必要な部分のみを読み込み、データ転送量を大幅に削減する。同じフォントに対して 複数回の段階的な追加が可能であり、例えばユーザーエージェントは、 ユーザーが複数のページを閲覧するにつれてフォントを更新できる。インクリメンタル転送は、 レイアウト規則(カーニング、合字など)を損なわないため、unicode-range より優れており、 ラテン文字に対する細粒度の増分や、 インド系文字やアラビア文字のような複雑な文字体系にも効率的に対応できる。

この文書の位置付け

この節では、公開時点におけるこの文書の位置付けを説明する。 現在の W3C 公開文書の一覧と、この技術報告書の最新版は、 W3C 標準および草案の索引で確認できる。

この文書は、 Web Fonts Working Group によって、勧告候補 草案として、勧告 策定プロセスに従って公開された。

この文書は草案であり、いつでも他の文書によって更新、置換、または廃止される可能性がある。 進行中の作業として以外の形でこの文書を引用することは適切ではない。

この文書には、2025年8月18日付 W3C プロセス文書が適用される。

現在、実装報告書は存在しない。テストスイートは開発中である。

この文書は、W3C 特許ポリシーに基づいて活動するグループによって作成された。W3C は、特許 開示の公開一覧を維持しており、グループの成果物に関連して行われた開示を掲載している。そのページには、 特許を開示するための手順も記載されている。自身が実際に知っている特許について、 その特許に必須請求項が含まれると考える者は、 W3C 特許ポリシー第6節に従って、その情報を開示しなければならない。

勧告候補として公開されることは、W3C およびその会員による承認を意味しない。勧告候補 草案には、作業部会が前回の勧告候補からの変更のうち、 次回の勧告候補スナップショットに含める予定の変更が組み込まれている。

1. はじめに

この節は非規範的である。

インクリメンタルフォント転送(IFT)は、ウェブ上のリモートフォント(または「ウェブフォント」)の 読み込み遅延を改善する技術である。この技術がなければ、ブラウザーはフォントを使用して 文字を描画する前に、そのフォントのすべてのバイトをダウンロードする必要がある。IFT により、ブラウザーは ファイルの一部のバイトのみをダウンロードでき、 ブラウザーがフォントを必要とすると認識してから、 必要なテキストをそのフォントで描画できるまでの体感的な遅延を短縮できる。従来のフォントサブセット化手法とは異なり、インクリメンタル フォント転送は、 セグメント間のレイアウト規則の符号化を維持する(プログレッシブフォント拡充:評価報告書 § fail-subset)。

WebFonts の普及状況には偏りがある。この仕様により、現在は 低速なネットワーク、非常に大きなフォント、または複雑なサブセット化の要件によって利用が妨げられている環境でも、WebFonts を利用できるようになる。例えば、 WOFF 2 [WOFF2] を使用しても、CJK 言語用のフォントは実用的なサイズを超える場合がある。

1.1. 技術的な動機:評価報告書

この仕様の策定につながった調査については、プログレッシブフォント拡充:評価報告書 [PFE-report] を 参照されたい。

1.2. 概要

インクリメンタルフォントとは、 通常の OpenType フォントを、インクリメンタル機能を含むように再構成したものであり、 その機能は、一部には追加された2つのテーブルによって実現される。これらの 新しいテーブルを使用すると、パッチを読み込んで適用することで、 フォントを拡張できる (例えば、より多くのコードポイントに対応させることができる)。

IFT 技術は、主に4つの要素から構成される。

大まかに言えば、インクリメンタル フォントは次のように使用される。

  1. クライアントは初期フォントファイルをダウンロードする。このファイルには、完全な フォントのデータから抽出された初期サブセットと、 フォントを拡張するために使用できる埋め込みデータとして記述されたパッチの集合が 含まれる。

  2. 描画するコンテンツに基づいて、クライアントはパッチを選択、ダウンロード、 適用し、フォントを拡張して 追加の文字、レイアウト機能、および/またはバリエーション空間に対応させる。この手順は、 新しいコンテンツが現れるたびに 繰り返される。

1.3. インクリメンタルフォントの作成

インクリメンタルフォントを作成する最も一般的な方法は、既存のフォントを変換して この仕様で定義されるインクリメンタル 符号化を使用することになると予想される。大まかに言えば、既存のフォントをインクリメンタル形式に変換する 手順は次のようになる。

  1. 初期サブセットの内容を選択する。これはクライアントが読み込む 初期フォントファイルに含まれ、 通常は常に必要になると予想される元のフォントのデータで構成される。

  2. パッチの種類を選択する。パッチの種類によって特性が異なるため、 用途に応じて異なる パッチの種類、または場合によっては2種類の組み合わせが必要になることがある。

  3. フォントの分割方法を選択する。個々のセグメントは、クライアントによってパッチを 使用して基本サブセットに追加される。適切な 分割方法を選択することは、効率的な符号化を作成するうえで最も重要な要素の1つである。

  4. これらの選択に基づいてパッチの集合を生成する。各パッチは特定の セグメントのデータを、 初期フォントファイルまたは以前のパッチを基準として追加する。

  5. 初期サブセットとパッチマッピングを含む初期フォントファイルを生成する。このマッピングには、 利用可能なすべてのパッチファイル、それらが配置されている URL、および 各パッチがフォントに追加するデータに関する情報が列挙される。

注記:これはインクリメンタルフォントの 作成方法を大幅に簡略化した説明である。符号化の生成と 符号化に関する要件についての詳細な説明は、§ 7 符号化を参照されたい。

1.4. 性能に関する考慮事項とインクリメンタルフォント転送の利用

インクリメンタル転送の使用が常に有益であるとは限らず、フォント、 ネットワーク、および描画するコンテンツの特性によって異なる。この節では、 インクリメンタル転送を使用すべき状況を判断するための非規範的な指針を示す。

インクリメンタルフォントでは、複数のパッチの読み込みが並列に開始されることが一般的である。そのため、 性能を最大化するには、 インクリメンタルフォントを配信する際に、マルチプレクシングに対応した HTTP サーバー(例えば [rfc9113] または [rfc9114]) を使用することが推奨される。

フォントを段階的に読み込むことには、フォント全体を読み込む場合との間に基本的な性能上のトレードオフがある。 単純に言えば、インクリメンタル転送では転送するバイト数を減らせる一方で、 ネットワークリクエストの総数が増加したり、リクエスト処理の 遅延が増加したりする可能性がある。一般に、インクリメンタルフォント転送は、 転送するバイト数の削減による遅延の短縮が、インクリメンタル転送方式によって生じる追加の遅延を上回る場合に有益となる。

最初に考慮すべき要素は、描画するコンテンツの言語である。評価報告書には、 3つの言語カテゴリーにわたってインクリメンタルフォント転送をシミュレーションした 結果が含まれている (プログレッシブフォント拡充:評価報告書 § langtype)。言語カテゴリーごとの インクリメンタルフォント転送の予想される性能については、その結論プログレッシブフォント拡充:評価報告書 § conclusionsを参照されたい。

次に、フォントのどの程度の部分が必要になると予想されるかを考慮する。フォントの大部分が コンテンツの描画に必要になると予想される場合、インクリメンタルフォント転送は有益でない可能性が高い。しかし、 多くの場合、フォントの一部のみが必要になると予想される。例えば、次のような場合である。

インクリメンタル転送の代替手法として、フォントを個別のサブセット(通常は文字体系ごと)に 分割し、@font-face の unicode-range 機能を使用して必要なサブセットのみを読み込む方法がある。しかし、 異なるサブセットの文字間にレイアウト規則が存在する場合、一部のコンテンツの描画が 変化する可能性がある(プログレッシブフォント 拡充:評価報告書 § fail-subset)。インクリメンタルフォント転送では、 元のフォントとそのすべてのレイアウト規則を包含できるため、この問題は発生しない。

1.4.1. ネットワークリクエスト数の削減

前節で説明したように、インクリメンタルフォント転送の最も基本的な実装では、 従来のフォント読み込みと比較してリクエストの総数が増える傾向がある。各拡張には 通常少なくとも1回の往復時間が必要となるため、リクエストが多すぎると性能に 悪影響を及ぼす可能性がある。 利用可能なパッチの種類と、 パッチマッピングで提供される情報量によっては、クライアントは 現在は必要でないものの、 将来必要になると予想されるコードポイントのパッチを先行してリクエストすることがある。実装がこの機能を 適切に使用することで、リクエストの総数を削減できる。評価報告書では、 基本的な文字出現頻度に基づくコードポイント予測 方式の性能を検証し、全体的な性能が改善されることを確認した。

2. オプトインの仕組み

ウェブページは、CSS のフォント技術キーワード (CSS Fonts 4 § 11.1 フォント技術)を ''@font-face'' ブロック内で使用することにより、フォントのインクリメンタル転送を オプトインで選択できる。キーワード incrementalは、参照先のフォントに IFT データが含まれており、 インクリメンタルフォント転送をサポートするユーザーエージェントによってのみ読み込まれるべきであることを示す。

@font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf") tech(incremental);
}
@font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf") tech(incremental);
    unicode-range: U+0000-00FF;
}

2番目の例に示すように、unicode-rangeは IFT フォントと組み合わせて 使用できる。 Unicode 範囲は、完全に拡張されたフォントが対応する範囲と一致するように設定するべきである。これにより、クライアントは 必要なコードポイントのいずれにも対応していないフォントについて、 IFT フォントの読み込みを試みずに済む。

別の方法として、CSS supports の仕組みを使用し、フォント技術に基づいて 選択することもできる。

@when font-tech(incremental) {
  @font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont-Incremental.otf");
  }
}
@else {
  @font-face {
    font-family: "MyCoolWebFont";
    src: url("MyCoolWebFont.otf");
  }
}

注記:個々の@font-faceブロックは、 IFT をオプトインしても、しなくてもよい。これは、 ウェブページでフォントがさまざまな方法で使用されるためである。制作者は、どのフォントに この技術を使用し、どのフォントには使用しないかを制御できる。

注記:IFT 技術キーワードは、 他のフォント技術指定子と組み合わせて使用し、 フォント機能を選択できる。例えば、@font-faceには2つの URL を含めることができ、一方に tech(incremental, color-COLRv1)を、もう一方に tech(incremental, color-COLRv0)を指定できる。

2.1. オフラインでの利用

場合によっては、ユーザーエージェントがウェブページをオフラインで使用するために保存することがある。保存されたページは、 ネットワーク接続がない状態で閲覧される可能性があり、 そのためインクリメンタルフォントが参照する追加のパッチをリクエストすることはできない。 コンテンツが変更された場合(例えば JavaScript の実行による変更)、インクリメンタルフォントを 拡張できなくなるため、ページ保存機構はインクリメンタルフォントを フォントサブセットを完全に拡張する操作を呼び出して完全に拡張し、 インクリメンタルフォントへの参照を、完全に拡張されたフォントへの参照に置き換えるべきである。

3. 定義

3.1. フォントサブセット

フォントサブセットとは、 フォントファイル [iso14496-22]を変更したもので、 元のフォントが対応する次の要素の 一部を描画するために必要なデータのみを含む。

適切に構築されたフォントサブセットを使用して、サブセットに含まれる コードポイント、 レイアウト 機能、またはデザインバリエーション 空間の任意の組み合わせでテキストを描画すると、 元のフォントとまったく同じように描画される。これには、レンダラーが元のフォントから使用することを選択できる 任意のオプションのタイポグラフィ 機能(ヒンティング命令など)を使用した描画も含まれる。デザイン バリエーション空間は、 ユーザー軸スケールを使用して指定される(OpenType 仕様 § otvaroverview#coordinate-scales-and-normalization)。

フォントサブセット 定義は、 フォント サブセットが対応する最小限のデータ(コードポイント、レイアウト機能、 バリエーション軸空間)を記述する。

注記:便宜上、この文書の残りの部分では、 [open-type]仕様へのリンクを使用する。これは [iso14496-22]の複製である。

3.2. フォントパッチ

フォントパッチとは、 IFT 符号化されたフォントに適用する変更を符号化したファイルである。パッチは、 既存のフォントサブセットを拡張し、 対応範囲を広げるために使用される。

パッチ形式とは、 フォントサブセットを基準に適用する変更の指定された符号化形式である。 その形式に従って符号化された変更の集合がフォントパッチである。各パッチ形式には、対応する パッチ 適用アルゴリズムがあり、 フォントサブセットと、フォントパッチを、パッチ形式で符号化された入力として受け取り、 拡張された フォントサブセットを出力する。

3.3. パッチマップ

パッチマップとは、 OpenType テーブルであり、 フォントサブセット定義から、 パッチを提供する URL へのマッピングの集合を符号化する。これらのパッチは、 インクリメンタル フォントを拡張する。パッチマップテーブルには、 パッチマップ エントリーの一覧が符号化され、 各エントリーはキーと値を持つ。エントリーのキーは、そのエントリーの対応範囲を定義し、 どのサブセット 定義が一致するかに関する情報を示す。値は、 エントリーが 一致したときに適用すべきパッチに関する情報を指定する。パッチマップ エントリーの概要は次のとおりである。

キー 値
  • フォントサブセット定義:基本となる 対応範囲を定義する。

  • 0個以上の子パッチマップエントリーへの参照:
    これらの子エントリーは、対応範囲を拡張するために使用される。

  • 子エントリーの一致モード。論理積または論理和のいずれかを指定できる。

パッチマップの形式についての詳細は、§ 5 フォント 形式の拡張を参照されたい。

3.4. データ型の説明

この仕様の以降の部分における符号化されたデータ構造は、 OpenType 仕様 § otff#data-typesで定義されるデータ型を使用して説明される。OpenType の他の部分と同様に、 すべてのフィールドは「ビッグエンディアン」のバイト順序を使用する。

4. フォントサブセットの拡張

この節では、クライアントがインクリメンタルなフォントサブセットを拡張して、追加の コードポイント、レイアウト機能、および/またはデザイン空間に対応させるために使用するアルゴリズムを定義する。このアルゴリズムは反復的であり、以下を繰り返す。

この処理は、関連するパッチがなくなるまで繰り返される。パッチの適用によって フォントファイルに埋め込まれたパッチマッピングが変更される可能性があるため、 各反復では、フォントサブセットの現在のバージョンに含まれるパッチマップを再解析し、 残っているパッチを確認する。したがって、各反復においてフォントサブセットが利用可能なパッチに関する 唯一の信頼できる情報源となり、 拡張処理の現在の状態を完全に内包する。

4.1. パッチの無効化

フォントサブセットに埋め込まれたパッチマッピングには、各パッチの無効化モードが符号化されている。 パッチの無効化モードは、 そのパッチを適用した後に、どの他のパッチが無効になるかを示す。この無効化 モードは、 拡張アルゴリズムが互換性のあるパッチを判断するために使用され、選択順序にも影響する。パッチ 適用時の有効性は、 § 5.3 パッチマップ テーブルの互換性 ID によって保証される。すべてのパッチには互換性 ID が符号化されており、 その ID は、パッチを列挙する§ 5.3 パッチマップテーブルの 互換性 ID と一致する必要がある。

無効化モードには次の3種類がある。

特定のパッチの無効化モードは、その形式番号に符号化されており、§ 6.1 形式の概要で確認できる。

4.2. 既定のレイアウト機能

ほとんどのテキストシェーピングエンジンには、常に有効であり、 そのため段階的に読み込まれるフォントで常に必要となるレイアウト機能の 集合がある。付録 A:既定の機能タグには、 執筆時点で一般的なシェーピングエンジンの実装において既定で必要とされることが知られている機能の 一覧をまとめている。クライアントが拡張アルゴリズムへの入力として フォントサブセット定義を構成する際には、 通常、付録 A:既定の機能 タグに記載されたすべての機能をサブセット定義に含めるべきである。ただし、 特定のシェーピングエンジンが付録 A:既定の機能タグに記載された一部の機能を 使用しないことをクライアントが把握している場合、それらの未使用機能をサブセット定義から除外してもよい。

4.3. インクリメンタル フォント拡張アルゴリズム

次のアルゴリズムは、クライアントがインクリメンタルなフォントサブセットを拡張し、追加の コードポイント、レイアウト機能、および/またはデザイン空間に対応させるために使用される。このアルゴリズムは、 パッチを1つずつ段階的に選択してフォントに適用し、 必要に応じて読み込む。ネットワークの往復回数を最小限に抑えるための重要な最適化として、 最終的に必要になるすべてのパッチの読み込みを 開始できるようにしている。これには次の2つの形態がある。

インクリメンタルフォントサブセットを拡張する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. extended font subsetをfont subsetに設定する。

  2. extended font subsetから 'IFT ' および 'IFTX'(存在する場合)のマッピングテーブルを 読み込む。両方のテーブルは § 5.3 パッチマップテーブルの形式で構成されている。それらが § 5.3 パッチマップテーブルの要件に従って有効であることを確認する。 いずれかのテーブルが無効な場合は、エラーを 処理するを呼び出す。extended font subsetに 'IFT ' テーブルがない場合、 それはインクリメンタル フォントではなく拡張できないため、extended font subsetを返す。

  3. 'IFT ' の互換性 ID が 'IFTX' の互換性 ID と等しい場合、これはエラーであるため、 エラーを処理するを呼び出す。

  4. 'IFT ' および 'IFTX'(存在する場合)の各テーブルについて、 パッチマップを解釈するを呼び出し、 テーブルをエントリーの一覧に変換する。返されたエントリーの一覧を1つの一覧に連結し、 entry listとする。

  5. entry list内の各entryについて、エントリーの交差を確認するを、 entryと target subset definitionを入力として呼び出す。false が返された場合、entryを entry listから削除する。さらに、 このアルゴリズムの実行中に以前に読み込まれて適用されたパッチ URL 文字列を持つ entry list内のエントリーも削除する。

  6. entry listが空の場合、拡張処理は完了しているため、extended font subsetを返す。

  7. entry listのエントリーを、それぞれのパッチ形式の無効化モードに基づいて 3つの一覧に分類する:full invalidation entry list、partial invalidation entry list、 およびno invalidation entry list。

  8. 次の手順でentryを1つ選択する。

    • full invalidation entry listが空でない場合、 そこに含まれるエントリーから正確に1つを選択する。 § 4.4 無効化するパッチの選択の基準に従って、 その1つのエントリーを選択する。

    • そうでなく、partial invalidation entry listが空でない場合は、 そこに含まれるエントリーから正確に1つを選択する。 § 4.4 無効化する パッチの選択の基準に従って、その1つのエントリーを選択する。

    • それ以外の場合、no invalidation entry list内で、 パッチマップに最初に列挙されているエントリー (entries配列で最初に現れるエントリー)を選択する。IFT および IFTX の両方のテーブルのエントリーが候補となる場合、IFT 内のすべてのエントリーは IFTX 内のエントリーより前にあるとみなされる。

  9. パッチファイルを読み込むを呼び出して、 patch fileの読み込みを開始する(以前に開始されていない場合)。 initial font URLを初期フォント URL とし、 entry内の最初のパッチ URL 文字列をパッチ URL 文字列として使用する。 entryに他の URL 文字列が存在する場合は、 同じ手順でそれらの読み込みも開始する。これらは このアルゴリズムの将来の反復で使用される可能性がある。 さらに、クライアントは、entryによって 無効化されないentry list内のエントリーについても、 同じ手順で読み込みを任意に開始してよい。クライアントが1回の実行中に 読み込んで適用できるパッチの総数は、次のように制限される。

    これらは、このアルゴリズムの1回の呼び出し中に読み込んで適用できる上限である。 いずれかの上限を超えた場合はエラーとなるため、 エラーを処理するを呼び出す。

  10. patch fileの読み込みが完了したら、entry内のパッチ形式に 対応する適切な適用アルゴリズムを § 6 フォントパッチ形式から選び、 entryのパッチ URL 文字列および互換性 ID を使用して、 patch fileをextended font subsetに適用する。 patch fileの読み込みでエラーが発生した場合は、 エラーを処理するに従って処理する。

  11. 手順2に戻る。

注記:手順9では、クライアントは現在 選択されているエントリーによって無効化されないパッチの読み込みを 並列に開始してもよい。そのようなパッチは無効化されないため、 ほぼ確実に後続の反復で必要となり、並列に読み込むことで ネットワークの往復を省略でき、性能が大幅に向上する。この方法で読み込みを開始する場合、 リクエストの開始順序は 手順8で指定された順序に従う必要がある。

注記:残っている交差するエントリーが 無効化なしのエントリーだけである場合、手順5の交差確認を 後続の反復で繰り返す必要はない(無効化なしのパッチは、 適用時に自身のエントリーを削除する以外、 利用可能なパッチの一覧を変更しないためである)。さらに最適化として、クライアントは 残りの交差する無効化なしのエントリーに対するパッチ適用を、 単一のバッチ処理として実行することを検討してもよい。グリフキー方式のパッチの性質上、 複数のパッチを順番に適用した最終結果を、 1回の処理で構築することは容易である。この方法により、個々のパッチごとに glyf/loca/CFF/CFF2 テーブルを繰り返し再構築する必要がなくなり、 必要な計算量の総量を大幅に削減できる。

拡張アルゴリズムの実行例については、付録 B:拡張アルゴリズムの実行例を参照されたい。

エントリーの交差を確認する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. subset definition内の各集合(コードポイント、機能タグ、 デザイン空間)について、mapping entryのサブセット定義に含まれる 対応する集合と交差するかを確認する。集合は、 次の条件で交差する。

    サブセット定義の集合が空である サブセット定義の集合が空でない
    マッピングエントリーの集合が空である true true
    マッピングエントリーの集合が空でない false 2つの集合が交差する場合は true

    デザイン空間の集合の交差を確認する際には、 少なくとも1組の交差するセグメント (タグが等しく、範囲が交差する)が存在する場合、それらは交差する。

  2. 手順1で確認した集合のうち1つ以上が交差しなかった場合、 intersectsとして false を返す。

  3. mapping entryに子エントリーがない場合、 intersectsとして true を返す。

  4. mapping entryで参照される各子エントリーについて、エントリーの交差を確認するを subset definitionを入力として 呼び出す。子エントリーの一致モードが論理積の場合、 すべての呼び出しが true を返した場合に限り、intersectsとして true を返す。 それ以外の場合は、少なくとも1つの呼び出しが true を返した場合に限り true を返す。

次の表はパッチマッピングを表し、 さまざまなエントリーに対する交差確認の期待される結果を示す。これらの例では、 集合(コードポイント、機能タグ、デザイン空間、子エントリー)が指定されていない場合、 その集合は空集合であるとみなされる。

インデックス マッピングエントリー サブセット定義 交差するか?
0
subset definition {
  code points: {1, 2, 3},
},
match mode: disjunctive,
code points: {2},
true
1
subset definition {
  code points: {4, 5, 6},
},
match mode: disjunctive,
code points: {2},
false
2
subset definition {
  code points: {1, 2, 3},
},
match mode: disjunctive,
code points: {2},
feature tags: {smcp},
true
3
subset definition: {
  code points: {1, 2, 3},
},
match mode: disjunctive,
feature tags: {smcp},
false
4
subset definition: {
  code points: {1, 2, 3},
},
child entry indices: {1},
match mode: disjunctive,
code points: {5},
false
5
subset definition: {
},
child entry indices: {0, 1},
match mode: conjunctive,
code points: {2},
false
6
subset definition: {
},
child entry indices: {0, 1},
match mode: conjunctive,
code points: {2, 6},
true

パッチ ファイルを読み込む

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. URL 標準 § url-parsingを使用して、 patch URL stringをURL レコードに解析する。 initial font URLを基底 URLとし、符号化方式は UTF-8 とする。結果を target URLに格納する。URL の解析に失敗した場合は、エラーを返す。

  2. 実装するユーザーエージェントのフェッチ機能を使用して、 target URLの内容を取得する。ウェブブラウザーの場合は、 [FETCH]を使用するべきである。 [FETCH]を使用する場合、 リクエストを次のように構成する。

    リクエストをフェッチする。このとき、 processResponseConsumeBodyには、この アルゴリズムの手順3を指定する。

    [FETCH]を 使用しない実装では、利用可能なフェッチ機能を使用して target URLに対するリクエストを行う。 同等の概念が存在する場合は、上記の[FETCH]に基づく 設定を適用する。そのフェッチの結果を使用して手順3に進む。

  3. processResponseConsumeBodyには、レスポンスと、 null、失敗、またはバイト列のいずれかが渡される。バイト列を受け取った場合は、 そのバイト列をpatch fileとして返す。null を受け取った場合は、空のバイト配列を patch fileとして返す。 それ以外の場合は、エラーを返す。

注記:フェッチ設定は、CSS の フォント読み込みで使用される設定(CSS Fonts 4 § 4.8.2 フォントのフェッチ要件)と一致させることを目的としているが、いくつかの相違点がある。 第一に、リファラーは初期フォントの URL に設定される。第二に、URL の解決では スタイルシートではなく初期フォントが基準として使用される。

エラーを 処理する

フォントサブセットの拡張処理がエラーで失敗した場合、フォント内の一部のデータが 完全に読み込まれていない可能性があり、 その結果、欠落したデータに依存するコンテンツを描画すると、正しく描画されない可能性がある。クライアントは そのフォントの使用を継続することを選択してもよいが、 § 4.6 フォントが描画できるコンテンツの判定に従って、 完全に読み込まれたコードポイント、機能、およびデザイン空間の描画にのみ使用するべきである。 その他のすべてのコンテンツの描画では、通常のクライアントのフォールバック処理に従い、 別のフォントにフォールバックするべきである。

パッチファイルを読み込むの実行中にエラーが発生した場合、 クライアントはフォントサブセットの拡張を引き続き試みてもよい。 インクリメンタルフォントサブセットを拡張するの 手順8では、各無効化グループ内で、読み込みに失敗したパッチを選択対象から除外する。 無効化グループが空でなく、そのグループから選択する段階にあるにもかかわらず、 失敗したパッチしか含まれていない場合、 拡張は失敗しており、継続できない。

その他のすべてのエラーの場合、クライアントは フォントサブセットをさらに拡張しようとしてはならない。

4.4. 無効化するパッチの選択

インクリメンタルフォントサブセットを拡張する アルゴリズムの実行中、候補エントリーの一覧から単一の無効化(完全または部分) パッチエントリーを選択する必要がある場合がある。使用する選択基準は、拡張を実行するために必要な 往復回数の総数に直接影響する。 往復にはコストがかかるため、性能を最大化するには、 必要な往復回数の総数を最小限に抑えるようにパッチを選択するべきである。

次の選択基準は、 往復回数を最小限に抑えるものであり、クライアントは、 インクリメンタルフォント サブセットを拡張するの手順8で単一の部分無効化または完全無効化パッチを選択する際に、 この基準を使用しなければならない。

  1. 1つ以上の候補エントリーに関連付けられたパッチファイルが、以前に インクリメンタルフォント サブセットを拡張するの手順9によって読み込まれている場合、 以降の手順では、パッチファイルがすでに読み込まれているか、 現在読み込み中の候補エントリーのみを考慮する。それ以外の場合は、すべての 候補エントリーを考慮する。

  2. 各候補エントリーについて、そのエントリーのサブセット 定義と、参照される子エントリーのグラフを通じて到達可能なすべての子エントリーのサブセット定義との 和集合を求め、全体のサブセット定義を計算する。

  3. 各候補エントリーについて、全体のサブセット定義と 対象サブセット定義との集合の共通部分を計算する。

  4. 手順2で求めた共通部分が、他のどの共通部分の真部分集合にもならないエントリーを見つける。

  5. 手順3で見つけたエントリーと同じパッチマップにあり、共通部分が同じである追加のエントリーを探す。 このエントリー集合 (手順3で選択したものを含む)から、パッチマップに最初に列挙されているエントリー (entries配列で最初に現れるエントリー)を最終的に選択する。

注記:手順3の基準を満たすエントリーを 高速かつ効率的に見つける方法は、コードポイント集合の共通部分の大きさ、 次に機能タグ集合の共通部分の大きさ、最後にデザイン空間の 共通部分の大きさの順に、エントリーを降順に並べ替えることである。この並べ替えで最初のエントリーは、 他のどのエントリーの真部分集合にもならないことが保証される。真上位集合が存在すれば、 少なくとも1つ以上の要素を余分に含む必要があるためである。この方法には、 クライアントが現在要求しているデータを最も多く追加するパッチを 選択できるという利点もある。

4.5. 対象サブセット定義

インクリメンタルフォントサブセットを拡張する アルゴリズムは、クライアントが描画したいコンテンツに基づく対象サブセット定義を 入力として受け取る。クライアントは、コンテンツ全体に対して単一のサブセット定義を構成し、 拡張アルゴリズムを 1回実行することを選択してもよい。あるいは、コンテンツをより小さな範囲に分割し、各範囲の サブセット定義を構成して、 それぞれの小さなサブセット定義に対して拡張アルゴリズムを実行してもよい。いずれの方法でも、 次の条件を満たす限り、最終的にはコンテンツ全体を 同等に描画するフォントが生成される。

4.6. フォントが描画できるコンテンツの判定

インクリメンタルフォント(初期フォントでも部分的に拡張されたフォントでも)が与えられた場合、クライアントは そのフォントが現在の状態で どのコンテンツを描画できるかを知りたい場合がある。これは、クライアントがテキストの どの部分にフォールバックフォントを使用するかを 判断する際に特に重要である。

フォールバック処理中、クライアントは通常、フォントのcmapテーブルを確認し、 どのコードポイントに対応しているかを判断する。しかし、IFT フォントでは、§ 6.3 グリフキー方式のパッチの仕組みにより、 cmapテーブルに、 対応するグリフデータがまだ読み込まれていないコードポイントの マッピングが含まれる場合がある。そのため、クライアントはコードポイントの存在を判断する際に cmapテーブルだけに依存するべきではない。 代わりに、次の手順を使用して、インクリメンタルフォントがコンテンツの どの部分を描画できるかを確認できる。

クライアントは、シェーピング単位よりも細かい粒度でフォントが描画できる内容を知りたい場合もある。 次の擬似コードは、 上記の確認に失敗したシェーピング単位を、インクリメンタルフォントを使用して 描画できる範囲に分割する 方法の一例を示す。

# shaping_unit 内で ift_font が対応し、安全に描画できる範囲の
# リストを [start, end](両端を含む)の形式で返す。
#
# shaping_unit は配列であり、各要素にはコードポイントと、それに関連付けられた
# レイアウト機能のリスト、およびそのコードポイントの描画に使用するデザイン空間上の点が含まれる。
def supported_spans(shaping_unit, ift_font):
  current_start = current_end = current_subset_def = None
  supported_spans = []

  i = 0
  while i < shaping_unit.length():
    if current_subset_def is None:
      current_subset_def = SubsetDefinition()
      current_start = i

    current_end = i
    current_subset_def.add(shaping_unit.codepoint_at(i),
                           shaping_unit.features_at(i),
                           shaping_unit.design_space_point_at(i))

    if supports_subset_def(ift_font, current_subset_def):
      i += 1
      continue

    if current_end > current_start:
      supported_spans.append(Span(current_start, current_end - 1))
      # 次の反復で現在のコードポイントを単独で確認できるように、i は
      # インクリメントしない。
    else:
      i += 1

    current_start = current_end = current_subset_def = None

  return supported_spans


# ift_font が subset_def の対象コンテンツの描画に対応している場合は true を返す。
def supports_subset_def(ift_font, subset_def):
  # 次の2つの確認が両方とも true の場合に限り、true を返す。
  # - subset_def 内の各コードポイントが、ift_font の cmap テーブルによって '0' 以外のグリフ ID にマッピングされている。
  # - ift_font に対して subset_def を使用して「インクリメンタルフォントサブセットを拡張する」アルゴリズムを実行し、手順6で停止した後、
  #   エントリー一覧が空である。

返された範囲のいずれにも含まれないシェーピング単位内のテキストは、 インクリメンタルフォントでは対応していないため、 フォールバックフォントで描画するべきである。各範囲は個別にシェーピングするべきである(つまり、各範囲が新しい シェーピング単位になる)。 この方法ではシェーピング単位を分割するため、複数のコードポイントの 置換など、元のフォントの一部の機能が 利用できない場合がある。クライアントがインクリメンタルフォントサブセットを拡張する アルゴリズムに、§ 4.5 対象サブセット定義に従って構成した サブセット定義を正しく使用している場合、欠落したデータは読み込まれるため、 この状態は関連するパッチの読み込み中に一時的にのみ発生する。欠落していたパッチが到着して適用されると、 置換によって影響を受けるコードポイントの描画が変化する可能性がある。

注記:上記の「supported_spans(...)」の確認は、 インクリメンタルフォントの拡張を制御する目的ではない。 インクリメンタルフォントサブセットを拡張するの 実行に使用する対象サブセット定義の構成指針は、§ 4.5 対象サブセット定義に示されている。

4.7. フォントの完全な 拡張

この節では、インクリメンタルフォントを完全に拡張された 非インクリメンタルフォントに変換するためのアルゴリズムを定義する。この 処理では、インクリメンタルフォントが提供する利用可能なすべてのデータを読み込み、 追加で適用するパッチを含まない単一の静的フォントファイルを 生成する。

フォントサブセットを完全に拡張する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. font subsetを指定してインクリメンタルフォント サブセットを拡張するを呼び出す。入力する対象サブセット定義は、 エントリーの交差を確認する手順において、 すべてのエントリーと交差するとみなされる特別なものである。 結果として得られるフォントサブセットを expanded fontとして返す。

4.8. 拡張されたインクリメンタルフォントのキャッシュ

拡張されたインクリメンタルフォントには、この節の手順に従って 将来の拡張処理を実行するために必要な状態がすべて含まれている。したがって、 クライアントがインクリメンタルフォントを将来の使用のために保存またはキャッシュする場合は、 拡張アルゴリズムの直近の適用によって生成されたフォントバイナリのみを 保存すれば十分である。初期フォントや以前の拡張によって生成された バージョンを保持する必要はない。

5. フォント形式の拡張

インクリメンタルフォントは、 既存のOpenType形式に従うが、 4バイトのタグ 'IFT ' および 'IFTX' で識別される2つの新しい テーブルを含む。 これらの新しいテーブルはいずれもパッチマップである。 すべてのインクリメンタルフォントには、少なくとも 'IFT ' テーブルが含まれる。'IFTX' テーブルは任意である。両方のテーブルが 存在する場合、フォント全体のマッピングは2つのテーブルのマッピングの和集合となる。これら2つの新しい テーブルは、この 仕様でのみ使用され、Open-Type仕様には追加されない。

注記:マッピングを2つの異なる テーブルに分割できるようにすることで、インクリメンタルフォントは複数の パッチ形式をより容易に利用できる。例えば、ある種類のすべてのパッチを 'IFT ' テーブルに、 別の種類のすべてのパッチを 'IFTX' テーブルに指定できる。これらのパッチは、いずれか一方のマッピングテーブルのみを更新することで、 競合する更新を回避できる。

5.1. インクリメンタルフォント転送とフォント圧縮形式

ウェブ上でフォントを使用する際には、[WOFF]や[WOFF2]などの圧縮形式で圧縮することが一般的である。 次の条件を満たす限り、このような形式を使用して インクリメンタルフォント転送の符号化に用いる初期フォントファイルを圧縮できる。

  1. 圧縮形式によってフォントを符号化してから復号する過程で、各テーブルの バイトが変更されないこと。

  2. インクリメンタルフォント転送の拡張アルゴリズム(§ 4 フォントサブセットの拡張)は、非圧縮のフォントファイルに対して 動作するため、拡張を試みる前に圧縮されたフォントを復号する必要があること。

[WOFF2]については、 特別な注意が必要である。インクリメンタルフォントを転送用に WOFF2 で符号化する場合は、次のとおりとする。

  1. WOFF2 の符号化に変換済みの glyf および loca テーブルが含まれる場合(WOFF 2.0 § 5.1 変換された glyf テーブル形式)、インクリメンタル フォントには、glyf または loca テーブルを変更する§ 6.2 テーブルキー方式のパッチを 含めるべきではない。WOFF2 形式は、変換された glyf および loca テーブルを復号した結果の 具体的なバイト列を保証しない。§ 6.3 グリフキー方式のパッチは、 変換された glyf および loca テーブルと組み合わせて使用してもよい。

  2. 'IFT ' および 'IFTX' テーブルは、WOFF2 エンコーダーによって、 WOFF 2.0 § 5 圧縮データ 形式で定義される標準の処理に従って処理し、Brotli で符号化できる。

注記:glyf/loca 変換を無効にした場合でも、WOFF2 の圧縮率は WOFF より優れているため、 一般に IFT フォントは WOFF2 で圧縮することが推奨される。テーブルキー方式のパッチを使用して glyf/loca テーブルを更新する符号化の場合は、 これらの変換を無効にする。

5.2. CFF および CFF2 のインクリメンタルフォント

グリフのアウトラインをCFFまたはCFF2テーブルに格納する インクリメンタルフォントには、次の追加の制限がある。

これら3つの要件により、CFF および CFF2 テーブルに対するグリフキー方式のパッチ適用の実装を 大幅に簡素化できる。これにより、 CFF/CFF2 テーブル内に符号化された他のデータ要素へのオフセットを変更せずに、 グリフデータを挿入できる。 格納された CFF/CFF2 オフセットにより、クライアントは CFF/CFF2 テーブルの他の部分を解析せずに CharStrings INDEX を特定できる。

注記:場合によっては、CFF または CFF2 テーブルが テーブルキー方式のパッチによって追加または変更されることがある。この場合、パッチは 新しい内容または変更された内容を反映するように、CharStrings オフセットも追加または更新する必要がある。

CFF または CFF2 のサブルーチン化は、インクリメンタルフォント転送と互換性がある。ただし、単純な サブルーチン化は、 パッチのサイズを削減する一方、初期ファイルのサイズを増加させる傾向がある。また、WOFF2 は、 サブルーチン化されていない フォントを、対応するサブルーチン化されたフォントより効率的に圧縮できることが多い (非圧縮ファイルのサイズが大幅に大きくなるという代償はある)。 したがって、サブルーチン化は回避するか、適度に使用するか、 IFT の特定の要件に合わせて調整することが推奨される。

5.3. パッチマップテーブル

この節では、パッチマップの符号化を説明し、この形式で符号化されたバイト列を解釈して、 それが表すエントリー一覧を生成するアルゴリズムを定義する。インクリメンタルフォントサブセットを拡張する アルゴリズムは 解釈アルゴリズムを呼び出し、結果として得られたエントリー一覧を処理する。符号化されたバイト列は、 常にパッチマップの 唯一の信頼できる情報源となる。サブセット拡張中にパッチを適用すると、パッチ マップの符号化されたバイト列が変更され、その 結果、符号化されたバイト列から導出されるエントリー一覧も変化する。拡張アルゴリズムは、 前の反復で行われた変更を反映するため、 各反復の開始時に符号化されたバイト列を再解釈する。

パッチマップテーブルの 符号化:

型 名前 説明
uint8 format 2に設定する。このテーブルの形式を識別する。注記:以前のバージョンの仕様には形式1が 存在したが、削除された。互換性を維持し、将来の拡張点を提供するため、 format フィールドは以前の値である2のまま保持されている。
uint24 reserved 使用されない。0に設定する。
uint8 flags 任意のフィールドの存在を示すフラグ。 ビット0(最下位ビット)がセットされている場合、cffCharStringsOffsetが存在する。 ビット1(最下位ビット)がセットされている場合、cff2CharStringsOffsetが 存在する。
uint32 compatibilityId[4] このフォントと互換性のあるパッチを識別する一意の ID(§ 4.1 パッチの無効化を参照)。エンコーダーがこの 値を選択する。エンコーダーは、IFT フォントの符号化中に 以前使用されていないランダムな値に設定するべきである。
uint8 defaultPatchFormat urlTemplate が参照するパッチの形式を指定する(エントリーによって上書きされる場合を除く)。 § 6.1 形式の 概要の表に記載された形式番号のいずれかに設定しなければならない。
uint24 entryCount このテーブルに符号化されたエントリーの数。
Offset32 entries マッピング エントリーサブテーブルへのオフセット。オフセットはこのテーブルの先頭からの値である。
Offset32 entryIdStringData すべてのエントリー ID 文字列を連結したデータブロックへのオフセット。 null(0)でもよい。オフセットはこのテーブルの先頭からの値である。
uint16 urlTemplateLength urlTemplate バイト配列の長さ。
uint8 urlTemplate[urlTemplateLength] 各エントリーに関連付けられた URL 文字列を生成するために使用されるURL テンプレートを含む バイト配列。
uint32 cffCharStringsOffset flagsのビット0(最下位)がセットされている場合にのみ存在する。 CFFテーブルの 先頭から、そのテーブルの CharStrings INDEX データ構造までの オフセットを示す。 CFFテーブルの。
uint32 cff2CharStringsOffset flagsのビット1がセットされている場合にのみ存在する。 CFF2テーブルの 先頭から、そのテーブルの CharStrings INDEX データ構造までの オフセットを示す。 CFF2テーブルの。

マッピングエントリーの 符号化:

型 名前 説明
uint8 entries[variable] entryCount個のマッピングエントリーを符号化したバイト列を含むバイト配列。 各エントリーの長さは可変であり、 パッチマップエントリーを解釈するに従って決定される。

マッピングエントリーの符号化:

型 名前 説明
uint8 formatFlags ビットフィールド。ビット0(最下位ビット)からビット5は、任意の フィールドの存在を示す。ビット6がセットされている場合、このエントリーは 無視される。ビット7は将来の使用のために予約され、0に設定される。
uint8 featureCount featureTags リスト内の機能タグの数。formatFlagsのビット 0がセットされている場合にのみ存在する。
Tag featureTags[featureCount] エントリーのフォントサブセット定義に含まれる機能 タグの一覧。formatFlagsのビット0がセットされている場合にのみ存在する。
uint16 designSpaceCount デザイン空間リスト内の要素数。formatFlagsの ビット0がセットされている場合にのみ存在する。
デザイン 空間セグメント designSpaceSegments[designSpaceCount] エントリーのフォントサブセット 定義に含まれるデザイン空間セグメントの一覧。formatFlagsのビット0がセットされている場合にのみ存在する。
uint8 childEntryMatchModeAndCount このフィールドと次のフィールドは、以前のエントリーが交差するかどうかに依存する 条件を、このエントリーの交差確認に追加するために使用される。 最上位ビットは一致モードを示すために使用される。このビットがセットされている場合、条件は 論理積であり、それ以外の場合は論理和である。 残りの7ビットは符号なし整数として解釈され、childEntryIndices リスト内の エントリーインデックスの数を表す。このフィールドは、 formatFlagsのビット1がセットされている場合にのみ存在する。
uint24 childEntryIndices[0b01111111 & childEntryMatchModeAndCount] 各値は、entries配列内のエントリーのインデックスであり、 その交差を確認して、このエントリーが交差するかどうかを判断する。 マッピングエントリーより前にentries内に現れるエントリーのみを 参照できる。formatFlagsのビット1がセットされている場合にのみ存在する。
int24 entryIdDelta[variable] このエントリーの URL 文字列の ID を計算する符号付き差分値の一覧。存在する場合、 少なくとも1つの差分値を含む。差分値の 最下位ビットがセットされている場合、さらに1つの差分値が続く。これは、 最下位ビットが クリアされた差分値に遭遇するまで繰り返される。各差分値に対応するエントリー ID は、最後に計算されたエントリー ID + 1 + floor(entryIdDelta / 2) である。formatFlagsのビット2がセットされ、かつentryIdStringDataが null(0)の場合にのみ存在する。 存在せず、かつentryIdStringDataが null(0)の場合、 このエントリーには1つの ID があり、 差分値は0とみなされる。
uint24 entryIdStringLength[variable] このエントリーの各 ID 文字列がentryIdStringData データブロック内で占めるバイト数。長さの値の最上位ビットがセットされている場合、 別の長さの値が続く。これは、 最上位ビットがクリアされた長さの値に遭遇するまで繰り返される。実際の長さの 値は、各値の 下位23ビットに格納される。formatFlagsの ビット2がセットされ、かつ entryIdStringDataが null(0)でない場合にのみ存在する。 存在する場合、少なくとも1つの長さの値を含む。存在せず、 かつentryIdStringDataが null(0)でない場合、 1つの ID 文字列があり、その値は前のエントリーの最後の ID 文字列、または最初のエントリーの場合は空文字列に設定される。
uint8 patchFormat このエントリーによって参照されるパッチの形式を指定する。§ 6.1 形式の概要の表に記載された ID 番号を使用する。 defaultPatchFormatを上書きする。 formatFlagsのビット3がセットされている場合にのみ存在する。
uint16/uint24 bias コードポイント集合内のすべてのコードポイント値に加算されるバイアス値。 形式のビット4が0でビット5が1の場合、これは存在し、uint16 となる。 形式のビット4が1でビット5が1の場合、これは存在し、uint24 となる。 それ以外の場合は存在しない。
uint8 codePoints[variable] このマッピングのコードポイント集合。疎なビット集合として符号化される。 formatFlagsのビット4および/または5がセットされている場合にのみ存在する。長さは、 § 5.3.3 疎なビット集合の復号手順に従って決定される。

エンコーダーがファイルシステムに格納してから配信するパッチを生成する場合、 数値のエントリー ID のみを 使用することが推奨される(entryIdDeltaを使用)。一般に、これによりパッチマップの 符号化サイズが最小になるためである。文字列 ID は、 パッチが事前に格納されておらず、ID 文字列を使用して 要求されるパッチに関する情報を 符号化できる場合に有用である。

デザイン空間 セグメントの符号化:

型 名前 説明
Tag tag 軸タグの値。
Fixed start セグメントの開始値(この値を含む)。この値はユーザー軸スケールを使用する。 OpenType 仕様 § otvaroverview#coordinate-scales-and-normalization。
Fixed end セグメントの終了値(この値を含む)。start 以上でなければならない。 この値はユーザー軸スケールを使用する。 OpenType 仕様 § otvaroverview#coordinate-scales-and-normalization。

5.3.1. パッチマップの解釈

このアルゴリズムは、パッチ マップをパッチマップエントリーの一覧に変換するために使用される。

パッチマップを解釈する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. patch mapのformatが2に等しく、 § 5.3 パッチマップテーブルの要件(「must」で示される要件)に 従って有効であることを確認する。有効でない場合はエラーを返す。

  2. entryIdStringDataのオフセットが0の場合、 last entry idを0に初期化する。それ以外の場合は、 空のバイト文字列に初期化する。current byteを0に、current id string byteを 0に設定する。

  3. entry listとprior entry listを空の一覧に初期化する。

  4. パッチマップエントリーを解釈するを、 entryCount回呼び出す。各呼び出しについて:

    • prior entry list、patch mapのentries[current byte]から patch mapの末尾までのバイト列、 entryIdStringData[current id string byte]から patch mapの末尾までのバイト列(entryIdStringDataが0でない場合)、 last entry id、 defaultPatchFormat、および urlTemplateを渡す。

    • last entry idを返されたエントリー ID に設定する。

    • 返された消費バイト数をcurrent byteに加算する。

    • 返された消費 ID 文字列バイト数をcurrent id string byteに加算する。

    • 返されたエントリーをprior entry listに追加する。

    • 返された ignored の値が false の場合、返された エントリーの互換性 ID を compatibilityIdに設定し、そのエントリーを entry listに追加する。

  5. entry listを返す。

パッチマップエントリーを解釈する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. すべての手順において、entry bytesからデータを読み込むたびに、 読み込んだバイト数だけconsumed bytesを増加させる。

  2. entry id = last entry id、consumed id string bytes = 0に設定する。

  3. entryのパッチ形式をdefault patch formatに設定する。

  4. すべての集合を空に初期化した単一のフォントサブセット定義をentryに 追加する。

  5. entry bytesからformatFlagsを読み込む。

  6. formatFlagsのビット0がセットされている場合、 機能タグとデザイン空間の一覧が存在する。

  7. formatFlagsのビット1がセットされている場合、 コピーインデックスの一覧が存在する。

    • childEntryMatchModeAndCountの 最上位ビットがセットされている場合、entryの一致モードを論理積に設定し、 それ以外の場合は論理和に設定する。

    • childEntryMatchModeAndCountと childEntryIndicesによって指定される 子エントリーのインデックス一覧をentry bytesから読み込む。

    • 子エントリーのインデックスは、以前に読み込まれたエントリーを参照する。0は prior entry list内の最初のマッピングエントリー、 1は2番目、 以下同様である。childEntryIndices内の各値について、 prior entry listから一致するインデックスのエントリーを特定する。 そのエントリーへの参照をentryに追加する。childEntryIndicesが prior entry listの長さ以上の場合、 この符号化は無効であるため、エラーを返す。

  8. formatFlagsのビット2がセットされている場合、 ID の差分値または ID 文字列の長さが存在する。

    • id string bytesが存在しない場合:

      • 次のentryIdDeltaの値を読み込む。

      • entry idを entry id + 1 + floor(delta value / 2)に設定する。 entry idが負、または4,294,967,295より大きい場合、この符号化は 無効であるため、エラーを返す。

      • url templateと entry idを入力としてURL テンプレートを展開するを呼び出し、 entry idを URL 文字列に変換する。テンプレートの展開でエラーが発生した場合は、 エラーを返す。

      • 生成されたパッチ URL 文字列をentryに追加する。

      • 読み込んだ差分値の最下位ビットがセットされている場合、手順8を繰り返す。

    • それ以外の場合、id string bytesが存在する場合:

      • 次のentryIdStringLengthの値を読み込む。

      • 下位23ビットを符号なし整数として解釈し、その数だけ id string bytesからバイトを読み込む。 entry idをその結果に設定する。consumed id string bytesを 読み込んだバイト数だけ増加させる。

      • url templateと entry idを入力としてURL テンプレートを展開するを呼び出し、 entry idを URL 文字列に変換する。テンプレートの展開でエラーが発生した場合は、 エラーを返す。

      • 生成されたパッチ URL 文字列をentryに追加する。

      • 読み込んだ長さの値の最上位ビットがセットされている場合、手順8を繰り返す。

  9. formatFlagsのビット2がセットされていない場合:

    • id string bytesが存在しない場合:

      • entry idをentry id + 1に設定する。

      • url templateと entry idを入力としてURL テンプレートを展開するを呼び出し、 entry idを URL 文字列に変換する。テンプレートの展開でエラーが発生した場合は、 エラーを返す。

      • 生成されたパッチ URL 文字列をentryに追加する。

    • それ以外の場合、id string bytesが存在する場合:

      • url templateと entry idを入力としてURL テンプレートを展開するを呼び出し、 entry idを URL 文字列に変換する。テンプレートの展開でエラーが発生した場合は、 エラーを返す。

      • 生成されたパッチ URL 文字列をentryに追加する。

  10. formatFlagsのビット3がセットされている場合、 パッチ形式が存在する。entry bytesから patchFormatで指定された形式を読み込み、 entryのパッチ形式を読み込んだ値に設定する。 patchFormatが§ 6.1 形式の概要に記載された値のいずれでもない場合、 この符号化は無効であるため、エラーを返す。

  11. formatFlagsのビット4とビット5の一方または両方がセットされている場合、 コードポイントの一覧が存在する。

    • formatFlagsのビット4が0でビット5が1の場合、 entry bytesから2バイト(uint16)のbias値を 読み込む。

    • formatFlagsのビット4が1でビット5が1の場合、 entry bytesから3バイト(uint24)のbias値を 読み込む。

    • それ以外の場合、バイアスは0である。

    • § 5.3.3 疎なビット集合に従って、 entry bytesからバイアスを使用して疎なビット集合codePointsを読み込む。 結果のコードポイント集合をentry内の最初のフォントサブセット 定義に追加する。疎なビット集合の復号に失敗した場合、 この符号化は無効であるため、エラーを返す。

  12. formatFlagsのビット6がセットされている場合、 ignoredを true に設定する。それ以外の場合、ignoredは false である。

  13. entry id、entry、consumed bytes、 consumed id string bytes、およびignoredを返す。

5.3.2. パッチマップからエントリーを削除する

このアルゴリズムは、パッチマップからエントリーを削除するために使用される。この削除によって パッチマップのバイト列は変更されるが、 バイト数は変更されない。

パッチマップからエントリーを削除する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムは、パッチマップを 解釈するの変更版である。patch mapを入力としてパッチマップを解釈するを呼び出すが、 次の変更を加える。

5.3.3. 疎なビット集合

疎なビット集合は、相異なる符号なし整数の集合をコンパクトに格納するデータ構造である。集合は 木として表現され、 各ノードは一定数の子を持ち、区間を等しい部分に再帰的に分割する。 高さがH、分岐係数が Bの木は、区間[0から BH-1](両端を含む)内の整数の集合への所属情報を格納できる。木は 転送のためにバイト配列に符号化される。

パッチマップテーブルの文脈では、疎なビット集合は Unicodeコードポイントの集合を格納するために使用される。したがって、 疎なビット集合に格納される整数値は、 Unicodeコードポイント値の範囲0から0x10FFFFに制限される。

疎なビット集合の符号化:

型 名前 説明
uint8 header ビット0(最下位)とビット1は、分岐係数の符号化によって木の分岐係数Bを符号化する。 ビット2から6は、Hの値を符号化する5ビットの符号なし整数である。ビット7は0に設定され、 将来の使用のために予約される。
uint8 treeData[variable] 木のバイナリ符号化。

treeDataの正確な長さは最初は不明であり、 復号アルゴリズムの実行によって決定される。 分岐係数に2または4を使用する場合、最後のノードは1バイト内のビットの一部しか消費しないことがある。 その場合、残りのすべてのビットは使用されず、 無視される。

分岐係数の 符号化:

ビット1 ビット0 分岐係数(B) 最大高さ(H)
0 0 2 31
0 1 4 16
1 0 8 11
1 1 32 7

符号化された高さ(H)が、上の表で符号化された 分岐係数(B)に対する最大高さを超える 疎なビット集合は無効である。

疎なビット集合の treeData を復号する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

FIFO(先入れ先出し)キューQを使用するアルゴリズム:

  1. treeDataから最初のバイトを取り除く。これはヘッダーバイトである。 疎なビット集合に従って、 木の高さHと分岐係数Bを決定する。

  2. Hが分岐係数の符号化の 表でBに対応する行の「最大高さ」を超える場合、 符号化は無効であるため、エラーを返す。

  3. Hが0の場合、これは空集合であり、treeDataからそれ以上のバイトを 消費しない。空集合を返す。

  4. 組(0, 1)をQに挿入する。

  5. Sを空集合に初期化する。

  6. treeDataをビット列として解釈する。ここで、 treeData[0]の最下位ビットがビット列の最初のビットであり、 treeData[0]の最上位ビットが8番目のビットである。以下同様とする。

  7. 以降の手順で、Unicode コードポイントの最大値(0x10FFFF)を超える値が Sに追加される場合、 その値を無視し、Sに追加しない。

  8. Qが空の場合、Sを返す。

  9. Qから次の組tを取り出す。tの最初の値が startであり、2番目の値がdepthである。

  10. treeDataのビット列から次のBビットを取り除く。最初に取り除いたビットを v1、 2番目をv2とし、最後に取り除いたビットである vBまで同様とする。取り除く前の treeDataに残っているビット数がB未満の場合、treeDataは不正であるため、 エラーを返す。

  11. v1からvBまでのすべてのビットが0の場合、 区間 [start + bias, start + bias + BH - depth + 1) 内のすべての整数をSに挿入する。手順5に進む。

  12. v1から vBまでの各viのうち、1に等しいものについて: depthがHに等しい場合、整数 start + bias + i - 1をSに追加する。それ以外の場合、 組 (start + (i - 1) * BH - depth, depth + 1) をQに挿入する。

  13. 手順8に進む。

注記:疎なビット集合を符号化する際、エンコーダーは 利用可能な任意の分岐係数を使用できるが、 通常遭遇するほとんどの Unicode コードポイント集合について最小の符号化サイズになることが示されている ため、4を使用することが推奨される。

分岐係数が8の木における集合{2, 33, 323}は、次のビット列として符号化できる。
bit string:
|-- header --|- lvl 0 |---- level 1 ----|------- level 2 -----------|
| B=8 H=3    |   n0   |   n1       n2   |   n3       n4       n5    |
[ 01  11000 0 10000100 10001000 10000000 00100000 01000000 00010000 ]

これは次のバイト列になる:
[
  0b00001110,
  0b00100001,
  0b00010001,
  0b00000001,
  0b00000100,
  0b00000010,
  0b00001000
]
分岐係数が2の木における空集合は、次のビット列として符号化される。
bit string:
|-- header -- |
| B=2 H=0     |
[ 00  00000 0 ]

これは次のバイト列になる:
[
  0b00000000,
]
集合{0, 1, 2, ..., 17}は、分岐係数4で次のように符号化できる。
bit string:
|-- header --| l0 |- lvl 1 -| l2  |
| B=4 H=3    | n0 | n1 | n2 | n3  |
[ 10  11000 0 1100 0000 1000 1100 ]

byte string:
[
  0b00001101,
  0b00000011,
  0b00110001
]

5.3.4. URL テンプレート

URL テンプレートは、各パッチマップエントリーに関連付けられた URL 文字列を圧縮するために使用される。各パッチマッピング テーブルは、 URL テンプレートを提供し、各エントリーの ID を入力として共通テンプレートを展開することで 各エントリーの URL 文字列を生成する。 テンプレート展開の出力は、[UTF-8]で符号化された文字列である。

URL テンプレートは、リテラル値を挿入するか、入力されたエントリー ID に基づく 値を挿入する 一連の1バイトのオペコードとして符号化される。

URL テンプレートを復号して展開するアルゴリズムを以下に示す。

URL テンプレートを展開する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. URL stringを空のバイト配列に初期化する。以降の手順では、 url template bytesをキューとして使用する。 読み込み操作は、キューの先頭(インデックス0のバイト)からバイトを取り除く。

  2. url template bytesの次のバイトを読み込み、op codeに格納する。 残りのバイトがない場合、 展開は完了しているため、URL stringを返す。

  3. op codeの最上位ビットがセットされていない場合:

    • op codeの下位7ビットを符号なし整数として解釈し、 number of literalsとする。

    • number of literalsが0の場合、エラーを返す。

    • url template bytesから次のnumber of literalsバイトを読み込み、 literal bytesに格納する。 url template bytesに十分なバイトが残っていない場合、 エラーを返す。

    • literal bytesがUTF-8、ISO 10646 の変換形式 § section-4に従って有効な UTF-8 符号化文字列であることを確認する。 有効でない場合はエラーを返す。

    • literal bytesをURL stringの末尾に追加する。

    • 手順2に進む。

  4. op codeの最上位ビットがセットされている場合:

    • 後述のオペコード参照表でop codeを検索する。 「挿入操作」列で指定された 操作を実行する。op codeが表に見つからない場合、 エラーを返す。

    • 手順2に進む。

オペコード参照表

名前 オペコード値 挿入操作
id32 を挿入 128 (0b10000000) 後述の展開変数表のid32変数の値を URL stringに追加する。
d1 を挿入 129 (0b10000001) 後述の展開変数表のd1変数の値を URL stringに追加する。
d2 を挿入 130 (0b10000010) 後述の展開変数表のd2変数の値を URL stringに追加する。
d3 を挿入 131 (0b10000011) 後述の展開変数表のd3変数の値を URL stringに追加する。
d4 を挿入 132 (0b10000100) 後述の展開変数表のd4変数の値を URL stringに追加する。
id64 を挿入 133 (0b10000101) 後述の展開変数表のid64変数の値を URL stringに追加する。

展開変数

変数 値
id32 入力されたentry IDをbase32hex文字列として符号化したもの (数字0~9および A~V を使用)であり、 パディングは省略される。entry IDが符号なし整数の場合、最初にビッグエンディアンの32ビット 符号なし整数に変換しなければならない。 ただし、符号化する前に0に等しい先頭のバイトをすべて取り除く。(例えば、 整数が256未満の場合、1バイトのみが符号化される。)entry IDが0の場合は、 1つのゼロバイトが符号化される。 entry IDが文字列の場合、生のバイト列が base32hex として符号化される。
d1 id32変数内の文字列の最後の文字。 id32変数が空の場合、値は文字 _(U+005F)である。
d2 id32変数内の文字列の最後から2番目の文字。 id32変数の文字数が2未満の場合、値は文字 _ (U+005F)である。
d3 id32変数内の文字列の最後から3番目の文字。 id32変数の文字数が3未満の場合、値は文字 _ (U+005F)である。
d4 id32変数内の文字列の最後から4番目の文字。 id32変数の文字数が4未満の場合、値は文字 _ (U+005F)である。
id64 入力されたentry IDをbase64url文字列として符号化したもの (文字 A~Z、a~z、数字0~9、- (ハイフン)および _(アンダースコア)を使用)であり、パディングが含まれる。パディング文字は '=' であるため、 '%3D' として URL 符号化しなければならない。entry IDが符号なし整数の場合、 最初にビッグ エンディアンの32ビット符号なし整数に変換しなければならない。ただし、符号化する前に 0に等しい先頭のバイトをすべて取り除く。 (例えば、整数が256未満の場合、1バイトのみが符号化される。)entry IDが0の場合、 1つのゼロバイトが符号化される。entry IDが文字列の場合、その生のバイト列が base64urlとして符号化される。

入力例とそれに対応する展開結果を以下に示す。「テンプレートのバイト列」列の値は、 C 形式のバイト配列として示される。

テンプレートのバイト列 入力 ID ID の型 展開結果
[16, 'h', 't', 't', 'p', 's', ':', '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 128] 123 整数 https://foo.bar/FC
[8, 'f', 'o', 'o', '?', 'b', 'a', 'r', '=', 128] 123 整数 foo?bar=FC
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 128] 0 整数 //foo.bar/00
[5, '/', 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 128] 478 整数 /foo/0/F/07F0
[5, '/', 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] 123 整数 /foo/C/F/_/FC
[4, 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] ['b', 'a', 'z'] 文字列 foo/K/N/G/C9GNK
[4, 'f', 'o', 'o', '/', 129, 1, '/', 130, 1, '/', 131, 1, '/', 128] ['z'] 文字列 foo/8/F/_/F8
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 14,000,000 整数 //foo.bar/1Z-A
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 0 整数 //foo.bar/AA%3D%3D
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] 17,000,000 整数 //foo.bar/AQNmQA%3D%3D
[10, '/', '/', 'f', 'o', 'o', '.', 'b', 'a', 'r', '/', 133] [0xc3, 0xa0, 0x62, 0x63] 文字列 //foo.bar/w6BiYw%3D%3D

以下の例では、展開が失敗し、エラーが返されることが予想される。

テンプレートのバイト列 入力 ID ID の型 失敗の理由
[4, 'f', 'o', 'o', '/', 150] 123 整数 オペコード150は無効である
[4, 'f', 'o', 'o', '/', 0, 128] 123 整数 オペコード0は無効である
[10, 'f', 'o', 'o', '/', 128] 123 整数 リテラルコピー用のオペコード10に対して、テンプレート内のバイト数が不足している。
[4, 'f', 'o', 'o', 0x85, 128] 123 整数 リテラルのバイト列が有効な UTF-8 ではない。

6. フォントパッチ形式

インクリメンタルフォント転送では、フォント サブセットはパッチを適用することによって拡張される。 この仕様では、それぞれ異なる拡張シナリオに適した2種類のパッチ形式を定義する。単一の 符号化で複数のパッチ形式を使用できる。

6.1. 形式の概要

この仕様では、次のパッチ形式を定義する。

各アルゴリズムの詳細については、以降の節で説明する。

§ 5.3 パッチマップテーブルでは、次の形式番号を使用して パッチ形式と無効化モードを識別する。

形式番号 名前 無効化
1 § 6.2 テーブルキー方式 完全 無効化
2 § 6.2 テーブルキー方式 部分 無効化
3 § 6.3 グリフキー方式 無効化なし

6.2. テーブルキー方式

テーブルキー方式のパッチには、入力フォントファイル内の個々の フォントテーブルに適用されるパッチの集合が含まれる。 各テーブルパッチは、入力フォントファイル内の対応するテーブルを 共有 LZ77 辞書として使用し、Brotli 圧縮によって符号化される。テーブルキー方式で符号化されたパッチは、短いヘッダーと、 それに続く1つ以上の Brotli 符号化されたパッチで構成される。テーブルにパッチを適用するだけでなく、 パッチによってフォント サブセット内のテーブルを置換(既存のテーブルデータは使用しない) または削除することもできる。

テーブルキー方式のパッチの 符号化:

型 名前 説明
Tag format 形式が テーブルキー方式であることを識別し、'iftk' に設定しなければならない。
uint32 reserved 将来の使用のために予約され、0に設定する。
uint32 compatibilityId[4] このパッチを適用できるフォント サブセットの ID。§ 4.1 パッチの無効化を参照。
uint16 patchesCount patches 配列内のエントリー数。
Offset32 patches[patchesCount+1] 各エントリーは、このテーブルの先頭からTablePatchまでのオフセットである。オフセットは 昇順に並べ替えられていなければならない。

patches配列内の連続する 2つのオフセットの差は、 対応するTablePatchのサイズを示す。

TablePatchの符号化:

型 名前 説明
Tag tag このパッチが適用されるフォント テーブルを識別するタグ。
uint8 flags ビットフィールド。ビット0(最下位ビット)がセットされている場合、このパッチは既存のテーブルを置換する。 ビット1がセットされている場合、このテーブルは削除される。
uint32 maxUncompressedLength brotliStreamの非圧縮時の最大長。
uint8 brotliStream[variable] Brotli で符号化されたバイトストリーム。

6.2.1. テーブル キー方式のパッチの適用

このパッチ適用アルゴリズムは、テーブルキー方式の パッチを適用してフォントサブセットを拡張し、 追加のコードポイント、機能、および/またはデザインバリエーション空間に対応させるために使用される。

テーブルキー方式のパッチを適用する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. extended font subsetを、テーブルを含まない空のフォントに初期化する。

  2. patchが§ 6.2 テーブルキー方式の要件 (「must」で示された要件)に従って有効であり、 すべてのTablePatchが patch内に完全に含まれていることを確認する。そうでない場合はエラーを返す。

  3. patch内のcompatibilityIdフィールドが compatibility idと等しいことを確認する。 一致しない場合、またはbase font subsetに 'IFT ' と 'IFTX' のどちらのテーブルもない場合、 パッチの適用は 失敗しているため、エラーを返す。

  4. 以降の手順でextended font subsetにテーブルを追加する処理は、 フォントにテーブルのデータを追加し、 OpenType 仕様の要件に従ってテーブル ディレクトリに新しいエントリーを挿入することで構成される。 このエントリーにはテーブルデータのチェックサムが含まれる。既存のテーブルを変更せずにコピーする場合、 クライアントは元のフォントのエントリーに含まれるチェックサムを 再利用できる。それ以外の場合は、新しいチェックサムを計算する必要がある。

  5. patches内の各エントリーについて、インデックスをiとして:

    • インデックスiに関連付けられたTablePatchを 見つける。オブジェクトはオフセット patches[i](この位置を含む)から始まり、 オフセット patches[i+1](この位置を含まない)で終わる。 どちらのオフセットも patchの先頭を基準とする。

    • patches内のエントリーが以前に適用されており、 そのエントリーのtagが 現在のエントリーと同じ場合、現在のエントリーを無視して次のエントリーの処理に進む。 エントリーは、 patches配列に列挙された順序で処理される。

    • flagsのビット1がセットされている場合、 tagで識別されるテーブルを extended font subsetにコピーも追加もしない。次のエントリーに進む。

    • flagsのビット0(最下位ビット)がセットされている場合、 brotliStreamを Brotli 圧縮データ 形式 § 10 復号アルゴリズムに従って復号する。 共有辞書は使用しない。復号されたデータがmaxUncompressedLengthより 大きい場合はエラーを返す。brotliStreamに 復号処理で使用されなかったデータが存在する場合はエラーを返す。 テーブルを extended font subsetに追加し、 tagで識別し、 その内容を復号されたbrotliStreamに設定する。次のエントリーに進む。

    • それ以外の場合、brotliStreamをBrotli 圧縮データ 形式 § 10 復号アルゴリズムに従って復号する。このとき、 base font subset内のtagで識別されるテーブルを 共有 LZ77 辞書として使用する。そのようなテーブルが存在しない場合はエラーを返す。 復号されたデータがmaxUncompressedLengthより大きい場合は エラーを返す。brotliStreamに 復号処理で使用されなかったデータが存在する場合はエラーを返す。 テーブルを extended font subsetに追加し、tagで識別し、その内容を復号された brotliStreamに設定する。

  6. base font subset内の各テーブルのうち、 手順5で処理したどのエントリーにも見つからなかったタグを持つものについて、 そのテーブルのコピーをextended font subsetに追加する。

6.3. グリフキー方式

グリフキー方式のパッチには、それぞれがグリフインデックスと フォントテーブルに関連付けられたデータチャンクの集合が含まれる。 符号化されたデータは、参照先のテーブル内で、 そのグリフインデックスに対応する既存のデータを置換する。グリフキー方式のパッチは、 glyf/loca、 gvar、CFF、およびCFF2テーブルのデータを符号化できる。

グリフキー方式のパッチの 符号化:

型 名前 説明
Tag format 形式がグリフキー方式であることを識別し、 'ifgk' に設定しなければならない。
uint32 reserved 将来の使用のために予約され、0に設定する。
uint8 flags ビットフィールド。ビット0(最下位ビット)がセットされている場合、 glyphIdsは uint24 を使用し、 それ以外の場合は uint16 を使用する。
uint32 compatibilityId[4] このパッチを適用できるフォントサブセットの互換性 ID。§ 4.1 パッチの無効化を参照。
uint32 maxUncompressedLength brotliStreamの非圧縮時の最大長。
uint8 brotliStream[variable] Brotli で符号化されたGlyphPatchesテーブル。

GlyphPatchesの符号化:

型 名前 説明
uint32 glyphCount パッチ内に符号化されたグリフの数。
uint8 tableCount パッチにデータが含まれるテーブルの数。
uint16/uint24 glyphIds[glyphCount] パッチに含まれるグリフインデックスの配列。flagsのビット0(最下位ビット)が セットされている場合、要素は uint24 であり、それ以外の場合は uint16 である。 昇順に 並べ替えられていなければならず、 重複する値を含んではならない。
Tag tables[tableCount] パッチに含まれるテーブルの配列 (タグによって識別される)。昇順に 並べ替えられていなければならず、重複する値を含んではならない。 並べ替えでは、タグの値を4バイトのビッグエンディアン 符号なし整数として解釈し、その整数値によって並べ替える。
Offset32 glyphDataOffsets[glyphCount * tableCount + 1] 各テーブルのグリフデータへのオフセットの配列。最初のglyphCount個のオフセットは tables[0]に対応し、次のglyphCount個のオフセットは (存在する場合)tables[1]に対応する。以下同様とする。 すべてのオフセットは、 GlyphPatchesテーブルの 先頭を基準とする。 オフセットは 昇順に並べ替えられていなければならない。
uint8 glyphData[variable] オフセットによって指定される実際のグリフデータ。

glyphDataOffsets 配列内の連続する2つのオフセットの差は、 対応するグリフデータのサイズを示す。

6.3.1. グリフ キー方式のパッチの適用

このパッチ適用アルゴリズムは、グリフキー方式の パッチを適用してフォントサブセットを拡張し、 追加のコードポイント、機能、および/またはデザインバリエーション空間に対応させるために使用される。

グリフキー方式のパッチを適用する

このアルゴリズムへの入力は次のとおりである。

このアルゴリズムの出力は次のとおりである。

アルゴリズム:

  1. patchが§ 6.3 グリフキー方式の要件(「must」で示された要件)に 従って有効であることを確認する。有効でない場合はエラーを返す。

  2. patch内のcompatibilityIdフィールドが compatibility idと等しいことを確認する。 一致しない場合、またはbase font subsetに 'IFT ' と 'IFTX' のどちらのテーブルもない場合、 パッチの適用は 失敗しているため、エラーを返す。

  3. brotliStream内の Brotli 符号化データを、 Brotli 圧縮データ 形式 § 10 復号アルゴリズムに従って復号する。 復号されたデータはGlyphPatchesテーブルである。復号されたデータが maxUncompressedLengthより大きい場合は エラーを返す。

  4. tablesに列挙された各フォント テーブルについて、インデックスをiとして:

    • base font subset内の対応するテーブルを使用して、 各グリフのデータを、そのグリフインデックスに対応する glyphDataのデータが存在する場合はそれに置換し、 存在しない場合はbase font subset内の対応するテーブルから そのグリフインデックスのデータをコピーした新しいテーブルを合成する。

    • あるグリフインデックスのパッチグリフデータは、そのグリフインデックスに等しい glyphIds[j]を見つけることで 特定する。関連するグリフデータへの オフセットはglyphDataOffsets[i * glyphCount + j]である。 関連するグリフデータの長さは、 glyphDataOffsets[i * glyphCount + j + 1]から glyphDataOffsets[i * glyphCount + j]を引いた値である。

    • 新しいテーブルを合成する具体的な処理は、 テーブルの 指定された形式によって異なる。 グリフに関連付けられていないデータは、 base font subset内のテーブルからコピーするべきである。 glyf、 gvar、CFF、またはCFF2の 各形式のテーブルに対応する。その他の種類の テーブルの エントリーは無視しなければならない。glyfを更新する場合は、 loca テーブルも 更新しなければならない。この手順の結果として、フォント内の他のテーブルを変更することはできない。 特に、これはパッチによって maxpで指定された numGlyphs を超える インデックスのグリフを追加できないことを意味する。

      CFF、CFF2、およびgvarでは、 グリフごとのデータへのオフセットのサイズが可変である。 新しいテーブルを合成する際に必要であれば、オフセットのサイズを拡大できる。一方、 glyf/locaでは、 オフセットのサイズがheadテーブルで指定されているため、 変更できない。合成中に生成されたオフセットが、 可能であればオフセットサイズを拡大した後でも、 最大のオフセット値を超える場合、パッチの適用は 失敗しているため、エラーを返す。

    • base font subsetに対応するテーブルがない場合、エラーを返す。

    • 合成されたテーブルをextended font subsetに挿入する。

  5. compatibility idと同じcompatibilityIdを持つ § 5.3 パッチマップテーブルを特定する。 パッチマップテーブルとpatch URL stringを入力として、 パッチマップからエントリーを削除するを 呼び出す。変更されたパッチマップテーブルを extended font subsetにコピーする。

  6. base font subset内の各テーブルのうち、 手順4または5で処理したどのエントリーにも見つからなかったタグを持つものについて、 そのテーブルのコピーをextended font subsetに追加する。

  7. 前の手順でいずれかのフォント テーブルの内容が変更された場合、 変更された各テーブルについて、フォントの テーブルディレクトリ内のチェックサムを、 テーブルの新しい内容と一致するように更新する。

7. 符号化

エンコーダーとは、インクリメンタルフォントと、それに関連付けられたパッチの集合を生成するツールである。「符号化」とは、 エンコーダーを使用する処理を指し、特定の場合に 結果へ影響を与えるためにエンコーダーが必要とする、または許容するパラメーターも含まれる。 適合するエンコーダーによって生成されるインクリメンタルフォント と関連するパッチは、次の条件を満たす。

  1. § 5 フォント形式の拡張および§ 6 フォントパッチ形式のすべての要件を 満たさなければならない。

  2. 一貫性がなければならない。すなわち、 任意のフォントサブセット定義について、 そのサブセット定義とインクリメンタルフォントを使用してインクリメンタルフォント サブセットを拡張するを呼び出した結果は、 インクリメンタルフォント サブセットを拡張するの手順8で選択された具体的なパッチ選択順序に 関係なく、常に同じでなければならない。

  3. パッチの 無効化基準を遵守しなければならない。IFT 符号化の一部であるパッチは、 互換性のあるフォントサブセットに適用された場合、 パッチマップの互換性 ID に対して、 関連するパッチマップエントリーが宣言する無効化モードの § 4.1 パッチの無効化の基準に適合する変更のみを 行わなければならない。

  4. エンコーダーを使用して既存のフォントをインクリメンタルフォントに変換する場合、 対応する完全に拡張されたフォントは、 既存のフォントと同等であるべきである。同等の完全に拡張されたフォントは、 既存のフォントと同じテーブルを すべて含み(インクリメンタル IFT/IFTX テーブルを除く)、各テーブルは既存のフォント内の対応するテーブルと 機能的に同等であるべきである。注記:完全に 拡張されたフォントが、既存のフォントとバイナリレベルで完全に一致するとは限らない。

  5. 拡張処理の全体を通じて、完全に拡張されたフォントの機能を維持するべきである。 すなわち、 インクリメンタル フォントから導出された完全に拡張されたフォントと 任意のコンテンツが与えられた場合、そのコンテンツを対象とする最小のサブセット定義と インクリメンタル フォントを使用してインクリメンタルフォント サブセットを拡張するを呼び出して生成された フォントサブセットは、そのコンテンツを 完全に拡張されたフォントと同一に描画するべきである。

エンコーダーを使用して既存のフォントファイルをインクリメンタルフォントに変換し、 クライアントがこの文書の 他の節に従って実装されている場合、IFT 仕様の意図は、 クライアントにおけるフォントの外観と動作が、 フォントファイル全体をクライアントに転送した場合と同じになることである。IFT 仕様の主な目標は、 IFT 形式とプロトコルが WOFF2 に匹敵する、フォント転送のための中立的な媒体として機能することである。 エンコーダーが上記のすべての要件(1から5)を満たす 元のフォントから符号化を生成した場合、その符号化は 元のフォントのすべての機能を維持する。上記の要件4は、 元のフォントに含まれるすべての機能を利用可能にすることを保証する。これは、 IFT フォントの部分的なバージョンが、その部分的なフォントの導出に使用された サブセット定義に含まれるコンテンツについて、完全なバージョン(ここでは元のフォント)と 同等の機能を持つことを要求する要件5と組み合わせて機能する。

これは、フォント製造元やその他の権利者が、 IFT を使用したそのフォントの 符号化と転送によって動作が変わらず、その結果としてフォント制作者の意図も変わらないことを 確信したい場合に重要となり得る。その場合、ライセンスや 契約に IFT への適合性に関する要件が含まれる可能性があり、 内容の中立性によって WOFF2 形式への再符号化が事実上 許容される状況では、そのフォントの IFT 符号化も許容される可能性がある。

ただし、これらの符号化への適合性に関する要件は、 元のフォントのすべての機能を維持しない 符号化の可能性や実用的な利用を排除したり、非推奨にしたりすることを意図していない。 最小限の要件(上記の1、2、3)を満たす符号化は すべて有効であり、適切な用途を持つ可能性がある。状況によっては、 元のフォントファイルに含まれていた機能やデータの一部への対応を、 符号化されたフォントのすべてのパッチファイルから 省略することが望ましい場合もある。また、 フォント作成用のソースファイルから直接 IFT 形式に符号化する場合もある。 エンコーダーが上記の要件4を満たさないことを選択した場合でも、 拡張処理の全体を通じてフォントの動作の一貫性を保証する要件5を満たすことが強く推奨される。

7.1. 符号化に関する考慮事項

この節は非規範的である。

符号化処理の詳細はエンコーダーによって異なる場合があり、この文書の範囲外である。ただし、 この節では、エンコーダーの実装において 考慮する価値がある指針を示す。これらは、既存のフォントファイルの 外観と動作を再現しながら、 そのフォントのインクリメンタルなバージョンを生成する際に重要となる可能性がある。 この節で示す指針は、 この仕様の開発中にエンコーダーの実装を構築した経験に基づいている。 これは、執筆時点において、 § 7 符号化の要件1から4を満たし、 元のフォントのすべての機能と動作を維持する高性能な符号化を生成する方法についての 最善の理解を示したものである。

§ 6.2 テーブルキー方式のパッチについて

§ 6.2 テーブルキー方式のパッチは、一部のフォントテーブルの内容を変更し、 他のテーブルを変更せずに残すことができる。通常、パッチ対象の各テーブルは 特定のテーブル内容を基準とする必要があるが、他のテーブルは異なる内容を持っていてもよい。 したがって、§ 6.2 テーブルキー方式の パッチがグリフデータを含むテーブルを変更しない限り、 § 6.3 グリフキー方式のパッチと互換性を持ち、 部分 無効化のみを行うことができる(つまり、他の§ 6.2 テーブルキー方式のパッチを無効化するが、 § 6.3 グリフキー方式のパッチは無効化しない)。 さらに、2組の§ 6.2 テーブルキー方式のパッチは、 同じテーブルを一切変更しない場合、互いに独立して動作できる。 例えば、グリフテーブル以外のすべての データに§ 6.2 テーブルキー方式のパッチを使用し、 グリフテーブルには§ 6.3 グリフキー方式のパッチではなく、 別の§ 6.2 テーブルキー方式のパッチの集合を使用できる。 この場合、理論上はどちらも部分 無効化となり得る。これにより、 それぞれの集合内では依存関係を持ちながら、集合間では互いに独立した状態を維持できる。

§ 6.2 テーブルキー方式のパッチを適用すると、通常、 そのパッチが列挙されていた IFT または IFTX テーブルが変更され、 フォントをさらに拡張するための新しいパッチの集合が追加される。 これは、§ 6.2 テーブルキー方式のパッチ全体がグラフを構成することを意味する。 このグラフでは、分割された各フォントサブセットがノードであり、各パッチが辺である。 また、この種類のパッチは 通常、順番にダウンロードして適用されるため、 遅延に関するこのパッチ形式の性能にも影響する。

§ 6.3 グリフキー方式のパッチについて

§ 6.3 グリフキー方式のパッチは、他のパッチ形式とは大きく異なる。 第一に、§ 6.3 グリフキー方式のパッチは、 グリフのアウトラインデータを含むテーブルのみを変更できる。したがって、 § 6.3 グリフキー方式のみを使用するインクリメンタルフォントでは、 その他のすべてのフォントテーブルのデータを初期フォントファイルに含める必要がある。 第二に、§ 6.3 グリフキー方式のパッチは 無効化を行わないため、 互いに独立してダウンロードし、適用できる。この独立性により、複数のパッチを 並列にダウンロードでき、 無効化を行うパッチ形式と比較して、必要な往復回数を大幅に削減できる。

符号化に使用するパッチ形式の選択

すべての符号化では、使用するパッチ形式を1つ以上選択しなければならない。 § 6.2 テーブルキー方式のパッチは フォント内のあらゆる種類のデータにパッチを適用できるが、 この形式は少なくとも部分無効化を行うため、 必要なパッチの総数は、セグメント数に対して線形ではなく指数関数的に増加する。 § 6.3 グリフキー方式のパッチは、 アウトラインとバリエーション差分データの更新に限定されるが、 必要なパッチ数はセグメント数に比例して線形に増加する。

エンコーダーは、パッチ数に加えて、 一般的なコンテンツに必要なパッチを 取得するためのネットワーク往復回数も考慮するべきである。無効化を行うパッチ形式では、 パッチを順番に要求する必要がある。つまり、 あるコンテンツが複数のセグメントを必要とする場合、複数回のネットワーク往復が必要になる可能性がある。 一方、グリフキー方式のパッチは 無効化を行わないため、パッチを並列に取得でき、1回の往復で済む。

両形式の特性の両極端を考えると、§ 6.2 テーブルキー方式のパッチは、 アウトライン以外のデータが大量にあり、必要なパッチ数が 少ないフォントに最も適している。§ 6.3 グリフキー方式のパッチは、 データの大部分がグリフの アウトラインで構成されるフォントに最も適しており、既存の多くの CJK フォントがこれに該当する。

その中間に位置するフォントや、グリフデータを細粒度に分割する必要がある一方で、 他のテーブルのデータも 分割する必要がある場合には、§ 6.2 テーブルキー方式と § 6.3 グリフキー方式のパッチ形式を、 次のように組み合わせることが望ましい場合がある。

  1. すべてのテーブルキー方式のパッチエントリーを一方のマッピングテーブルに格納し、 すべてのグリフキー方式のエントリーをもう一方のマッピングテーブルに格納する。

  2. グリフキー方式のパッチが変更するテーブル (アウトライン、 バリエーション差分、およびグリフキー方式のパッチマッピングテーブル)を除く、 すべてのテーブルの更新にテーブルキー方式のパッチを使用する。これらのパッチでは、 パッチ数を適切に抑えるため、 少数の大きなセグメントを使用するべきである。

  3. グリフキー方式のパッチは、更新対象となる特定のグリフ ID を参照するため、 テーブルキー方式のパッチは、 元のフォントで使用されているグリフとグリフ ID の対応関係を変更してはならない。 変更すると、グリフキー方式のパッチに列挙されたグリフ ID が 不正確になる可能性があるためである。フォントサブセット化ツールでは、これは通常、 「retain glyph IDs」という名前のオプションとして提供される。

  4. 最後に、残りのテーブルの更新にグリフキー方式のパッチを使用する。この場合、 パッチ数を過度に増やすことなく、 より小さく細粒度のセグメントを利用できる。

多くのフォントは2つの 極端な特性の中間に位置するため、 パッチ形式を組み合わせた符号化は一般的に使用される方法になると予想される。

無効化を行うパッチによる往復回数の削減

無効化を行うパッチ形式のいずれかを使用する分割方法で、必要な往復回数を削減する方法の1つは、 複数のセグメントを一度に追加するパッチを提供することである (単一セグメント用のパッチに加えて)。例えば、4つのセグメントを持つフォントを考える。 A、B、C、Dである。パッチテーブルには、A、B、C、D、A + B、A + C、A + D、B + C、B + D、 および C + D を追加するパッチを列挙できる。これにより、 任意の2つのセグメントを1回の往復で追加できる。この方法の欠点は、 必要な一意のパッチ数がさらに 増加することである。

符号化されたパッチマッピング内のエントリー順序

§ 4.4 無効化するパッチの選択では、クライアントは 読み込んで適用するパッチを選択する際、候補が同順位の場合にパッチマップ内のエントリー順序を使用する。 クライアントは総転送量の削減を目指しているため、 複数のエントリーの共通部分の大きさが同じ場合、通常は 総転送サイズが最も小さいパッチを選択することがクライアントにとって有利である。 そのため、エンコーダーはパッチマップ内のエントリーを バイト単位のサイズが小さいものから大きいものへと並べるべきである。 これにより、クライアントが§ 4.4 無効化するパッチの選択に従う場合、小さいパッチを優先して選択し、性能を最大化できる。

パッチ数の管理

多数のセグメントとともに§ 6.2 テーブルキー方式のパッチを使用すると、 非常に多くのパッチが必要になる可能性があり、 2つの悪影響が生じる可能性がある。第一に、事前生成されたすべてのパッチを保存するために必要な ストレージ容量が望ましくないほど大きくなる可能性がある。第二に、 パッチ数が増えると一般に CDN キャッシュの効率が低下する。パッチ数が増えることは、 あるサブセットから別のサブセットに到達する経路の数が増えることを意味し、 ユーザーごとにアクセスするコンテンツに応じて異なる経路が選択されるためである。 事前生成されるパッチの総数を削減するためには、次のような方法がある。

  1. パッチグラフに最大深さを設定する。この上限に達したら、 元の完全なフォントの残りの部分をすべて 追加するパッチを適用する。これにより、一定数のセグメントが追加された後、 残りのフォント全体が読み込まれる。 グラフの深さを制限することで、深い階層におけるパッチ数の組合せ爆発を抑えられる。

  2. あるいは、深い階層でエンコーダーが複数のセグメントを単一のパッチに 統合し、各階層での分岐数を削減してもよい。

分割方法の選択

エンコーダーが行う必要のある最も重要かつ複雑な決定の1つは、 符号化するフォント内のデータをどのように分割するかである。 上記の説明ではセグメント数に注目したが、 インクリメンタルフォントの性能は、 セグメント内でのデータのグループ化に より大きく依存する。効率を最大化するため、エンコーダーは 一緒に使用されることが多いデータ(例えばコードポイント)を 同じセグメントにまとめる必要がある。これにより、クライアントがフォントを拡張する際に 読み込む不要なデータ量が削減される。エンコーダーは、 セグメントのサイズも決定しなければならない。小さなセグメントはパッチ数を増やし、 より多くのネットワークリクエストが必要になるためオーバーヘッドが増加するが、 一般に大きなセグメントと比較して、各セグメントに含まれる不要なデータは少なくなる。 コードポイントを分割する際には、 コードポイントの使用頻度に関するデータが分割方法の決定に役立つ。

一部のコードポイントには明らかに適切な分割方法があり、 少なくとも、どのコードポイントをまとめるかについてほとんど疑問の余地がない場合がある。 例えば、ラテンアルファベットの大文字と小文字は自然なグループを構成する。 他の場合はより複雑になる可能性がある。例えば、 中国語、日本語、韓国語はいくつかのコードポイントを共有しているが、 日本語で使用頻度が高いコードポイントが、 中国語では使用頻度が低い場合がある。1つの言語に合わせて符号化を最適化することを選択する場合もある。 別の方法として、折衷的な 符号化を生成することもできる。例えば、分割時に、 日本語、中国語、韓国語のすべてで使用頻度が高いコードポイントを1つの セグメントにまとめ、日本語と中国語でのみ使用頻度が高いコードポイントを別のセグメントにまとめる、といった方法である。 その後、1つの言語でのみ 使用頻度が高いコードポイントを通常の方法で処理できる。この方法ではセグメントの サイズが不均一になるが、 いずれかの言語の高頻度パッチを読み込んでも、使用頻度の低いグリフが一緒に読み込まれずに済む。

既定のレイアウト機能を含める

付録 A:既定の機能タグには、通常既定で使用されるレイアウト機能の一覧が まとめられている。この一覧の機能は通常、 シェーピングエンジンによって常に使用されるため、性能を最大化するには、エンコーダーは通常、 フォントの符号化においてこれらの機能を 任意にするべきではない。

機能的同等性の維持

§ 7 符号化で説明したように、エンコーダーは元のフォントの機能を 維持するべきである。フォントは複雑であり、 コードポイント間の相互作用を含むことが多いため、フォントの部分的なコピーで 機能的同等性を維持することは難しい場合がある。 次の2つの小節では、異なるパッチ形式を使用して機能的同等性を維持する方法を説明する。

テーブルキー方式のパッチ

§ 6.2 テーブルキー方式のパッチを作成する際、 機能的同等性を実現する方法の1つは、 既存のフォントサブセット化ツールの実装を利用して、元のフォントの機能を 維持するフォントサブセットを生成することである。その後、 これらのサブセットから IFT パッチを導出できる。

フォントサブセット化ツールは、入力フォントから、 目的のフォントサブセット定義に基づいてフォント サブセットを生成する。フォントを確実に サブセット化する手法はよく理解されており、複数のオープンソース実装が存在する (完全な形式的説明は この文書の範囲外である)。通常は到達可能性分析が行われ、 テーブル内のデータを フォントサブセット定義と照合して、その定義が対象とする任意のコンテンツから どの部分に到達可能かを確認する。 到達可能なデータは生成されるフォントサブセットに保持され、 到達不能なデータは削除してもよい。

次の擬似コードの例では、フォントサブセット化ツールを使用して、 テーブルキー方式のパッチのみを使用する IFT 符号化フォントを生成する。

# フォント(full_font)を、base_subset_def から始まり、
# subset_definitions のいずれも段階的に追加できるインクリメンタルフォントに符号化する。IFT 符号化フォントと
# 関連するパッチの集合を返す。
encode_as_ift(full_font, base_subset_def, subset_definitions):
  base_font = subset(full_font, base_subset_def)
  base_font, patches  = encode_node(full_font, base_font, base_subset_def, subset_definitions)
  return base_font, patches

# base_font を更新し、subset_definitions のいずれにも到達できるように、
# すべての IFT パッチマッピングを追加し、関連するパッチを生成する。
encode_node(full_font, base_font, cur_def, subset_definitions):
  patches = []
  next_fonts = []

  for each subset_def in subset_definitions not fully covered by cur_def:
    next_def = subset_def union cur_def
    next_font = subset(full_font, next_def)
    let patch_url be a new unique url

    add a mapping from, (subset_def - cur_def) to patch_url, into base_font
    next_font, patches += encode_node(full_font, next_font, next_def, subset_definitions)

    next_fonts += (next_font, next_def, patch_url)

  for each (next_font, next_def, patch_url) in next_fonts:
    patch = table_keyed_patch_diff(base_font, next_font)
    patches += (patch, patch_url)

  return base_font, patches

この実装例では、入力された基本サブセット定義とサブセット定義の一覧の 和集合が入力された完全なフォントを 完全に網羅し、使用するサブセット化ツールの実装がすべての機能を正しく維持する場合、 上記の実装は中立的な符号化に関する § 7 符号化の要件を満たすべきである。この基本的なエンコーダーの 実装は説明を目的とするものであり、 考えられるすべてのエンコーダー実装を代表することを意図していない。特に、 グリフキー方式のパッチの利用は 行われておらず、その方法も示されていない。ほとんどのエンコーダーは より複雑になり、以降の節で説明するものを含む 追加の要素を考慮する必要があると考えられる。

§ 6.3 グリフキー方式のパッチ

特に、コードポイントと機能タグによってパラメーター化されながら、 互いに独立して適用できるという性質のため、 § 6.3 グリフキー方式のパッチには追加の要件があり、 サブセット化ツールの実装を使用して直接導出することはできない。ただし、 このような実装は、この種類の パッチを生成する際に機能的同等性を維持するため、 エンコーダーが何を行う必要があるかを明確にする助けとなる。 特定のフォントサブセット定義を基準に フォントのサブセットを生成した結果を考える。 このフォント サブセット定義のグリフ閉包を、 サブセットに含まれるグリフの完全な集合として定義できる。これは、 サブセット化ツールが、記述されたコードポイントとレイアウト機能の 任意の組み合わせを描画するために必要と判断したグリフである。

この定義を使用すると、§ 6.3 グリフキー方式のパッチ全体に対するグリフ閉包要件は次のようになる。

サブセット化ツールが正確に動作すると仮定すると、グリフ閉包要件は、 動作の同等性に関する 要件から導かれる。あるフォントサブセット定義について、 サブセット化ツールはグリフ *i* をサブセットに含める一方、 § 6.3 グリフキー方式のパッチを生成するエンコーダーが、 その定義に対応するパッチの集合からグリフ *i* を省略すると仮定する。 サブセット化ツールの判断が 正しければ、その定義内のコードポイントと機能の ある組み合わせを描画する際に同等の動作を維持するには、そのグリフが存在しなければならない。 これは、インクリメンタルフォントが その組み合わせを描画する際に同等の動作をしないことを意味する。

したがって、グリフキー方式のパッチを使用する符号化を生成する際には、 エンコーダーはすべてのパッチ間で グリフ閉包要件を満たすようにグリフを分配する方法を決定しなければならない。 これは主に、セグメントに割り当てられたコードポイントを調べ、 そのセグメントに対応するパッチに追加する必要がある他のグリフを判断することである。 例えば、あるグリフの変種が、 コードポイントによってセグメントに含まれるグリフと置換される場合などである。 場合によっては、複数のセグメントが 読み込まれたときにのみグリフが必要になることがある。この場合、 そのグリフは、それらのセグメントのいずれかに対応するパッチに追加できる。 (これは合字や合成済みアクセント付き文字に該当する場合がある。) 最後に、セグメントの初期分析後、 2つ以上のセグメントのパッチを読み込む際に同じグリフが必要になる場合がある。 この状況に対処するための主な方法は5つある。

  1. 2つ以上のセグメントを統合し、単一のパッチに含めることができる。 これにより共通するグリフの重複を回避できるが、 セグメントのサイズは増加する。

  2. 共通するグリフを独自のパッチに配置し、 その共通パッチを必要とするセグメントのいずれかとともに 読み込むようにマッピングエントリーを設定できる。 例えば、'c' がセグメント 'a' と 'b' に必要な共通セグメントである場合、 次のマッピングエントリーを使用できる。

    • サブセット定義 a → セグメント a

    • サブセット定義 b → セグメント b

    • サブセット定義 a とサブセット定義 b の和集合 → セグメント c

  3. Unicode 異体字セレクターのように、 他の多くのコードポイントと組み合わせたときにグリフの置換を引き起こす 修飾子コードポイントが存在する場合がある。代替 グリフの数が多いため、修飾子コードポイントと適切な基本 コードポイントの両方が存在する場合にのみ読み込まれる独立したパッチに 格納することが望ましい。これは、 childEntryIndicesによる複数エントリーの一致を 使用して実現できる。設定方法の例については、 例2:子エントリーを持つグリフキー方式のパッチを参照されたい。

  4. あるいは、グリフデータを複数のパッチに重複して格納する代わりに、 それらのセグメントに対応する複数のパッチに 同じグリフを含めることもできる。

  5. 最後に、共通するグリフを初期フォントに移動できる。 これによりセグメントサイズの増加とグリフデータの重複を 回避できるが、初期フォントのサイズが増加する。また、 必要ない場合でもそのグリフのデータが 常に読み込まれることになる。これは、 多くのセグメントで必要となるグリフや、分割を複雑にしているグリフに有用な場合がある。

初期フォントでのデータの事前読み込み

場合によっては、初期ファイルにパッチを適用するオーバーヘッドを 回避することが望ましい。例えば、 企業のホームページで読み込まれるフォントが、そのページのコンテンツを すでに描画できることが望ましい場合がある。このようなファイルの主な利点は、 描画遅延を削減できることであり、1回の往復後にコンテンツを描画できる。

ダウンロードするフォントファイルにデータを含める方法は2つある。1つは、 インクリメンタルフォント全体を データが初期ファイルに含まれるように符号化することである。 そのようなデータは、パッチ適用後のフォントのどのバージョンでも常に利用可能となる。 これは、同じデータが多くの異なるセグメントで 必要になる場合に役立つ。

もう1つの方法は、すでにパッチが適用されたフォントをダウンロードすることである。 つまり、「基本」 ファイルにはほとんど、またはまったくデータを含めずにフォントを符号化し、 サーバー側でそのファイルにパッチを適用することで、 ダウンロードされるファイルにすでにパッチのデータが含まれるようにする。

事前読み込み済みのフォントが1つだけ必要な場合、これらの方法の結果はほぼ同等になるが、 最初の方法の方が 単純であり、場合によってはより特定の用途に適している。ただし、 複数の事前読み込み済みフォントが必要な場合、事前パッチ適用方式の方が 適していることが多い。最初の方法を使用する場合、 事前読み込み済みファイルごとに1つずつ、複数の符号化を生成する必要がある。 2番目の方法を使用する場合、 すべての事前読み込み済みファイルが引き続き同じパッチグラフ全体を共有するため、 パッチの保存に必要な総容量を 削減できるだけでなく、すべての事前読み込み済みファイルが 同じ集合から後続のパッチを選択するため、 CDN キャッシュの効率も向上する。

テーブルの順序

初期フォントファイルでは(woff2 で符号化されているかどうかにかかわらず)、 ファイル内の実際のテーブルのバイト列の順序を カスタマイズできる。エンコーダーは、マッピングテーブル(IFT と IFTX)および マッピングテーブルの復号に必要な追加のテーブル (cmap)を、できるだけファイルの先頭に配置することを検討するべきである。 これにより、最適化されたクライアントの実装は、 フォントデータ全体を受信する前にパッチマッピングにアクセスし、 必要なパッチのリクエストをより早く開始できる可能性がある。

同様に、テーブルキー方式のパッチには、パッチ対象の各テーブルに対して個別の Brotli ストリームがあり、この形式では これらのストリームをパッチファイル内の任意の順序で配置できる。 したがって、同じ理由により、エンコーダーはマッピングテーブルの更新と、 マッピングテーブルの復号に必要な追加のテーブルの更新を、 できるだけパッチファイルの先頭に配置することを検討するべきである。

入力 ID の符号化方式の選択

この仕様では、パッチ ID を URL テンプレートに埋め込むための2つの符号化方式をサポートする。 1つ目はbase32hexであり、 通常ファイルシステムに格納される事前生成パッチに適している。 Base32hex 符号化は、 0~9と A~V の文字のみを使用する。これらは一般的に使用されるすべてのファイルシステムで ファイル名として安全に使用でき、 大文字と小文字を区別しないことによる衝突の危険もない。 文字列はパディングなしで埋め込まれるため、この形式は確実に復号できず、 動的に生成されるパッチには 適さない場合がある。もう1つの符号化方式は base64urlであり、 URL または大文字と小文字を区別するファイルシステムへの埋め込みに適した Base64 符号化の変種である。この符号化方式では、 値を確実に復号できるように、 ID がパディング付きで埋め込まれる。

個々の文字選択子 d1 から d4 は、base32hex で符号化された ID のみに基づく。 これらは通常、 ID の符号化結果の末尾の文字に応じて関連するファイルを 1つ以上の階層のサブディレクトリに分散させ、 単一のファイルシステムディレクトリに保存されるファイル数を削減するために使用される。 整数 ID を使用する場合、これらは数字間で 均等に分布する傾向があるが、文字列 ID では不均等に分布したり、 一定の値になったりする可能性がある。文字列 ID とともに d1 から d4 を使用するエンコーダーは、ID 文字列の末尾が変化するように注意するべきである。 d1 から d4 と base64url で符号化された ID を組み合わせることは有効である。

8. プライバシーに関する 考慮事項

8.1. 文字集合からのコンテンツの推測

IFT は、ブラウザーがフォントを使用して描画しようとする文字集合に関する情報を、 ウェブフォントをホストするサーバーに公開する(詳細については、 § 4 フォントサブセットの拡張を参照)。

非常に大きな文字集合を使用する一部の言語(中国語や日本語など)では、 転送される総 バイト数が大幅に削減されるため、モバイルネットワークを含めて、 ウェブフォントが初めて実用的に利用できるようになる。しかし、これらの言語では、 悪意のあるフォントサーバーが個々のリクエストを分析し、 読まれているコンテンツの種類に関する 情報を取得することが可能である。要求される 文字が非常に珍しいものでない限り、この攻撃がどの程度実現可能であるか、 また悪用するために必要な計算の複雑さは明らかではない。

より具体的には、IFT フォントには Unicode コードポイントのグループの集合が含まれ、 描画されるコンテンツと交差するグループに対して リクエストが行われる。これにより、ホスティングサーバーは、 グループ内の少なくとも1つのコードポイントが必要であったことを知ることができるが、 グループ内のどのコードポイントが必要であったかという具体的な情報は含まれない。 これは機能的には既存の CSS Fonts 4 § 4.5 文字 範囲:unicode-range 記述子と非常によく似ており、プライバシーへの影響も同じである。 unicode-range のプライバシーへの影響に関する議論は、 CSS Fonts 4 仕様に記載されている。

コンテンツやサイトの制作者が IFT フォントの使用を選択する場合、 そのフォントを符号化した者と、 フォントの読み込み元のサービスの両方をある程度信頼する必要がある。 前述のように、IFT フォントの拡張中には、 描画されるコンテンツに関する一定量の情報が送信されるためである。 (両者の信頼には均衡関係があり、 後述するように、符号化に十分な配慮がなされているほど、 サービスに求められる信頼は小さくなる。) したがって、 プライバシーに配慮する必要がある場合は、IFT フォントをセルフホストすることが推奨される。 これにより、コンテンツに関する情報が 第三者に送信されることを防げる。さらに、そのような場合は、 異なるオリジンからのフォントの読み込みを許可しないように コンテンツセキュリティポリシーを設定することが推奨される。

8.2. IFT フォントの符号化とプライバシー

IFT フォントの符号化方法は、パッチファイルの転送から コンテンツに関する情報をどの程度推測できるかに大きく影響する。 この節では、IFT フォントの符号化時に行う選択が プライバシーに及ぼす影響を評価するための一般的な指針を示す。

IFT フォントは、関連する有効化条件を持つパッチの集合に分割される。 パッチのリクエストが 行われると、コンテンツにそのパッチの有効化条件と交差する何らかの要素が含まれていることが伝わる。 その 結果、フォント内の有効化条件の構造は、 符号化のプライバシー特性を評価するうえで 最も重要な側面となる。

フォントが対応する一意のコードポイント、機能、デザイン空間の各構成は、 それが存在するかどうかという潜在的な シグナルを提供する。有効化条件は論理和または論理積のいずれかである。 論理和条件では、 有効化によって条件内の個々の項目のうち少なくとも1つが 存在したことしか分からないため、不確実性が生じる。 一方、論理積条件のパッチでは、 個々の項目がすべて同時に存在する必要があるため、 不確実性は増加しない。

コードポイントや機能の通常の出現頻度は、 その存在によって伝わる情報量に影響する。 出現頻度の高い項目は、出現頻度の低い項目よりも伝える情報が少ない。 低頻度のコードポイントが存在すると、 考えられるコンテンツの集合が大幅に絞り込まれる。 大まかに言えば、これは低頻度の 項目を含む条件には、より大きく粒度の粗い条件を使用するべきであることを 意味する。

この仕様の開発中に実施されたシミュレーションでは、 (論理和条件に対する)グループの最小サイズを 4から7項目にすると、良好な曖昧性が得られることが分かった。 符号化でグループの最小サイズを使用することは、 性能の観点からも望ましい。粒度が細かすぎるパッチは過剰なオーバーヘッドを生じ、 性能を低下させるためである。 低頻度の項目が必要になることはまれであるため、それらを含むパッチに グループの最小サイズを適用しても、 全体的な性能への影響は小さい。全体的な性能は高頻度の項目によって左右される傾向がある。

エンコーダーは、生成した符号化内の各条件を評価し、その実効グループサイズを決定するべきである。 実効グループ サイズとは、その条件の発動に寄与する個々の項目(コードポイント、レイアウトタグ、 デザイン空間)にわたる 論理和の部分条件のうち、最も小さいものである。 プライバシーに配慮する必要がある用途向けの符号化では、 エンコーダーは すべての条件について、グループの最小サイズを少なくとも4から7にするべきである。 例えば、次の 場合を考える。

エンコーダーは、生成する符号化のプライバシーレベルを設定するための制御を提供するべきである。 用途によって 必要なレベルが異なるためである。例えば、HTTPS を介してセルフホストするために符号化されたフォントでは、 プライバシー上の 懸念は生じないが、共通の第三者フォントサービスでホストすることを想定した IFT フォントでは異なる。 プライバシーへの配慮がそれほど 必要でない場合、エンコーダーは推奨されるグループの最小サイズに違反する最適化を 選択してもよい。例えば、 任意のレイアウト機能のデータを追加する条件を設けると、 実効グループサイズが1になる場合がある。

エンコーダーが、特定の符号化でプライバシーを保護できる程度について このような柔軟性を提供する場合、 符号化を行うユーザーが適切な選択をできるよう、 文書やユーザーインターフェイスで、この節の情報を十分に伝えることが推奨される。 同様に、IFT フォントをホストするサイトは、 独自のフォントを符号化する場合や、第三者から符号化済みフォントを取得する場合に、 プライバシーを考慮することが推奨される。

8.3. オリジンごとの制限によるフィンガープリンティングの防止

[css-fonts-4]で要求されるように:

「ウェブフォントは、 @font-face 規則に関連付けられているか、 FontFaceSet を所有する文書以外の文書からアクセス可能であってはならない。デバイス上の他のアプリケーションは、 ウェブフォントに アクセスできてはならない。」— CSS Fonts 4 § 10.2 ウェブフォント

IFT フォントは CSS では通常のフォントと同様に扱われるため(§ 2 オプトインの仕組み)、 これらの要件が適用され、オリジン間での 情報漏えいが防止される。

フォントパレット値にも同様の要件が適用される。

「制作者が定義した フォントカラーパレットは、それを参照する文書でのみ利用可能でなければならない。 制作者が定義したカラーパレットを 参照元の文書以外で使用すると、あるページの内容が 他のページに影響を与えられるようになるため、セキュリティ上の情報漏えいとなる。 攻撃者はこれを攻撃手段として利用できる。」— CSS Fonts 4 § 9.2 ユーザー定義のフォントカラーパレット:@font-palette-values 規則

9. セキュリティに関する 考慮事項

セキュリティ上の懸念の1つは、IFT フォントによって パッチに対する大量のネットワークリクエストが発生する可能性があることである。 これにより、クライアントやパッチをホストするサービスに 問題が生じる可能性がある。IFT 仕様には、過剰な リクエスト数を制限するための対策がいくつか含まれている。

  1. § 4 フォントサブセットの拡張:同じ URL を複数回 リクエストすることを禁止し、拡張処理中に 発行できるリクエストの総数に制限を設ける。

  2. パッチファイルを読み込む:実装する ウェブブラウザーで[FETCH]を使用することを指定し、 CORS 設定を初期フォントの 読み込みと一致させる。その結果、ホスティングサービスが適切な アクセス制御ヘッダーによって明示的に許可しない限り、 パッチファイルへのクロスオリジンリクエストは禁止される。

10. 変更点

2025年11月18日付 W3C 勧告候補草案以降 (コミット履歴を参照):

2025年7月31日付 勧告候補スナップショット以降 (コミット履歴を参照):

2025年7月15日付 作業草案以降 (コミット履歴を参照):

2025年2月20日付 作業草案以降( コミット履歴を参照):

2024年7月9日付 作業草案以降( コミット履歴を参照):

付録 A:既定の機能タグ

この付録は非規範的である。ほとんどのシェーピングエンジン実装で 既定で使用されると考えられるレイアウト機能の 一覧を示す。この一覧は、次の資料に基づいて作成された。

シェーピングエンジンで既定で使用されるレイアウト機能

タグ 名前
abvf 基底上方形
abvm 基底上方のマーク配置
abvs 基底上方の置換
akhn アカンド
blwf 基底下方形
blwm 基底下方のマーク配置
blws 基底下方の置換
calt 文脈依存の代替字形
ccmp グリフの合成/分解
cfar Ro の後の結合形
chws 文脈依存の半角スペーシング
cjct 結合形
clig 文脈依存の合字
cswh 文脈依存のスワッシュ
curs 筆記体の配置
dist 字間距離
dnom 分母
dtls 点なし字形
fin2 終端形 #2
fin3 終端形 #3
fina 終端形
flac 平坦化されたアクセント字形
frac 分数
half 半形
haln ハラント形
init 語頭形
isol 独立形
jalt 両端揃え用の代替字形
kern カーニング
liga 標準合字
ljmo 先頭ジャモ形
locl 地域別字形
ltra 左から右への代替字形
ltrm 左から右への鏡像字形
mark マーク配置
med2 中間形 #2
medi 中間形
mkmk マーク間の配置
mset 置換によるマーク配置
nukt ヌクタ形
numr 分子
pref 基底前方形
pres 基底前方の置換
pstf 基底後方形
psts 基底後方の置換
rand ランダム化
rclt 必須の文脈依存代替字形
rkrf ラカール形
rlig 必須合字
rphf レフ形
rtla 右から左への代替字形
rtlm 右から左への鏡像字形
rvrn 必須のバリエーション代替字形
ssty 数式用スクリプトスタイルの代替字形
stch 伸長グリフの分解
tjmo 末尾ジャモ形
valt 縦方向メトリクスの代替
vatu ヴァットゥ異体字
vchw 縦書きの文脈依存半角スペーシング
vert 縦書き
vjmo 母音ジャモ形
vkrn 縦書きカーニング
vpal プロポーショナルな縦方向メトリクスの代替
vrt2 縦書き用の代替字形と回転
vrtr 回転用の縦書き代替字形

付録 B:拡張アルゴリズムの実行例

この付録は非規範的である。一般的な IFT フォントが § 4.3 インクリメンタルフォント拡張アルゴリズムによって処理される方法の例を示す。

例1:テーブルキー方式とグリフキー方式の パッチ

この例では、IFT フォントに§ 6.2 テーブルキー方式と§ 6.3 グリフキー方式の両方のパッチが含まれる。

初期フォント:次の IFT および IFTX パッチマッピングを含む。注記:サブセット定義で機能とデザイン空間の 集合が指定されていない場合、 既定で空集合となる。

テーブル = "IFT " 互換性 ID = 0x0000_0000_0000_0001
サブセット定義 URL 形式番号
code points: { 'a', 'b', ..., 'z' }
//foo.bar/01.tk 2、テーブルキー方式 - 部分無効化
code points: { 'A', 'B', ..., 'Z' }
//foo.bar/02.tk 2、テーブルキー方式 - 部分無効化
code points: { '0', '1', ..., '9' }
//foo.bar/03.tk 2、テーブルキー方式 - 部分無効化
code points: { 'a', 'b', ..., 'z',
               'A', 'B', ..., 'Z' }
//foo.bar/04.tk 2、テーブルキー方式 - 部分無効化
code points: { 'a', 'b', ..., 'z',
               'A', 'B', ..., 'Z',
               '0', '1', ..., '9' }
//foo.bar/05.tk 2、テーブルキー方式 - 部分無効化

テーブル = "IFTX" 互換性 ID = 0x0000_0000_0000_0002
サブセット定義 URL 形式番号
code points: { 'a', 'b', ..., 'm' }
//foo.bar/01.gk 3、グリフキー方式
code points: { 'n', 'o', ..., 'z' }
//foo.bar/02.gk 3、グリフキー方式
code points: { 'A', 'B', ..., 'M' }
//foo.bar/03.gk 3、グリフキー方式
code points: { 'N', 'O', ..., 'Z' }
//foo.bar/04.gk 3、グリフキー方式
code points: { '0', '1', ..., '9' }
//foo.bar/05.gk 3、グリフキー方式

最適化された拡張の例

注記:この実行例は、 対象サブセット定義に合わせてフォントを拡張する際に必要な往復回数を削減することを目指す、 最適化されたクライアントでの実装として説明されている。 この最適化された実行は拡張アルゴリズムに完全に適合しているが、 一部の URL(グリフキー方式の URL)の読み込みを、拡張アルゴリズムで指定された時点より 早く開始する。これは、それらのパッチが 先行するテーブルキー方式のパッチによって無効化されないため許可される。

入力:

反復1:

反復2:

反復3:

反復4:

例2:子エントリーを持つグリフキー方式の パッチ

この例では、IFT フォントに、子エントリーを利用して UVS置換に対応するパッチを正しく含める § 6.3 グリフキー方式のパッチの集合が含まれる。 基本グリフの各集合には、異体字セレクターによって 置換される代替グリフの集合がある。これらは別のパッチに保持される。 代替グリフのパッチは、子エントリーを介して、 基本グリフと異体字セレクターが同時に存在する場合にのみ読み込まれるように設定される。

初期フォント:次の IFT パッチマッピングを含む。注記:サブセット定義でコードポイント、機能、 デザイン空間、または子エントリーの集合が指定されていない場合、 既定で空集合となる。

テーブル = "IFT " 互換性 ID = 0x0000_0000_0000_0001
サブセット定義 URL 形式番号 無視するか? 注記
code points:
  { 'a', 'b', ..., 'm' }
//foo.bar/01.gk 3、グリフキー方式 いいえ
code points:
  { 'n', 'o', ..., 'z' }
//foo.bar/02.gk 3、グリフキー方式 いいえ
code points: { VS1 }
N/A 3、グリフキー方式 はい
child entries: [0, 2],
match mode: conjunctive
//foo.bar/03.gk 3、グリフキー方式 いいえ VS1 によって有効化される {'a', ..., 'm'} の代替グリフを含む
child entries: [1, 2],
match mode: conjunctive
//foo.bar/04.gk 3、グリフキー方式 いいえ VS1 によって有効化される {'n', ..., 'z'} の代替グリフを含む

拡張例1

入力:

反復1:

反復2:

拡張例2

入力:

反復1:

反復2:

反復3:

適合性

文書の 規約

適合性要件は、 記述的な表明と RFC 2119 の用語を組み合わせて表現される。 規範的な部分におけるキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、 「MAY」、および「OPTIONAL」は、 この文書の規範的な部分では、 RFC 2119 に記載された意味で解釈しなければならない。 ただし、読みやすさのため、 この仕様ではこれらの単語をすべて大文字で表記するわけではない。

この仕様のすべての文章は、 明示的に非規範的と示された節、例、注記を除き、規範的である。[RFC2119]

この仕様の例は、「例えば」という語で導入されるか、 class="example"を使用して 規範的な文章から区別される。 次のように示される。

これは参考情報としての例である。

参考情報としての注記は「注記」という語で始まり、 class="note"を使用して 規範的な文章から区別される。 次のように示される。

注記:これは参考情報としての注記である。

適合する アルゴリズム

アルゴリズムの一部として命令形で記述された要件 (例えば「先頭の空白文字をすべて除去する」 または「false を返し、これらの手順を中止する」)は、 アルゴリズムの導入時に使用された キーワード(「must」、「should」、「may」など)の意味で 解釈しなければならない。

アルゴリズムまたは特定の手順として記述された適合性要件は、 最終的な結果が同等である限り、 どのような方法で実装してもよい。 特に、この仕様で定義されるアルゴリズムは、 理解しやすさを目的としており、 高性能であることを意図していない。 実装者には最適化が推奨される。

索引

この仕様で定義される 用語

参照によって 定義される用語

参考文献

規範参考文献

[CSS-FONTS-4]
Chris Lilley. CSS Fonts モジュール レベル4. 2026年9月13日. WD. URL: https://www.w3.org/TR/css-fonts-4/
[FETCH]
Anne van Kesteren. Fetch 標準. 現行 標準. URL: https://fetch.spec.whatwg.org/
[I18N-GLOSSARY]
Richard Ishida; Addison Phillips. 国際化 用語集. 2024年10月17日. NOTE. URL: https://www.w3.org/TR/i18n-glossary/
[ISO14496-22]
情報技術 — 音響映像 オブジェクトの符号化 — 第22部:オープンフォント形式. 2026年7月. URL: https://www.iso.org/standard/14496-22
[OPEN-TYPE]
OpenType 仕様. 2024年5月. 注記. URL: https://learn.microsoft.com/en-us/typography/opentype/spec
[PFE-report]
Chris Lilley. プログレッシブフォント拡充:評価 報告書. 2020年10月15日. 注記. URL: https://www.w3.org/TR/PFE-evaluation/
[RFC2119]
S. Bradner. RFC で要件レベルを 示すために使用するキーワード. 1997年3月. 現行のベストプラクティス. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC4648]
S. Josefsson. Base16、Base32、Base64 データ 符号化. 2006年10月. 標準案. URL: https://www.rfc-editor.org/info/rfc4648/
[RFC7932]
J. Alakuijala; Z. Szabadka. Brotli 圧縮データ 形式. 2016年7月. 参考情報. URL: https://www.rfc-editor.org/info/rfc7932/
[Shared-Brotli]
J. Alakuijala; et al. 共有 Brotli 圧縮データ形式. 2025年2月. インターネット草案. URL: https://datatracker.ietf.org/doc/html/draft-vandevenne-shared-brotli-format-15
[UNICODE]
Unicode 標準. URL: https://www.unicode.org/versions/latest/
[UTF-8]
F. Yergeau. UTF-8、ISO 10646 の変換形式. 2003年11月. インターネット標準. URL: https://www.rfc-editor.org/info/rfc3629/
[WHATWG-URL]
Anne van Kesteren. URL 標準. 現行標準. URL: https://url.spec.whatwg.org/
[WOFF2]
Vladimir Levantovsky. WOFF ファイル形式 2.0. 2024年8月8日. REC. URL: https://www.w3.org/TR/WOFF2/

非規範参考文献

[CSS-CONDITIONAL-5]
Chris Lilley; et al. CSS 条件付き規則モジュール レベル5. 2025年10月30日. WD. URL: https://www.w3.org/TR/css-conditional-5/
[ENABLING-TYPOGRAPHY]
John Hudson. タイポグラフィの実現: OpenType レイアウトの一般モデルに向けて. 2014年4月15日. 注記. URL: https://www.tiro.com/articles/enabling-typography
[RFC9113]
M. Thomson, Ed.; C. Benfield, Ed.. HTTP/2. 2022年6月. 標準案. URL: https://httpwg.org/specs/rfc9113.html
[RFC9114]
M. Bishop, Ed.. HTTP/3. 2022年6月. 標準案. URL: https://httpwg.org/specs/rfc9114.html
[WOFF]
Jonathan Kew; Tal Leming; Erik van Blokland. WOFF ファイル形式 1.0. 2012年12月13日. REC. URL: https://www.w3.org/TR/WOFF/