1. はじめに
この節は規範的ではありません。
増分フォント転送(IFT)は、ウェブ上のリモートフォント(または「ウェブフォント」)の レイテンシーを改善する技術です。この技術がなければ、ブラウザーはそのフォントを使用して 文字をレンダリングする前に、フォントの最後の1バイトまですべてダウンロードする必要があります。IFT を使用すると、 ブラウザーはファイル内のバイトの一部のみをダウンロードできるため、 ブラウザーがフォントを必要としていることを認識してから、そのフォントで必要なテキストを レンダリングできるようになるまでの体感レイテンシーが短縮されます。従来のフォントサブセット化手法とは異なり、増分 フォント転送では、セグメント間のレイアウト規則のエンコーディングが保持されます(プログレッシブフォント拡充:評価報告書 § fail-subset)。
WebFonts の成功は均等に行き渡っているわけではありません。この仕様により、低速なネットワーク、 非常に大きなフォント、または複雑なサブセット化要件のために現在は WebFonts を使用できない場所でも、 WebFonts を使用できるようになります。たとえば、WOFF 2 [WOFF2] を使用しても、CJK 言語用フォントは実用上大きすぎる場合があります。
1.1. 技術的動機:評価報告書
この仕様につながった調査については、プログレッシブフォント拡充:評価報告書 [PFE-report] を参照してください。
1.2. 概要
増分フォントとは、 増分機能を含むように再形式化された通常の OpenType フォントであり、その機能の一部は2つの追加テーブルによって実現されます。 これらの新しいテーブルを使用すると、パッチを読み込んで適用することで、 フォントを拡充できます(たとえば、より多くのコードポイントをカバーできます)。
IFT 技術は主に4つの部分で構成されます:
-
§ 4 フォントサブセットの拡張:クライアントが パッチを選択して適用するために使用するアルゴリズムを提供します。
-
§ 5 フォント形式の拡張:フォントに適用可能な パッチの一覧を含む新しいテーブルを定義します。
-
§ 6 フォントパッチ形式:使用できる2種類のパッチを 定義します。一方は「汎用」バイナリパッチで、もう一方は グリフデータを保存するフォント形式に固有のものです。
-
§ 7 エンコーディング:増分フォントを構成するフォントと 関連パッチを作成します。
大まかに言えば、増分 フォントは次のように使用されます:
-
クライアントは初期フォントファイルをダウンロードします。このファイルには、 完全版フォントのデータの初期サブセットと、フォントを拡張するために使用できる パッチの集合を記述する埋め込みデータが含まれます。
-
レンダリングするコンテンツに基づいて、クライアントはパッチを選択し、ダウンロードし、 適用して、追加の文字、レイアウト機能、および/またはバリエーション空間をカバーするように フォントを拡張します。この手順は、新しいコンテンツが生じるたびに 繰り返されます。
1.3. 増分フォントの作成
増分フォントを作成する最も一般的な方法は、既存のフォントを変換して、 この仕様で定義される増分エンコーディングを使用するようにすることだと想定されます。大まかには、 既存のフォントを増分形式へ変換する手順は次のようになります:
-
初期サブセットの内容を選択します。これはクライアントが読み込む 初期フォントファイルに含まれ、通常は常に必要になると予想される元のフォントの データで構成されます。
-
パッチの種類を1つまたは複数選択します。パッチの種類ごとに特性が異なるため、 ユースケースに応じて異なる種類、または場合によっては2種類の組み合わせが 必要になることがあります。
-
フォントのセグメント化方法を選択します。個々のセグメントは、クライアントによって パッチを使用して基本サブセットへ追加されます。適切なセグメント化を選択することは、 効率的なエンコーディングを作成するうえで最も重要な要素の1つです。
-
これらの選択に基づいてパッチの集合を生成します。各パッチは、初期フォントファイル または以前のパッチを基準として、特定のセグメントのデータを追加します。
-
初期サブセットとパッチマッピングを含む初期フォントファイルを 生成します。このマッピングには、利用可能なすべてのパッチファイル、それらが存在する URL、 およびパッチがフォントへ追加するデータに関する情報が一覧表示されます。
注:これは増分フォント作成についての 非常に簡略化された説明です。エンコーディングの生成とエンコーディング要件についての より詳細な説明は、§ 7 エンコーディングの節にあります。
1.4. パフォーマンス上の考慮事項と増分フォント転送の使用
増分転送の使用が常に有益とは限らず、フォント、ネットワーク、およびレンダリングされる コンテンツの特性によって異なります。この節では、増分転送を使用すべき時期を判断するための 非規範的な指針を示します。
増分フォントでは、複数のパッチの読み込みが並列に開始されることが一般的です。そのため、 パフォーマンスを最大化するには、増分フォントを提供する際に、 多重化に対応した HTTP サーバー([rfc9113] または [rfc9114] など)を使用することが推奨されます。
フォントを増分読み込みすることには、フォント全体を読み込む場合と比較して、 基本的なパフォーマンス上のトレードオフがあります。単純化して言えば、増分転送では 転送されるバイト数を減らせる一方で、ネットワークリクエストの総数が増加したり、 リクエスト処理のレイテンシーが増加したりする可能性があります。一般に、 転送バイト数の削減によるレイテンシー短縮が、増分転送方式によって追加される レイテンシーを上回る場合に、増分フォント転送は有益です。
最初に考慮すべき要素は、レンダリングするコンテンツの言語です。評価報告書には、 3つの言語カテゴリにわたって増分フォント転送をシミュレートした結果が含まれています (プログレッシブフォント拡充:評価報告書 § langtype)。言語カテゴリごとに想定される増分フォント転送のパフォーマンスについては、 その結論である プログレッシブフォント拡充:評価報告書 § conclusions を参照してください。
次に、フォントのどの程度が必要になると予想されるでしょうか。コンテンツをレンダリングするために フォントの大部分が必要になると予想される場合、増分フォント転送が有益である可能性は低くなります。 しかし、多くの場合はフォントの一部のみが必要になると予想されます。たとえば:
-
フォントが複数の言語をサポートしているが、ユーザーがその一部の言語でのみ コンテンツをレンダリングすると予想される場合。
-
レンダリングするコンテンツが、フォント内の全文字のうち小さなサブセットしか 使用しない場合。これは中国語、日本語、韓国語、絵文字、およびアイコンフォントで よく見られます。
-
レンダリングされるテキストが少量のみである場合。たとえば、見出しにのみ使用される フォントです。
増分転送の代替方法として、フォントを別個のサブセット(通常は用字系ごと)に分割し、 @font-face の unicode range 機能を使用して必要なサブセットのみを読み込む方法があります。 ただし、異なるサブセット内の文字間にレイアウト規則がある場合、この方法は一部のコンテンツの レンダリングを変更することがあります(プログレッシブフォント 拡充:評価報告書 § fail-subset)。増分フォント転送は、元のフォントとそのすべての レイアウト規則を包含できるため、この問題の影響を受けません。
1.4.1. ネットワークリクエスト数の削減
前節で説明したように、増分フォント転送の最も基本的な実装では、 従来のフォント読み込みに比べて、リクエスト総数が増加する傾向があります。各拡充では 通常、少なくとも1回のラウンドトリップ時間が必要になるため、リクエストが多すぎると パフォーマンスへ悪影響を及ぼす可能性があります。利用可能なパッチ形式と、 パッチマッピングに含まれる情報量によっては、クライアントが、 現在は不要だが将来必要になると予想されるコードポイント用のパッチを先行して リクエストすることがあります。この機能を実装が適切に使用することで、 リクエスト総数の削減に役立ちます。評価報告書では、基本的な文字頻度に基づく コードポイント予測方式の パフォーマンスをテストし、全体的なパフォーマンスが改善されることを確認しています。
2. オプトイン機構
ウェブページは、''@font-face'' ブロック内で CSS のフォント技術キーワード
(CSS Fonts 4 § 11.1
フォント技術)を使用することにより、フォントの増分転送へオプトインできます。
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 range は、完全に拡張されたフォントのカバー範囲と一致するように 設定するべきです。これにより、必要なコードポイントをフォントがまったくサポートしていない場合に、 クライアントが 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 に
tech(incremental, color-COLRv1) を持つ URL と
tech(incremental, color-COLRv0) を持つ別の URL を含めることができます。
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 への マッピングの集合をエンコードします。パッチマップテーブルは、パッチマップ エントリの一覧をエンコードし、各エントリにはキーと値があります。エントリのキーは、 エントリのカバー範囲、すなわちどのサブセット定義が一致するかに関する情報を定義します。 値は、エントリが一致したときに適用すべきパッチに関する情報を指定します。 パッチマップ エントリの概要:
| キー | 値 |
|---|---|
|
パッチマップ形式の詳細については、§ 5 フォント形式の拡張を参照してください。
3.4. データ型の説明
この仕様の残りの部分にあるエンコード済みデータ構造は、 OpenType 仕様 § otff#data-typesで定義されるデータ型を使用して記述されます。OpenType のほかの部分と同様に、 すべてのフィールドは「ビッグエンディアン」のバイト順を使用します。
4. フォントサブセットの拡張
この節では、追加のコードポイント、レイアウト機能、および/またはデザイン空間をカバーするように、 クライアントが増分フォントサブセットを拡張するために使用するアルゴリズムを 定義します。これは反復アルゴリズムであり、次の処理を繰り返します:
-
フォントサブセットのパッチマッピングを、利用可能なパッチの一覧へ解析します。
-
利用可能なパッチのいずれかが、レンダリング対象のコンテンツと一致するかを確認します。
-
利用可能なパッチを1つ選択し、読み込み、適用します。
この処理は、関連するパッチが残らなくなるまで繰り返されます。パッチの適用によって、 フォントファイルに埋め込まれたパッチマッピングが変更される可能性があるため、 各反復では現在のフォントサブセット内のパッチマップが再解析され、残っているパッチが確認されます。 したがって、各反復におけるフォントサブセットが利用可能なパッチに関する信頼できる唯一の情報源となり、 拡充処理の現在の状態を完全に内包します。
4.1. パッチの無効化
フォントサブセットに埋め込まれたパッチマッピングは、各パッチの無効化モードをエンコードします。 パッチの無効化モードは、そのパッチを適用した後に有効でなくなるほかのパッチを示します。 この無効化モードは、互換性のあるパッチを判定するために拡張アルゴリズムで使用され、 選択順序に影響します。パッチ適用時のパッチの有効性は、 § 5.3 パッチマップテーブルの互換性 ID によって強制されます。 各パッチには互換性 ID がエンコードされており、そのパッチを一覧に含める § 5.3 パッチマップテーブルの互換性 ID と一致する必要があります。
無効化モードは3つあります:
-
完全 無効化:このパッチが適用されると、フォントサブセットに現在一覧表示されている ほかのすべてのパッチが無効化されます。'IFT ' と 'IFTX' の両方の § 5.3 パッチマップテーブル内の互換性 ID が変更されます。
-
部分 無効化:このパッチが適用されると、同じ§ 5.3 パッチマップテーブル内のほかのすべてのパッチが無効化されます。 このパッチを含む§ 5.3 パッチマップテーブルの 互換性 ID のみが変更されます。
-
無効化 なし:このパッチを適用してもほかのパッチは無効化されません。 'IFT ' および 'IFTX' の§ 5.3 パッチマップテーブルの 互換性 ID は変更されません。
特定のパッチの無効化モードは、その形式番号にエンコードされます。形式番号は § 6.1 形式の概要で確認できます。
4.2. 既定のレイアウト機能
ほとんどのテキストシェーパーには、常に有効であり、したがって増分読み込みされるフォントでも 常に必要となるレイアウト機能の 集合があります。付録 A:既定の機能タグには、執筆時点で一般的な シェーパー実装において既定で必要であることが判明している機能の一覧がまとめられています。 拡張アルゴリズムへの入力としてフォントサブセット定義を 構成する際、クライアントは通常、付録 A:既定の機能タグにある すべての機能をサブセット定義に含めるべきです。ただし、場合によっては、 使用される特定のシェーパーが付録 A:既定の機能タグにある 一部の機能を使用しないことをクライアントが把握しており、未使用の機能をサブセット定義から 除外することがあります。
4.3. 増分 フォント拡張アルゴリズム
次のアルゴリズムは、追加のコードポイント、レイアウト機能、および/またはデザイン空間を カバーするように、クライアントが増分フォントサブセットを拡張するために使用します。このアルゴリズムは、 必要に応じてパッチを読み込みながら、フォントへ1つずつ増分的に選択して適用します。 ネットワークのラウンドトリップを最小限に抑える重要な最適化として、最終的に必要になる すべてのパッチの読み込みを開始できます。これには2つの形式があります:
-
第1に、パッチマッピングエントリには 複数の URL 文字列を列挙できます。最初の URL 文字列より後にある各 URL 文字列も、 将来の反復で必要になるため読み込むべきです。
-
第2に、§ 4.1 パッチの無効化を使用して、 どのパッチの読み込みを開始できるかを判定します。対象サブセット定義と一致し、 § 4.1 パッチの無効化に従って次に適用されるパッチによって 無効化されないパッチは、将来の反復で必要になると予想できます。
増分フォントサブセットを拡張する
このアルゴリズムへの入力は次のとおりです:
-
initial font URL:font subsetの派生元となった初期増分フォントの 場所を識別するURL。
-
target subset definition:クライアントがfont subsetを拡張して カバーさせたいフォントサブセット定義。
このアルゴリズムの出力は次のとおりです:
-
extended font subset:font subsetの拡張版。 増分 フォントである場合も、そうでない場合もあります。
アルゴリズム:
-
extended font subsetをfont subsetに設定します。
-
extended font subsetから、'IFT ' および 'IFTX'(存在する場合)のマッピング テーブルを 読み込みます。両方のテーブルは§ 5.3 パッチマップテーブルとして 形式化されています。§ 5.3 パッチマップテーブルの要件に従って 有効であることを確認します。いずれかのテーブルが無効な場合は、 エラーを処理するを呼び出します。 extended font subsetに 'IFT ' テーブルがない場合、それは 増分 フォントではなく、拡張できないため、extended font subsetを返します。
-
'IFT ' の互換性 ID が 'IFTX' の互換性 ID と等しい場合、これはエラーです。 エラーを処理するを呼び出します。
-
テーブル 'IFT ' および 'IFTX'(存在する場合)のそれぞれについて: 形式 1 パッチマップを解釈するまたは 形式 2 パッチマップを解釈するを 呼び出して、テーブルをエントリ一覧へ変換します。返されたエントリ一覧を連結して 単一の一覧entry listにします。
-
entry list内の各entryについて、entryと target subset definitionを入力としてエントリの交差を確認するを呼び出し、 false が返された場合はentry listからentryを削除します。 さらに、このアルゴリズムの実行中に以前読み込まれて適用されたパッチ URL 文字列を持つ エントリもentry listから削除します。
-
entry listが空の場合、拡張処理は完了しているため、 extended font subsetを返します。
-
entry listのエントリを、各エントリのパッチ形式の無効化モードに基づいて3つの一覧へ分類します: full invalidation entry list、partial invalidation entry list、 およびno invalidation entry list。
-
次の手順で1つのentryを選択します:
-
full invalidation entry listが空でない場合は、含まれるエントリから 正確に1つを選択します。単一のエントリを選択するには、 § 4.4 無効化パッチの選択の基準に従います。
-
そうでなく、partial invalidation entry listが空でない場合は、 含まれるエントリから正確に1つを選択します。単一のエントリを選択するには、 § 4.4 無効化パッチの選択の基準に従います。
-
それ以外の場合は、パッチマップ内で最初に一覧表示される no invalidation entry listのエントリを選択します。 § 5.3.1 パッチマップテーブル:形式 1では、 エントリインデックスが最も小さいエントリです。 § 5.3.2 パッチマップテーブル:形式 2では、 entries配列内で最初に現れるエントリです。 IFT テーブルと IFTX テーブルの両方のエントリが候補である場合、 IFT 内のすべてのエントリが IFTX 内のエントリより前にあるものと見なされます。
-
-
initial font URLを初期フォント URL、entry内の最初のパッチ URL 文字列を パッチ URL 文字列として、パッチファイルを読み込むを呼び出し、 patch fileの読み込みを開始します(以前に開始されていない場合)。 entry内にほかの URL 文字列がある場合、同じ手順を使用してそれらの読み込みも 開始します。これらはこのアルゴリズムの将来の反復で使用される可能性があります。 さらに、クライアントは、entryによって無効化されないentry list内の任意のエントリについて、 同じ手順を使用して任意で読み込みを開始できます。このアルゴリズムの1回の実行中に、 クライアントが読み込んで適用できるパッチ総数は、次のように制限されます:
このアルゴリズムの1回の呼び出し中に読み込んで適用できます。いずれかの数を超えた場合は エラーであり、エラーを 処理するを呼び出します。
-
patch fileの読み込みが完了したら、§ 6 フォントパッチ形式から、entry内のパッチ形式に対応する適切な適用 アルゴリズムを使用し、entryのパッチ URL 文字列および互換性 ID を使用して patch fileをextended font subsetへ適用します。 patch fileの読み込みでエラーが発生した場合は、 エラーを処理するに従って処理します。
-
手順2へ戻ります。
注:手順9では、クライアントは、現在選択されている エントリによって無効化されないパッチの読み込みを任意で並列に開始できます。このようなパッチは、 無効化されないため、後の反復でほぼ常に必要になります。また、それらを並列に読み込むことで ラウンドトリップがなくなり、パフォーマンスが大幅に向上します。この方法で読み込みを開始する場合、 リクエスト開始の順序は手順8で指定された順序に従う必要があります。
注:交差する残りのエントリがすべて 無効化なしエントリである場合、手順5の交差確認を後続の反復で繰り返す必要はありません (無効化なしパッチは、適用時に自身のエントリが削除される以外、 利用可能なパッチ一覧を変更しないためです)。さらに最適化として、クライアントは、 交差する残りの無効化なしエントリのパッチ適用を単一のバッチ処理として実行できます。 グリフキー方式パッチの性質上、複数のパッチを順次適用した最終結果を1回の処理で 構築することは容易です。この方法により、個々のパッチごとに新しい glyf/loca/CFF/CFF2 テーブルを繰り返し再合成する必要がなくなり、 必要な計算量の総量を大幅に削減できます。
エントリの交差を確認する
このアルゴリズムへの入力は次のとおりです:
-
mapping entry:パッチマップエントリ。
-
subset definition:フォントサブセット定義。
このアルゴリズムの出力は次のとおりです:
-
intersects:subset definitionがmapping entryと 交差する場合は true、それ以外の場合は false。
アルゴリズム:
-
subset definition内の各集合(コードポイント、機能タグ、 デザイン空間)について、その集合がmapping entryのサブセット定義にある 対応する集合と交差するかを確認します。集合は次の場合に交差します:
サブセット定義の集合が空 サブセット定義の集合が空ではない マッピングエントリの集合が空 true true マッピングエントリの集合が空ではない false 2つの集合が交差する場合は true デザイン空間の集合の交差を確認する場合、交差するセグメントのペア (タグが等しく、範囲が交差する)が少なくとも1つあれば、それらは交差します。
-
手順1で確認した1つ以上の集合が交差しなかった場合、intersectsとして false を返します。
-
mapping entryに子エントリがない場合、intersectsとして true を返します。
-
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 |
パッチ ファイルを読み込む
このアルゴリズムへの入力は次のとおりです:
-
patch URL string:読み込むパッチファイルを識別する URL文字列([UTF-8]でエンコード)。 相対 URL でもかまいません。
-
initial font URL:font subsetの派生元となった初期増分フォントの 場所を識別するURL。
このアルゴリズムの出力は次のとおりです:
-
patch file:patch URL stringによって識別される内容(バイト列)。
アルゴリズム:
-
URL 標準 § url-parsingを使用して、patch URL stringを URL レコードへ解析します。 initial font URLを基底 URLとし、 エンコーディングは UTF-8 とします。結果をtarget URLへ保存します。 URL の解析に失敗した場合、エラーを返します。
-
実装するユーザーエージェントのフェッチ機能を使用して、target URLの内容を取得します。 ウェブブラウザーでは、[FETCH]を使用するべきです。 [FETCH]を使用する場合、 リクエストは次のように構成されます:
-
methodを GET に設定します。
-
urlをtarget URLに設定します。
-
clientを、initial font URLの フェッチに使用したリクエストオブジェクトのクライアントに設定します。
-
initiator typeを "font" に設定します。
-
destinationを "font" に設定します。
-
referrerをinitial font URLに設定します。
-
modeを "cors" に設定します。
Fetchを使用して、requestを フェッチします。このとき、processResponseConsumeBodyは このアルゴリズムの手順3です。
[FETCH]を使用しない 実装では、利用可能なフェッチ機能を使用してtarget URLへのリクエストを行います。 同等の概念が存在する場合は、上記で指定した[FETCH]ベースの設定をコピーします。 そのフェッチ結果を使用して手順3へ進みます。
-
-
processResponseConsumeBodyには、 レスポンスと、null、failure、またはバイト列が渡されます。バイト列を受け取った場合、 そのバイトをpatch fileとして返します。null を受け取った場合、 空のバイト配列をpatch fileとして返します。それ以外の場合はエラーを返します。
注:フェッチ設定は、CSS フォント読み込みで 使用される設定(CSS Fonts 4 § 4.8.2 フォントのフェッチ要件)と一致させることを目的としていますが、 2つの相違点があります。第1にリファラーが初期フォントの URL に設定され、 第2に URL 解決ではスタイルシートではなく初期フォントが基底として使用されます。
エラーを 処理する
フォントサブセットの拡張処理がエラーで失敗した場合、フォント内の一部のデータが 完全には読み込まれていない可能性があり、その結果、欠落データに依存するコンテンツを レンダリングすると不正確なレンダリングになる可能性があります。クライアントはフォントの使用を 継続できますが、§ 4.6 フォントがレンダリングできるコンテンツの判定に 従って完全に読み込まれているコードポイント、機能、およびデザイン空間のレンダリングにのみ 使用するべきです。それ以外のすべてのコンテンツは、通常のクライアントのフォールバックロジックに 従って別のフォントへフォールバックするべきです。
パッチファイルを読み込むの実行中に エラーが発生した場合、クライアントはフォントサブセットの拡張を試行し続けることができます。 増分フォントサブセットを拡張するの 手順8では、各無効化グループ内で、読み込みに失敗したパッチが選択対象から除外されます。 無効化グループが空ではなく、そこから選択する必要があるものの、 失敗したパッチしか含まれていない場合、拡張は失敗し、続行できません。
それ以外のすべてのエラーの場合、 クライアントはフォントサブセットをさらに拡張しようとしてはなりません。
4.4. 無効化パッチの選択
増分フォントサブセットを拡張する アルゴリズムの実行中、候補エントリの一覧から単一の無効化(完全または部分) パッチエントリを選択する必要がある場合があります。使用される選択基準は、 拡張の実行に必要なラウンドトリップ総数へ直接影響します。ラウンドトリップは高コストであるため、 最大のパフォーマンスを得るには、必要なラウンドトリップ総数が最小になるように パッチを選択するべきです。
次の選択基準はラウンドトリップを 最小化するため、増分フォントサブセットを 拡張するの手順8で単一の部分無効化または完全無効化パッチを選択する際に、 クライアントが使用しなければなりません:
-
1つ以上の候補エントリについて、関連するパッチファイルが 増分フォントサブセットを 拡張するの手順9によって以前に読み込まれている場合、 次の手順では、パッチファイルがすでに読み込まれているか、現在読み込み中である 候補エントリのみを考慮します。それ以外の場合は、すべての候補エントリを考慮します。
-
各候補エントリについて、そのエントリのサブセット定義と、参照される子エントリの グラフを通じて到達可能なすべての子エントリのサブセット定義を和集合にして、 合計サブセット定義を計算します。
-
各候補エントリについて、合計サブセット定義と対象サブセット定義との 集合の共通部分を計算します。
-
手順2の共通部分が、ほかのどの共通部分の真部分集合でもないエントリを見つけます。
-
同じパッチマップ内にあり、手順3で見つかったエントリと 同じ共通部分を持つ追加エントリをすべて特定します。このエントリ集合 (手順3で選択したエントリを含む)の中で、最終的に選択するのは パッチマップ内で 最初に一覧表示されるエントリです。§ 5.3.1 パッチマップテーブル:形式 1では、エントリインデックスが最も小さいエントリです。 § 5.3.2 パッチマップテーブル:形式 2では、 entries配列内で 最初に現れるエントリです。
注:手順3の基準を満たすエントリを高速かつ 効率的に見つける方法は、まずコードポイント集合の共通部分の大きさ、次に機能タグ集合の 共通部分の大きさ、最後にデザイン空間の共通部分の大きさの順で、エントリを降順に ソートすることです。このソートで最初のエントリは、ほかのエントリの真部分集合ではないことが 保証されます。真上位集合であれば少なくとも1項目大きい必要があるためです。 この方法には、クライアントが現在要求しているデータを最も多く追加するパッチを選択するという 追加の利点もあります。
4.5. 対象サブセット定義
増分フォントサブセットを拡張する アルゴリズムは、クライアントがレンダリングしたいコンテンツに基づく対象サブセット定義を 入力として受け取ります。クライアントは、コンテンツ全体について単一のサブセット定義を 構成し、拡張アルゴリズムを1回実行できます。別の方法として、コンテンツをより小さな スパンへ分割し、各スパンについてサブセット定義を構成し、小さい各サブセット定義に対して 拡張アルゴリズムを実行できます。次の条件を満たす限り、どちらの方法でも最終的に、 コンテンツ全体を同等にレンダリングするフォントが生成されます:
-
サブセット定義を生成する各テキストスパンが、1つ以上の完全なシェーピング単位のみから構成されていること。
-
シェーピング単位とは、 クライアントがシェーピング中に単一の単位としてまとめて処理する テキストスパンであること。
4.6. フォントがレンダリングできるコンテンツの判定
ある増分フォント(初期フォントであるか、部分的に拡張されたフォントであるかを問わず)について、 クライアントは、そのフォントが現在の状態でどのコンテンツをレンダリングできるかを 知りたい場合があります。これは、テキストのどの部分にフォールバックフォントを使用するかを クライアントが判定しようとする場合に特に重要です。
フォールバック処理中、クライアントは通常、フォントの cmapテーブルを確認して、 どのコードポイントがサポートされているかを判定します。しかし IFT フォントでは、 § 6.3 グリフキー方式パッチの動作方法により、 cmapテーブルに、 対応するグリフデータがまだ読み込まれていないコードポイントのマッピングが含まれる場合があります。 そのため、クライアントはコードポイントの存在を判定する際に、 cmapテーブルのみに 依存するべきではありません。代わりに、次の手順を使用して、増分フォントが コンテンツのどの部分をレンダリングできるかを確認できます:
-
コンテンツを、テキストシェーピング中に処理されるシェーピング単位 (§ 4.5 対象サブセット定義を参照)へ分割します。
-
各シェーピング単位について2つの確認があります:
-
第1に、シェーピング単位内のいずれかのコードポイントについて cmap エントリが存在しないか、そのエントリがグリフ0へマッピングされている場合、 増分フォントはそのシェーピング単位のレンダリングを完全にはサポートしていません。
-
第2に、対応するフォントサブセット定義を計算し、 増分フォントサブセットを 拡張するアルゴリズムを手順6で停止して実行します。エントリ一覧が空でない場合、 増分フォントはそのシェーピング単位のレンダリングを完全にはサポートしていません。
-
-
両方の確認に合格したシェーピング単位は、フォントを使用して全体をレンダリングできます。
クライアントは、フォントがレンダリングできる内容を、シェーピング単位より細かい粒度で 知りたい場合もあります。次の擬似コードは、上記の確認に失敗したシェーピング単位を、 増分フォントでレンダリングできるスパンへ分割する方法の例を示します:
# 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 にマッピングされている。 # - subset_def を使用して ift_font 上で「増分フォントサブセットを拡張する」アルゴリズムを実行し、手順6で停止した後、 # エントリ一覧が空である。
返されたスパンのいずれにも含まれないシェーピング単位内のテキストは、増分フォントによって サポートされておらず、フォールバックフォントを使用してレンダリングするべきです。 各スパンは個別にシェーピングするべきです(すなわち、各スパンが新しいシェーピング単位になります)。 この方法ではシェーピング単位が分割されるため、複数コードポイント置換など、 元のフォントのすべての機能が存在するとは限りません。クライアントが、 § 4.5 対象サブセット定義に従って構成された サブセット定義を使用して、増分フォントサブセットを 拡張するアルゴリズムに正しく従っている場合、欠落データは読み込まれるため、 この状況は関連するパッチの読み込み中に一時的にのみ発生します。欠落しているパッチが到着して 適用されると、置換の結果として影響を受けるコードポイントのレンダリングが変化する可能性があります。
注:上記の "supported_spans(...)" 確認は、 増分フォントの拡張を駆動する目的で使用するものではありません。 増分フォントサブセットを拡張するの 実行に使用する対象サブセット定義の構成方法については、 § 4.5 対象サブセット定義に指針があります。
4.7. フォントの完全な 拡張
この節では、増分フォントを完全に拡張された非増分フォントへ変換するために使用できる アルゴリズムを定義します。この処理は、増分フォントによって提供されるすべての利用可能な データを読み込み、さらに適用すべきパッチを含まない単一の静的フォントファイルを生成します。
フォントサブセットを完全に拡張する
このアルゴリズムへの入力は次のとおりです:
このアルゴリズムの出力は次のとおりです:
-
expanded font:増分ではない[open-type]フォント。
アルゴリズム:
-
font subsetを使用して増分フォントサブセットを 拡張するを呼び出します。入力となる対象サブセット定義は、 エントリの交差を確認する手順で すべてのエントリと交差すると見なされる特別な定義です。結果のフォントサブセットを expanded fontとして返します。
4.8. 拡張済み増分フォントのキャッシュ
拡張された増分フォントには、この節の手順に従って将来の拡張処理を実行するために必要な すべての状態が含まれています。そのため、クライアントが将来使用するために増分フォントを 保存またはキャッシュする必要がある場合、拡張アルゴリズムの最新の適用によって生成された フォントバイナリのみを保存すれば十分です。初期フォントや以前の拡張で生成された版を 保持する必要はありません。
5. フォント形式の拡張
増分フォントは、 既存の OpenType形式に従いますが、4バイトのタグ 'IFT ' および 'IFTX' で 識別される2つの新しいテーブルを 含みます。これらの新しいテーブルはどちらもパッチマップです。すべての増分フォントは、 少なくとも 'IFT ' テーブルを含みます。'IFTX' テーブルは任意です。両方のテーブルが存在する場合、 フォント全体のマッピングは2つのテーブルのマッピングの和集合になります。 2つの新しいテーブルはこの仕様でのみ使用され、Open-Type仕様へ追加されるものではありません。
注:マッピングを2つの異なるテーブルへ分割できることで、 増分フォントは複数のパッチ形式をより容易に利用できます。たとえば、ある種類のすべてのパッチを 'IFT ' テーブルで指定し、2つ目の種類のすべてのパッチを 'IFTX' テーブルで指定できます。 それらのパッチは、マッピングテーブルの一方のみを更新し、競合する更新を回避できます。
5.1. 増分フォント転送とフォント圧縮形式
ウェブ上でフォントを使用する際は、[WOFF]または[WOFF2]などの 圧縮形式でフォントを圧縮することが一般的です。次の条件を満たす限り、 このような形式を使用して、増分フォント転送エンコーディングで使用される初期フォントファイルを 圧縮できます:
-
圧縮形式を通じてフォントをエンコードしてからデコードする処理によって、 各テーブルの バイトが変更されないこと。
-
増分フォント転送拡張アルゴリズム(§ 4 フォントサブセットの拡張)は非圧縮フォントファイルを直接操作するため、 圧縮済みフォントは拡張を試みる前にデコードする必要があります。
[WOFF2]については、 特別な注意が必要です。増分フォントを転送のために WOFF2 でエンコードする場合:
-
WOFF2 エンコーディングに変換済み glyf および loca テーブル (WOFF 2.0 § 5.1 変換済み glyf テーブル形式)が含まれる場合、増分フォントには、 glyf または loca テーブルを変更する§ 6.2 テーブルキー方式パッチを 含めるべきではありません。WOFF2 形式は、変換済み glyf および loca テーブルの デコード結果となる特定のバイトを保証しません。 § 6.3 グリフキー方式パッチは、変換済み glyf および loca テーブルと 組み合わせて使用できます。
-
'IFT ' および 'IFTX' テーブルは、WOFF 2.0 § 5 圧縮データ形式で定義される標準処理に従って、 WOFF2 エンコーダーによって処理および brotli エンコードできます。
注:glyf/loca 変換を無効にしても WOFF2 圧縮は WOFF より優れているため、IFT フォントは一般に WOFF2 を使用して圧縮することが推奨されます。 ただし、エンコーディングがテーブルキー方式パッチを使用してこれらのテーブルを更新する場合は、 glyf/loca 変換を無効にします。
5.2. CFF および CFF2 増分フォント
CFFまたは CFF2テーブルに 保存されたグリフアウトラインを含む増分フォントには、次の追加制限があります:
-
増分フォント内の CFF および CFF2 テーブルでは、CharStrings INDEX データ構造がテーブルの最後の要素でなければなりません (後続には4バイトワード境界までの0パディングのみを許可します)。
-
増分フォント内の CFF および CFF2 テーブルには、CharStrings INDEX データ構造と重複するほかのデータ要素が あってはなりません。
-
'IFT ' パッチマップテーブルには、 CFF および/または CFF2 テーブルの CharStrings INDEX データの先頭へのオフセット (cffCharStringsOffset、 cff2CharStringsOffset、 cffCharStringsOffset、または cff2CharStringsOffset)を 含めなければなりません。
これら3つの要件により、CFF および CFF2 テーブルに対するグリフキー方式パッチ適用の実装を 大幅に簡略化できます。これにより、CFF/CFF2 テーブル内にエンコードされたほかのデータ要素への オフセットを変更せずに、グリフデータを CFF/CFF2 テーブルへ挿入できます。 保存された CFF/CFF2 オフセットにより、クライアントは CFF/CFF2 テーブルのほかの部分を 解析することなく CharStrings INDEX を特定できます。
注:場合によっては、CFF または CFF2 テーブルが テーブルキー方式パッチによって追加または変更されることがあります。この場合、パッチは、 新しいまたは変更された内容を反映するように charstrings オフセットも追加または更新する必要があります。
CFF または CFF2 のサブルーチン化は増分フォント転送と互換性があります。ただし、 単純なサブルーチン化では、パッチサイズを縮小する一方で初期ファイルのサイズが増加する傾向があります。 また、WOFF2 は、サブルーチン化された同等のフォントより、サブルーチン化されていないフォントを より効果的に圧縮することが多いことが示されています(ただし非圧縮ファイルはかなり大きくなります)。 したがって、サブルーチン化は回避するか、適度に使用するか、IFT の具体的な要件に合わせて カスタマイズすることが推奨されます。
5.3. パッチマップテーブル
パッチマップは、 次の2つの形式のいずれかでエンコードされます:
-
形式 1:機能は限定されていますが、よりコンパクトなエンコーディングです。 グリフ ID からパッチ URL 文字列への1対1のマッピングをエンコードします。 デザイン空間を含むフォントサブセット定義や、 サブセット定義が重複するエントリはサポートしません。
-
形式 2:デザイン空間を含むものや、サブセット定義が重複するものを含め、 任意のマッピングをエンコードできます。ただし通常は形式 1 よりコンパクトではありません。
各形式は、その形式でエンコードされたバイトを解釈し、表現されるエントリ一覧を生成する アルゴリズムを定義します。増分フォントサブセットを拡張する アルゴリズムは解釈アルゴリズムを呼び出し、結果のエントリ一覧を操作します。 エンコードされたバイトは、パッチマップについて常に信頼できる唯一の情報源です。 サブセット拡張中のパッチ適用によってパッチマップのエンコード済みバイトが変更され、 その結果、エンコード済みバイトから派生するエントリ一覧も変更されます。 拡張アルゴリズムは各反復の開始時にエンコード済みバイトを再解釈し、 前の反復で行われた変更を取り込みます。
5.3.1. パッチマップテーブル:形式 1
形式 1 パッチマップの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| uint8 | format | 1 に設定し、これが形式 1 であることを識別します。 |
| uint24 | reserved | 未使用。0 に設定します。 |
| uint8 | flags | 任意フィールドの存在を通知するフラグ。 ビット0(最下位ビット)が設定されている場合、cffCharStringsOffsetが存在します。 ビット1(最下位ビット)が設定されている場合、cff2CharStringsOffsetが存在します。 |
| uint32 | compatibilityId[4] | このフォントと互換性のあるパッチを識別するために使用される一意の ID (§ 4.1 パッチの無効化を参照)。 エンコーダーがこの値を選択します。IFT フォントのエンコード中に以前使用されていない ランダムな値へ設定するべきです。 |
| uint16 | maxEntryIndex | このテーブルにエンコードされた最大のエントリインデックス。 |
| uint16 | maxGlyphMapEntryIndex | このテーブルに エンコードされた最大のグリフマップエントリインデックス。 maxEntryIndex 以下でなければなりません。 |
| uint24 | glyphCount |
マッピングが
提供されるグリフ数。フォントファイル内のグリフ数と一致しなければなりません。
注:フォント内のグリフ数は フォントファイル内にエンコードされています。執筆時点では、この値は maxp テーブルに記載されています。ただし、将来のフォント形式拡張では、 グリフ数の値をエンコードするために別のテーブルを使用する可能性があります。 |
| Offset32 | glyphMapOffset | グリフマップ サブテーブルへのオフセット。このテーブルの先頭からのオフセットです。 |
| Offset32 | featureMapOffset | 機能マップ サブテーブルへのオフセット。このテーブルの先頭からのオフセットです。null(0)でもかまいません。 |
| uint8 | appliedEntriesBitMap[(maxEntryIndex + 8)/8] | どのエントリが適用されたかを追跡するビットマップ。ビットiが設定されている場合、
エントリiのパッチがこのフォントへ適用済みであることを示します。
ビット0は appliedEntriesBitMap[0] の最下位ビットであり、ビット7は最上位ビットです。
ビット8は appliedEntriesBitMap[1] の最下位ビットであり、以後同様です。
|
| uint16 | urlTemplateLength | urlTemplate バイト配列の長さ。 |
| uint8 | urlTemplate[urlTemplateLength] | 各エントリに関連付けられた URL 文字列を生成するために使用される URL テンプレートを含むバイト配列。 |
| uint8 | patchFormat | urlTemplate によってリンクされるパッチの形式を指定します。 § 6.1 形式の概要表にある形式番号の いずれかに設定しなければなりません。 |
| uint32 | cffCharStringsOffset | flagsのビット0(最下位ビット)が 設定されている場合にのみ存在します。 CFFテーブルの 先頭から、そのCFFテーブルの CharStrings INDEX データ構造までのオフセットを示します。 |
| uint32 | cff2CharStringsOffset | flagsのビット1が設定されている場合にのみ存在します。 CFF2テーブルの 先頭から、そのCFF2テーブルの CharStrings INDEX データ構造までのオフセットを示します。 |
注:glyphCountは、 65,535個を超えるグリフを可能にするために提案されている将来のフォント形式 拡張と互換性を持つように設計されています。
グリフマップの エンコーディング:
グリフマップテーブルは、フォント内の各グリフインデックスをエントリインデックスへ関連付けます。
| 型 | 名前 | 説明 |
|---|---|---|
| uint16 | firstMappedGlyph | firstMappedGlyph より小さいすべてのグリフインデックスは、 暗黙的にエントリインデックス0へマッピングされます。 |
| uint8/uint16 | entryIndex[glyphCount - firstMappedGlyph] | グリフiのエントリインデックスは、entryIndex[i -
firstMappedGlyph] に保存されます。
maxEntryIndexが256未満の場合、
配列要素は uint8、それ以外の場合は uint16 です。
|
機能マップの エンコーディング:
機能マップテーブルは、機能タグと グリフの組み合わせをエントリインデックスへ関連付けます。
| 型 | 名前 | 説明 |
|---|---|---|
| uint16 | featureCount | featureRecords の数。 |
| FeatureRecord | featureRecords[featureCount] | 特定の機能 タグのマッピングを提供します。featureRecordsは、 featureTagの昇順に並べられ、 各機能タグは最大1回だけ現れます。ソートでは、タグ値を4バイトの ビッグエンディアン符号なし整数として解釈し、整数値で並べます。 |
| EntryMapRecord | entryMapRecords[variable] | 各機能マッピングのキー(エントリインデックス)を提供します。 entryMapRecords 配列には、featureRecords配列内の entryMapCountフィールドの合計と 同じ数のエントリが含まれます。entryMapRecords[0] は featureRecords[0] の最初の エントリに対応し、entryMapRecords[featureRecord[0].entryMapCount] は featureRecords[1] の最初のエントリに対応し、 entryMapRecords[featureRecords[0].entryMapCount + featureRecord[1].entryMapCount]] は featureRecords[2] の最初のエントリに対応し、 以後同様です。 |
FeatureRecordの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| Tag | featureTag | このマッピングの対象となる機能 タグ。 |
| uint8/uint16 | firstNewEntryIndex | maxEntryIndexが256未満の場合は uint8、 それ以外の場合は uint16。このレコードがマッピングする最初のエントリインデックス。 |
| uint8/uint16 | entryMapCount | maxEntryIndexが256未満の場合は uint8、 それ以外の場合は uint16。この機能に関連付けられたEntryMapRecordの数。 |
EntryMapRecordの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| uint8/uint16 | firstEntryIndex | maxEntryIndexが256未満の場合は uint8、 それ以外の場合は uint16。firstEntryIndex と lastEntryIndex は、このマッピングによって 作成されるエントリのサブセット定義を形成するグリフマップエントリの集合を指定します。 |
| uint8/uint16 | lastEntryIndex | maxEntryIndexが256未満の場合は uint8、 それ以外の場合は uint16。 |
エントリマップレコードは、firstEntryIndex 以上かつ lastEntryIndex 以下の すべてのエントリインデックスと一致します。
5.3.1.1. 形式 1 の 解釈
このアルゴリズムは、形式 1 パッチマップをパッチマップエントリの一覧へ 変換するために使用されます。
形式 1 パッチマップを解釈する
このアルゴリズムへの入力は次のとおりです:
-
patch map:形式 1 パッチマップでエンコードされたパッチマップ。
-
font subset:patch mapを含むフォントサブセット。
このアルゴリズムの出力は次のとおりです:
-
entry list:パッチマップエントリの一覧。
アルゴリズム:
-
patch mapデータが完全で切り詰められておらず、 formatが1に等しく、 § 5.3.1 パッチマップテーブル:形式 1の要件 (「must」で示される要件)に従って有効であることを確認します。 そうでない場合はエラーを返します。
-
entryIndex内の一意な各entry indexについて:
-
entry indexが0の場合、これはすでに初期フォント内にあるグリフを示す 特別なエントリです。このインデックスを飛ばし、エントリを作成しません。
-
entry indexがmaxGlyphMapEntryIndexより 大きい場合、このエントリは無効です。このentry indexを飛ばします。
-
appliedEntriesBitMap内の entry indexのビットが1に設定されている場合、 このentry indexを飛ばします。
-
entry indexへマッピングされるグリフインデックスの集合を収集します。
-
font subsetのcmap テーブルにあるコードポイントからグリフへのマッピングを使用して、 グリフインデックスの集合を Unicode コードポイントの集合へ変換します。 cmapによって マッピングされていないグリフインデックスは無視します。 複数のコードポイントが同じグリフ ID へマッピングされる場合があります。 グリフに関連付けられたすべてのコードポイントを含めるべきです。
-
urlTemplateと entry indexを入力としてURL テンプレートを展開するを 呼び出し、entry indexを URL 文字列へ変換します。 テンプレート展開がエラーになる場合、エラーを返します。
-
Unicode コードポイントの集合が空の場合、このentry indexを飛ばします。
-
Unicode コードポイント集合のみを含むサブセット定義を持ち、 生成された URL 文字列、patchFormatで指定されるパッチ形式、 およびcompatibilityIdへマッピングされる エントリをentry listへ追加します。
-
-
featureMapOffsetが null でない場合、 featureRecordsおよび entryMapRecords内の、 各FeatureRecordと関連付けられた EntryMapRecordについて:
-
FeatureRecordのfeatureTagが、一覧内で以前に現れた 任意のFeatureRecordのfeatureTag以下である場合、その FeatureRecord は無効です。関連付けられたすべてのEntryMapRecordを 飛ばします。順序付けでは、タグ値を4バイトのビッグエンディアン符号なし整数として 解釈し、その整数値によって順序付けします。
-
mapped entry indexを計算します。 FeatureRecordに関連付けられた最初の EntryMapRecordは、 FeatureRecord::firstNewEntryIndex、 2番目はFeatureRecord::firstNewEntryIndex + 1、以後同様です。最後はFeatureRecord::firstNewEntryIndex + entryMapCount - 1 になります。
-
計算したmapped entry indexがmaxGlyphMapEntryIndex以下、 またはmaxEntryIndexより大きい場合、 このEntryMapRecordは無効です。飛ばします。
-
EntryMapRecord::firstEntryIndexが EntryMapRecord::lastEntryIndexより 大きい場合、このEntryMapRecordは無効です。飛ばします。
-
urlTemplateと mapped entry indexを入力としてURL テンプレートを展開するを 呼び出し、mapped entry indexを URL 文字列へ変換します。 テンプレート展開がエラーになる場合、エラーを返します。
-
appliedEntriesBitMap内の mapped entry indexのビットが1に設定されている場合、 このエントリを飛ばします。
-
Unicode コードポイントの集合を構築します。EntryMapRecord::firstEntryIndex (含む)からEntryMapRecord::lastEntryIndex (含む)までの各entry indexについて:
-
entry indexがmaxGlyphMapEntryIndexより 大きい場合、このEntryMapRecordは無効です。飛ばします。
-
手順2で計算した、entry indexに関連付けられた Unicode コードポイント集合を 集合へ追加します。entry indexが0、または appliedEntriesBitMapのために 飛ばされた場合は、飛ばされなかったものとして関連コードポイント集合を計算します。
-
-
構築された Unicode コードポイント集合が空の場合、このEntryMapRecordは無効です。 飛ばします。
-
生成された URL 文字列、patchFormatで指定されるパッチ形式、 およびcompatibilityIdへマッピングされる エントリをentry listへ追加します。 または、生成された URL 文字列と同じパッチ URL 文字列を持つ既存の エントリがentry listに存在する場合は、 代わりにその既存エントリを変更します。構築された Unicode コードポイント集合と featureTagを、新しいまたは既存の エントリのサブセット定義へ追加します。
-
-
entry listを返します。
注:エンコーディングは [0, maxEntryIndex] 内のすべての エントリインデックスのエントリを含める必要はありませんが、最大のコンパクト性を得るために 含めることが推奨されます。
5.3.1.2. 形式 1 からのエントリの削除
このアルゴリズムは、形式 1 パッチマップからエントリを削除するために使用されます。 この削除はパッチマップのバイトを変更しますが、バイト数は変更しません。
形式 1 パッチマップからエントリを 削除する
このアルゴリズムへの入力は次のとおりです:
-
patch map:形式 1 パッチマップでエンコードされたパッチマップ。 この手順によって変更される場合があります。
-
patch URL string:削除するエントリを識別するパッチの URL 文字列。
アルゴリズム:
-
patch mapのformatが1に等しく、 § 5.3.1 パッチマップテーブル:形式 1の要件に従って 有効であることを確認します。そうでない場合はエラーを返します。
-
patch mapのentryIndex内の一意な各entry indexについて:
-
appliedEntriesBitMap内の entry indexのビットが1に設定されている場合、 このentry indexを飛ばします。
-
urlTemplateと entry indexを入力としてURL テンプレートを展開するを 呼び出し、entry indexを URL 文字列へ変換します。 テンプレート展開がエラーになる場合、エラーを返します。
-
生成された URL 文字列がpatch URL stringと等しい場合、 appliedEntriesBitMap内の entry indexのビットを1に設定します。
-
5.3.2. パッチマップテーブル:形式 2
形式 2 パッチマップの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| uint8 | format | 2 に設定し、これが形式 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テーブルの 先頭から、そのCFFテーブルの CharStrings INDEX データ構造までのオフセットを示します。 |
| uint32 | cff2CharStringsOffset | flagsのビット1が設定されている場合にのみ存在します。 CFF2テーブルの 先頭から、そのCFF2テーブルの CharStrings INDEX データ構造までのオフセットを示します。 |
マッピングエントリの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| uint8 | entries[variable] | entryCount個の マッピングエントリのエンコード済みバイトを含む バイト配列。各エントリの長さは可変であり、 形式 2 パッチマップ エントリを解釈するに従って判定されます。 |
マッピングエントリの エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| 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データブロック内で 占めるバイト数。長さ値の最上位ビットが設定されている場合、さらに1つの長さ値が 続きます。最上位ビットがクリアされた長さ値に到達するまで繰り返します。 実際の長さ値は、各値の下位23ビットに保存されます。 formatFlagsのビット2が設定され、 かつentryIdStringDataが null(0)ではない 場合にのみ存在します。存在する場合、少なくとも1つの長さ値があります。 存在せず、かつentryIdStringDataが null(0)ではない 場合、1つの ID 文字列があり、前のエントリの最後の ID 文字列、 または最初のエントリでは空文字列に設定されます。 |
| uint8 | patchFormat | このエントリによってリンクされるパッチの形式を指定します。 § 6.1 形式の概要表の ID 番号を使用します。 defaultPatchFormatを上書きします。 formatFlagsのビット3が設定されている場合にのみ 存在します。 |
| uint16/uint24 | bias | コードポイント集合内のすべてのコードポイント値へ追加されるバイアス値。 format のビット4が0、ビット5が1の場合、存在し、uint16 です。 format のビット4が1、ビット5が1の場合、存在し、uint24 です。 それ以外の場合は存在しません。 |
| uint8 | codePoints[variable] | このマッピングのコードポイント集合。疎ビット集合としてエンコードされます。 formatFlagsのビット4および/または5が 設定されている場合にのみ存在します。長さは、 § 5.3.2.3 疎ビット集合のデコード手順に従って 判定されます。 |
エンコーダーがファイルシステムに保存されてから提供されるパッチを生成する場合、 数値エントリ ID のみを使用することが推奨されます (entryIdDeltaを使用)。 これは通常、形式 2 パッチマップを最も小さくエンコードできるためです。 文字列 ID は、パッチが事前保存されず、リクエストされるパッチに関する情報を ID 文字列へエンコードできる場合に有用です。
デザイン空間 セグメントのエンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| Tag | tag | 軸タグ値。 |
| Fixed | start | セグメントの開始(含む)。この値はユーザー軸スケールを使用します: OpenType 仕様 § otvaroverview#coordinate-scales-and-normalization。 |
| Fixed | end | セグメントの終了(含む)。start 以上でなければなりません。 この値はユーザー軸スケールを使用します: OpenType 仕様 § otvaroverview#coordinate-scales-and-normalization。 |
5.3.2.1. 形式 2 の 解釈
このアルゴリズムは、形式 2 のパッチマップをパッチマップエントリの一覧へ変換するために使用されます。
形式 2 パッチマップを解釈する
このアルゴリズムへの入力は次のとおりです:
-
patch map:形式 2 パッチマップでエンコードされた パッチマップ。
このアルゴリズムの出力は次のとおりです:
-
entry list:パッチマップエントリの一覧。
アルゴリズム:
-
patch mapのformatが2に等しく、 § 5.3.2 パッチマップテーブル:形式 2の要件 (「must」で示される要件)に従って有効であることを確認します。 そうでない場合はエラーを返します。
-
entryIdStringDataのオフセットが0の場合、 last entry idを0で初期化します。それ以外の場合は空のバイト文字列で初期化します。 current byteを0に設定し、current id string byteを0に設定します。
-
entry listおよびprior entry listを空の一覧として初期化します。
-
形式 2 パッチマップ エントリを解釈するを、entryCount回呼び出します。 各呼び出しについて:
-
prior entry list、patch mapの entries[current byte]から patch mapの終端までのバイト、 entryIdStringDataが0でない場合は patch mapのentryIdStringData[current id string byte]からpatch mapの終端までのバイト、 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へ追加します。
-
-
entry listを返します。
形式 2 パッチマップエントリを解釈する
このアルゴリズムへの入力は次のとおりです:
-
prior entry list:このエントリより前にあるエントリの一覧。
-
entry bytes:エンコードされたマッピングエントリを含むバイト配列。
-
id string bytes(任意):エントリ ID 文字列を含むバイト配列。
-
last entry id:最後に生成されたエントリ ID。
-
default patch format:指定されていない場合の既定のパッチ形式。
-
url template:パッチの場所を特定するために使用される URL テンプレート。
このアルゴリズムの出力は次のとおりです:
-
entry id:このエントリで最後に生成された数値または文字列 ID。
-
entry:単一のエントリ。
-
consumed bytes:エントリのエンコードに使用されたバイト数。
-
consumed id string bytes:エントリ ID 文字列のエンコードに使用されたバイト数。
-
ignored:true の場合、このエントリは無視するべきです。
アルゴリズム:
-
すべての手順において、entry bytesからデータが読み込まれるたびに、 読み込んだバイト数だけconsumed bytesを増加させます。
-
entry id = last entry id、 consumed id string bytes = 0 に設定します。
-
entryのパッチ形式をdefault patch formatに設定します。
-
すべての集合を空として初期化した単一のフォントサブセット定義をentryへ追加します。
-
entry bytesからformatFlagsを読み取ります。
-
formatFlagsのビット0が設定されている場合、 機能タグ一覧とデザイン空間一覧が存在します:
-
featureCountおよび featureTagsで指定される機能タグ一覧を entry bytesから読み取り、読み込んだタグをentry内の最初の フォントサブセット定義へ追加します。
-
designSpaceCountおよび designSpaceSegmentsで指定される デザイン空間セグメント一覧をentry bytesから読み取り、 デザイン空間セグメントをentry内の最初のフォントサブセット定義へ追加します。 各セグメントは、tagによって識別される軸について、 startからendまでの 区間(両端を含む)を定義します。いずれかのセグメントで startがendより大きい場合、 このエンコーディングは無効です。エラーを返します。
-
-
formatFlagsのビット1が設定されている場合、 コピーインデックス一覧が存在します:
-
childEntryMatchModeAndCountの 最上位ビットが設定されている場合、entryの一致モードを連言に設定し、 それ以外の場合は選言に設定します。
-
childEntryMatchModeAndCount およびchildEntryIndicesで指定される 子エントリインデックス一覧をentry bytesから読み取ります。
-
子エントリインデックスは、以前に読み込まれたエントリを参照します。0は prior entry list内の最初のマッピングエントリ、 1は2番目、以後同様です。childEntryIndices内の各値について、 一致するインデックスを持つエントリをprior entry list内で特定し、 そのエントリへの参照をentryへ追加します。 childEntryIndicesの値が prior entry listの長さ以上である場合、このエンコーディングは無効です。 エラーを返します。
-
-
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を繰り返します。
-
-
-
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へ追加します。
-
-
-
formatFlagsのビット3が設定されている場合、 パッチ形式が存在します。entry bytesから patchFormatで指定される形式を読み取り、 entryのパッチ形式をその値に設定します。 patchFormatが § 6.1 形式の概要の値のいずれでもない場合、 このエンコーディングは無効です。エラーを返します。
-
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.2.3 疎ビット集合に従って、 entry bytesからバイアス付きの疎ビット集合 codePointsを読み取ります。 結果のコードポイント集合をentry内の最初の フォントサブセット定義へ追加します。 疎ビット集合のデコードに失敗した場合、このエンコーディングは無効です。 エラーを返します。
-
-
formatFlagsのビット6が設定されている場合、 ignoredを true に設定します。それ以外の場合、ignoredは false です。
-
entry id、entry、consumed bytes、 consumed id string bytes、およびignoredを返します。
5.3.2.2. 形式 2 からのエントリの削除
このアルゴリズムは、形式 2 パッチマップからエントリを削除するために使用されます。 この削除はパッチマップのバイトを変更しますが、バイト数は変更しません。
形式 2 パッチマップからエントリを 削除する
このアルゴリズムへの入力は次のとおりです:
-
patch map:形式 2 パッチマップでエンコードされたパッチマップ。 この手順によって変更される場合があります。
-
patch URL string:削除するエントリを識別するパッチの URL 文字列。
このアルゴリズムは、形式 2 パッチマップを解釈するを 変更したものです。patch mapを入力として形式 2 パッチマップを解釈するを 呼び出しますが、次の変更を加えます:
-
形式 2 パッチマップ エントリを解釈するの手順8および9の実行中: 最初の差分値/長さ値についてのみ生成された URL 文字列をpatch URL stringと 比較し、等しい場合、formatFlagsのビット6を1に設定します。 この時点で解釈処理を停止します。
-
形式 2 パッチマップを解釈するの 戻り値は使用しません。
5.3.2.3. 疎ビット 集合
疎ビット集合は、互いに異なる符号なし整数の集合をコンパクトに保存するデータ構造です。 集合は木として表現され、各ノードは固定数の子を持ち、区間を等しい区画へ再帰的に分割します。 高さH、分岐係数Bの木は、[0 から BH-1](両端を含む)の整数について集合への所属を保存できます。 木は転送のためにバイト配列へエンコードされます。
形式 2 パッチマップの文脈では、疎ビット集合は Unicodeコードポイントの 集合を保存するために使用されます。そのため、疎ビット集合に保存される整数値は、 0から0x10FFFFの範囲にあるUnicodeコードポイント値に制限されます。
疎ビット集合の エンコーディング:
| 型 | 名前 | 説明 |
|---|---|---|
| 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 をデコードする
このアルゴリズムへの入力は次のとおりです:
-
treeData:デコードするバイト配列。
-
bias:デコードされた各集合要素へ追加される符号なし整数値。
このアルゴリズムの出力は次のとおりです:
-
S:符号なし整数の集合。
FIFO(先入れ先出し)キューQを使用するアルゴリズム:
-
treeDataから最初のバイトを削除します。これはヘッダーバイトです。 疎ビット集合に従って、木の高さHと 分岐係数Bを判定します。
-
Hが、分岐係数 エンコーディング表のBの行にある「最大高さ」より大きい場合、 エンコーディングは無効です。エラーを返します。
-
Hが0に等しい場合、これは空集合であり、treeDataの それ以降のバイトは消費されません。空集合を返します。
-
タプル (0, 1) をQへ挿入します。
-
Sを空集合として初期化します。
-
treeDataはビット列として解釈されます。 treeData[0] の最下位ビットが列の最初のビット、 treeData[0] の最上位ビットが8番目のビットであり、以後同様です。
-
次の手順でSへ追加される値が Unicode コードポイントの最大値 (0x10FFFF)より大きい場合、その値を無視し、Sへ追加しません。
-
Qが空の場合、Sを返します。
-
Qから次のタプルtを取り出します。 t内の最初の値がstart、2番目の値がdepthです。
-
treeDataのビット列から次のBビットを削除します。 最初に削除したビットをv1、2番目をv2とし、 最後に削除したビットvBまで続きます。削除前に treeDataに残っているビットがB未満だった場合、 treeDataは不正です。エラーを返します。
-
v1からvBまでのすべてのビットが0の場合、 区間 [start + bias, start + bias + BH - depth + 1) 内のすべての整数を Sへ挿入します。手順5へ進みます。
-
v1からvBまでのうち、 1に等しい各viについて: depthがHに等しい場合、 整数start + bias + i - 1 をSへ追加します。 それ以外の場合、タプル (start + (i - 1) * BH - depth, depth + 1) をQへ挿入します。
-
手順8へ進みます。
注:疎ビット集合をエンコードする際、 エンコーダーは任意の分岐係数を使用できますが、通常遭遇するほとんどの Unicode コードポイント集合で 最も小さいエンコーディングになることが示されているため、 4を使用することが推奨されます。
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 ] Which then becomes the byte string: [ 0b00001110, 0b00100001, 0b00010001, 0b00000001, 0b00000100, 0b00000010, 0b00001000 ]
bit string: |-- header -- | | B=2 H=0 | [ 00 00000 0 ] Which then becomes the byte string: [ 0b00000000, ]
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.3. URL テンプレート
URL テンプレートは、各パッチマップエントリに関連付けられた URL 文字列を圧縮するために使用されます。 各パッチマッピングテーブルは URL テンプレートを提供し、各エントリの URL 文字列は、 そのエントリの ID を入力として共通テンプレートを展開することによって生成されます。 テンプレート展開の出力は、[UTF-8]でエンコードされた文字列です。
URL テンプレートは、リテラル値または入力エントリ ID に基づく値を挿入する、 1バイトのオペコード列としてエンコードされます。
URL テンプレートをデコードして展開するアルゴリズムは次のとおりです。
URL テンプレートを展開する
このアルゴリズムへの入力は次のとおりです:
-
url template bytes:URL テンプレートを含むバイト配列。
-
entry ID:エントリの ID。符号なし整数またはバイト配列のいずれでもかまいません。
このアルゴリズムの出力は次のとおりです:
-
URL string:URL 文字列を表すバイト配列。 [UTF-8]としてエンコードされます。
アルゴリズム:
-
URL stringを空のバイト配列として初期化します。 残りの手順ではurl template bytesをキューとして使用します。 読み取り操作は、キューの先頭(インデックス0のバイトから開始)からバイトを削除します。
-
url template bytesの次のバイトをop codeへ読み取ります。 残りのバイトがない場合、展開は完了しています。URL stringを返します。
-
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へ進みます。
-
-
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としてエンコードされます。 |
入力例と、それに対応する展開結果を示します。「Template Bytes」列の値は、 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. 形式の概要
この仕様では次のパッチ形式を定義します:
-
§ 6.2 テーブルキー方式: フォントサブセットのテーブルを基底として使用する、 brotli エンコードされたバイナリ差分の集合。
-
§ 6.3 グリフキー方式: それぞれがグリフ ID とテーブルに関連付けられた、不透明なバイナリブロブの集合。
各アルゴリズムの詳細な説明は、次の各節にあります。
パッチ形式および無効化モードを§ 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. テーブルキー方式パッチの適用
このパッチ適用アルゴリズムは、テーブルキー方式パッチを 適用して、追加のコードポイント、機能、および/またはデザインバリエーション空間をカバーするように フォントサブセットを 拡張するために使用されます。
テーブルキー方式パッチを適用する
このアルゴリズムへの入力は次のとおりです:
-
base font subset:拡張対象のフォントサブセット。
-
patch:base font subsetへ適用するテーブルキー方式パッチ。
-
compatibility id:このパッチを一覧に含めた base font subsetの 'IFT ' または 'IFTX' テーブル内の ID 番号。
このアルゴリズムの出力は次のとおりです:
-
extended font subset:patchによって拡張された フォントサブセット。
アルゴリズム:
-
extended font subsetを、テーブルを持たない空のフォントとして初期化します。
-
patchが§ 6.2 テーブルキー方式の要件 (「must」で示される要件)に従って有効であり、すべての TablePatchがpatch内に収まっていることを確認します。 それ以外の場合はエラーを返します
-
patch内のcompatibilityIdフィールドが compatibility idに等しいことを確認します。一致しない場合、または base font subsetに 'IFT ' テーブルも 'IFTX' テーブルもない場合、 パッチ適用は失敗しています。エラーを返します。
-
次の手順において、extended font subsetへテーブルを追加するとは、 OpenType 仕様の要件に従って、テーブルのデータをフォントへ追加し、 テーブル ディレクトリへ新しいエントリを挿入することです。そのエントリには テーブルデータのチェックサムが含まれます。既存のテーブルを変更せずにコピーする場合、 クライアントはソースフォント内のエントリのチェックサムを再利用できます。 それ以外の場合、新しいチェックサムを計算する必要があります。
-
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内にデコード処理で使用されなかった データがある場合、エラーを返します。tagで識別される テーブルを extended font subsetへ追加し、その内容をデコード済みの brotliStreamに設定します。 次のエントリへ進みます。
-
それ以外の場合、brotliStreamを、 Brotli 圧縮データ 形式 § 10 デコードアルゴリズムに従ってデコードします。 このとき、base font subset内のtagで識別される テーブルを 共有 LZ77 辞書として使用します。そのようなテーブルがない場合、エラーを返します。 デコード済みデータがmaxUncompressedLengthより大きい場合、 エラーを返します。brotliStream内にデコード処理で使用されなかった データがある場合、エラーを返します。tagで識別される テーブルを extended font subsetへ追加し、その内容をデコード済みの brotliStreamに設定します。
-
-
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. グリフキー方式パッチの適用
このパッチ適用アルゴリズムは、グリフキー方式パッチを 適用して、追加のコードポイント、機能、および/またはデザインバリエーション空間をカバーするように フォントサブセットを 拡張するために使用されます。
グリフキー方式パッチを適用する
このアルゴリズムへの入力は次のとおりです:
-
base font subset:拡張対象のフォントサブセット。
-
patch:base font subsetへ適用するグリフキー方式パッチ。
-
patch URL string:パッチデータが配置されている URL 文字列。
-
compatibility id:このパッチを一覧に含めた base font subsetの 'IFT ' または 'IFTX' テーブル内の互換性 ID。
このアルゴリズムの出力は次のとおりです:
-
extended font subset:patchによって拡張された フォントサブセット。
アルゴリズム:
-
patchが§ 6.3 グリフキー方式の要件 (「must」で示される要件)に従って有効であることを確認します。 それ以外の場合はエラーを返します
-
patch内のcompatibilityIdフィールドが compatibility idに等しいことを確認します。一致しない場合、または base font subsetに 'IFT ' テーブルも 'IFTX' テーブルもない場合、 パッチ適用は失敗しています。エラーを返します。
-
brotliStream内の Brotli エンコード済み データを、Brotli 圧縮データ 形式 § 10 デコードアルゴリズムに従ってデコードします。 デコード済みデータはGlyphPatchesテーブルです。デコード済みデータが maxUncompressedLengthより大きい場合、 エラーを返します
-
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へ挿入します。
-
-
compatibility idと同じcompatibilityIdを持つ § 5.3 パッチマップテーブルを特定します。 形式 1 パッチマップである場合、パッチマップテーブルとpatch URL stringを入力として 形式 1 パッチマップから エントリを削除するを呼び出します。形式 2 パッチマップである場合、 パッチマップテーブルとpatch URL stringを入力として 形式 2 パッチマップから エントリを削除するを呼び出します。変更されたパッチマップテーブルを extended font subsetへコピーします。
-
base font subset内にあり、手順4または5で処理したどのエントリにも 見つからなかったタグを持つ各テーブルについて、 そのテーブルのコピーをextended font subsetへ追加します。
-
前の手順でいずれかのフォント テーブルの内容が変更された場合、変更された各テーブルについて、 フォントの テーブルディレクトリ内のチェックサムを、新しいテーブル内容と一致するように更新します。
7. エンコーディング
エンコーダーとは、増分フォントと関連する パッチの集合を生成する ツールです。「エンコーディング」とは、特定の場合の結果に影響を与えるために エンコーダーが要求または許可するすべてのパラメーターを含め、エンコーダーを使用する処理を指します。 適合するエンコーダーによって生成される増分フォントと関連パッチは:
-
§ 5 フォント形式の拡張および § 6 フォントパッチ形式のすべての要件を 満たさなければなりません。
-
一貫していなければなりません。すなわち、任意のフォントサブセット定義について、 そのサブセット定義と増分フォントを使用して 増分フォントサブセットを 拡張するを呼び出した結果は、 増分フォントサブセットを 拡張するの手順8で選択されたパッチ選択順序にかかわらず、 常に同じでなければなりません。
-
パッチ無効化基準を尊重しなければなりません。 IFT エンコーディングの一部である任意のパッチは、互換性のある フォントサブセットへ適用されたとき、 関連するパッチマップエントリが宣言する 無効化モードについて、§ 4.1 パッチの無効化の 基準に適合するパッチマップの互換性 ID のみを 変更しなければなりません。
-
エンコーダーを使用して既存のフォントを増分フォントへ変換する場合、 関連する完全に拡張されたフォントは 既存フォントと同等であるべきです。同等の完全拡張フォントは、 既存フォントと同じすべてのテーブル (増分 IFT/IFTX テーブルを除く)を持つべきであり、各テーブルは既存フォント内の 対応するテーブルと機能的に同等であるべきです。注:完全拡張版は、 必ずしも既存フォントと完全に同じバイナリになるとは限りません。
-
拡充処理全体を通じて完全拡張フォントの機能を保持するべきです。すなわち、 増分フォントから導出された 完全に拡張されたフォントと 任意のコンテンツがある場合、そのコンテンツをカバーする最小サブセット定義を使用して 増分フォントに対して 増分フォントサブセットを 拡張するを呼び出して生成されたフォントサブセットは、 そのコンテンツについて完全拡張フォントと同一にレンダリングするべきです。
エンコーダーを使用して既存のフォントファイルを増分フォントへ変換し、 クライアントがこの文書のほかの節に従って実装されている場合、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 グリフキー方式パッチは、ほかのパッチ形式とはかなり異なります。 第1に、§ 6.3 グリフキー方式パッチはグリフアウトラインデータを含む テーブルのみを変更できるため、§ 6.3 グリフキー方式のみを使用する 増分フォントは、ほかのすべてのフォントテーブルデータを 初期フォントファイルへ含める必要があります。第2に、 § 6.3 グリフキー方式パッチは無効化しないため、 独立してダウンロードおよび適用できます。この独立性により、複数のパッチを並列に ダウンロードでき、無効化パッチ形式と比較して必要なラウンドトリップ数を大幅に削減できます。
エンコーディング用パッチ形式の選択
すべてのエンコーディングは、使用する1つ以上のパッチ形式を選択しなければなりません。 § 6.2 テーブルキー方式パッチではフォント内のあらゆる種類の データへパッチを適用できますが、この形式は少なくとも部分無効化であるため、 必要なパッチ総数はセグメント数に対して線形ではなく指数関数的に増加します。 § 6.3 グリフキー方式パッチは、アウトラインおよび バリエーション差分データの更新に限定されますが、必要数はセグメント数に対して線形に増加します。
パッチ数に加えて、エンコーダーは一般的なコンテンツ用のパッチを取得するために必要となる ネットワークラウンドトリップ数も考慮するべきです。無効化パッチ形式では、 パッチリクエストを直列に行う必要があります。これは、コンテンツが複数のセグメントを必要とする場合、 複数回のネットワークラウンドトリップが必要になる可能性があることを意味します。 一方、グリフキー方式パッチは無効化しないため、パッチを並列にフェッチでき、 必要なのは1回のラウンドトリップだけです。
2種類の極端な例では、§ 6.2 テーブルキー方式パッチは、 大量の非アウトラインデータを含み、必要なパッチ数が少ないフォントに最も適しています。 § 6.3 グリフキー方式パッチは、データの大部分が グリフアウトラインで構成されるフォントに最も適しており、多くの既存 CJK フォントが該当します。
中間に位置するフォント、またはグリフデータの細粒度なセグメント化が望まれる一方、 ほかのテーブル内のデータもセグメント化する必要がある場合、 § 6.2 テーブルキー方式と § 6.3 グリフキー方式のパッチ形式を次のように 混在させることが望ましい場合があります:
-
すべてのテーブルキー方式パッチエントリを一方のマッピングテーブルへ、 すべてのグリフキー方式エントリをもう一方のマッピングテーブルへ保持します。
-
グリフキー方式パッチが変更するテーブル (アウトライン、バリエーション差分、およびグリフキー方式パッチのマッピングテーブル)を除く すべてのテーブルを更新するために、テーブルキー方式パッチを使用します。 これらのパッチでは、パッチ数を妥当な範囲に保つため、少数の大きなセグメントを使用するべきです。
-
グリフキー方式パッチは更新対象となる特定のグリフ ID を参照するため、 テーブルキー方式パッチは、元のフォントで使用されているグリフからグリフ ID への 割り当てを変更してはなりません。そうしないと、グリフキー方式パッチに一覧表示される グリフ ID が不正確になる可能性があります。フォントサブセット化ツールでは、 これは「グリフ ID を保持する」と呼ばれるオプションとして提供されることがよくあります。
-
最後に、残りのテーブルを更新するためにグリフキー方式パッチを使用します。 ここでは、必要なパッチ数を増やしすぎることなく、より小さい細粒度のセグメントを使用できます。
多くのフォントは2つの極端な例の中間に位置するため、 混合パッチ形式のエンコーディングは一般的に使用される方法になると予想されます。
無効化パッチによるラウンドトリップの削減
無効化パッチ形式のいずれかを使用するセグメント化で必要なラウンドトリップ数を減らす方法の1つは、 単一セグメント用のパッチに加えて、複数のセグメントを一度に追加するパッチを提供することです。 たとえば、A、B、C、D の4セグメントを持つフォントを考えます。パッチテーブルには、 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つの悪影響があります。 第1に、事前生成されたすべてのパッチに必要な保存領域が望ましくないほど大きくなる可能性があります。 第2に、一般にパッチ数が増えると CDN キャッシュ性能が低下します。パッチ数が増えることは、 特定のサブセットから特定のサブセットへの経路数が増えることを意味し、 ユーザーがアクセスするコンテンツに応じて異なる経路が選択されるためです。 事前生成されるパッチ総数を削減するために使用できる手法があります:
-
パッチグラフに最大深度を使用し、この制限へ到達したら、完全な元のフォントの 残りの部分をすべて追加するようにフォントへパッチを適用します。 これにより、一定数のセグメントが追加された後、残りのフォント全体が読み込まれます。 グラフの深度を制限することで、低い深度におけるパッチの組み合わせ爆発を軽減できます。
-
別の方法として、低い深度では、エンコーダーが複数のセグメントを単一のパッチへ 結合し始め、各レベルの分岐数を減らすことができます。
セグメント化の選択
エンコーダーが行う必要のある最も重要かつ複雑な判断の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 # subset_definitions のいずれへも到達できるように、すべての IFT パッチマッピングを # base_font へ追加し、関連するパッチを生成します。 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 グリフキー方式パッチの集合全体に対する グリフ閉包要件は次のとおりです:
-
パッチマップテーブルを通じて、あるフォントサブセット定義の ために読み込まれるパッチに含まれるグリフ集合は、その フォントサブセット定義の グリフ閉包に含まれるグリフの上位集合でなければなりません。
サブセット化ツールが正確に処理すると仮定すると、グリフ閉包要件は同等な動作の要件から導かれます。 サブセット化ツールがグリフ *i* をサブセットへ含めるような フォントサブセット定義がある一方、 § 6.3 グリフキー方式パッチを生成するエンコーダーが、 その定義に対応するパッチ集合からグリフ *i* を省略したとします。 サブセット化ツールが正しい場合、その定義内のコードポイントと機能のある組み合わせを レンダリングする際に同等の動作を保持するため、そのグリフが存在しなければなりません。 これは、その組み合わせをレンダリングする際に増分フォントが 同等に動作しないことを意味します。
したがって、グリフキー方式パッチを利用するエンコーディングを生成する際、 エンコーダーはグリフ閉包要件を満たすように、すべてのパッチ間でグリフをどのように 分配するかを判定しなければなりません。これは主に、セグメントへ割り当てられた コードポイントを確認し、コードポイントによってセグメントへ含まれるグリフを別のグリフへ 置換できる場合などに、対応するパッチへほかのどのグリフを含める必要があるかを 判定する問題です。場合によっては、複数のセグメントが読み込まれたときにのみ必要となる グリフがあり、その場合、そのグリフをそれらのセグメントのいずれかに対応するパッチへ 追加できます(合字または合成済みアクセント文字が該当する場合があります)。 最後に、セグメントの初期分析後、同じグリフが2つ以上のセグメントのパッチを 読み込む際に必要になる場合があります。この状況へ対処する主な方法は5つあります:
-
2つ以上のセグメントを結合して単一のパッチへ含めることができます。 これにより共通グリフの重複を回避できますが、セグメントのサイズは増加します。
-
共通グリフを独自のパッチへ配置し、それを必要とする任意のセグメントとともに 共通パッチの読み込みが開始されるようにマッピングエントリを設定できます。 たとえば、'c' がセグメント 'a' と 'b' に必要な共通セグメントである場合、 次のマッピングエントリを形式 2 マッピングテーブルで設定できます:
-
subset definition a → segment a
-
subset definition b → segment b
-
subset definition a union subset definition b → segment c
-
-
Unicode バリエーションセレクターなどの場合、多数のほかのコードポイントと組み合わされたときに グリフ置換を開始する修飾コードポイントがあります。代替グリフ数が多いため、 修飾コードポイントと適切な基底コードポイントの両方が存在する場合にのみ読み込まれる 独自のパッチへ保持することが望まれます。これは、 形式 2 パッチマップと、 childEntryIndicesによる複数エントリ一致を 使用することで実現できます。設定例については、 例 2:子エントリを持つグリフキー方式パッチを参照してください。
-
別の方法として、グリフデータを複数のパッチへ重複させるコストと引き換えに、 そのグリフをこれらのセグメントに対応する複数のパッチへ含めることができます。
-
最後に、共通グリフを初期フォントへ移動できます。これによりセグメントサイズの増加と グリフデータの重複を回避できますが、初期フォントのサイズが増加します。 また、グリフデータは不要な場合でも常に読み込まれることになります。 これは、多数のセグメントで必要になるグリフや、セグメント化を複雑にするグリフに有用です。
初期フォント内でのデータの事前読み込み
場合によっては、初期ファイルへパッチを適用するオーバーヘッドを回避することが望ましいことがあります。 たとえば、企業のホームページで読み込まれるフォントが、そのページのコンテンツを すでにレンダリングできることが望ましい場合があります。このようなファイルの主な利点は レンダリングレイテンシーの短縮であり、コンテンツを1回のラウンドトリップ後にレンダリングできます。
ダウンロードされるフォントファイルへデータを含める方法は2つあります。 1つは、データが初期ファイル内に含まれるように、増分フォント全体を 単純にエンコードする方法です。このようなデータは、パッチ適用後のどの版のフォントでも 常に利用できます。これは、同じデータが多数の異なるセグメントで必要になる場合に役立ちます。
もう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 では不均等に分散するか、一定になる場合があります。 d1 から d4 を文字列 ID とともに使用するエンコーダーは、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 仕様にあります:
-
CSS Fonts 4 § 15.1 この機能はウェブサイトまたはその他の当事者へどのような情報を公開する可能性があり、 その公開はどのような目的で必要か。 特にプライバシーへ配慮が必要なコンテキストでは、ユーザーエージェントが文書内の すべてのウェブフォントをダウンロードすることを推奨しています。 IFT フォントでは、§ 4.7 フォントの完全な拡張を 使用すると、存在する具体的なコンテンツに関する情報を提供せずに、 利用可能な IFT フォント全体をフェッチできます。別の方法として、 プライバシーへ配慮が必要なコンテキストでは、ユーザーエージェントが、 現在のコンテンツでは不要な追加パッチをランダムに選択し、 実際に必要なパッチを難読化できます。
-
CSS Fonts 4 § 15.8 この仕様はオリジンへどのようなデータを公開するか。同じまたは異なるコンテキストで、 ほかの機能によって公開されるデータと同一のデータについても文書化してください。
コンテンツおよび/またはサイトの作成者が IFT フォントの使用を選択する場合、 上で説明したように、IFT フォントの拡張中にレンダリング対象コンテンツに関する ある程度の情報が送信されるため、そのフォントをエンコードした者と、 フォントの読み込み元サービスの両方を必然的にある程度信頼することになります。 (以下で説明するように、エンコーディングにより注意が払われているほど、 サービスへ置かれる信頼は少なくなるため、両者の間にはバランスがあります。) したがって、プライバシーへ配慮が必要な場合、コンテンツに関する情報が第三者へ送信されることを 防げるため、IFT フォントのセルフホスティングが推奨されます。 さらに、このような場合、異なるオリジンからのフォント読み込みを禁止するように、 コンテンツセキュリティポリシー設定を構成することが推奨されます。
8.2. IFT フォントのエンコーディングとプライバシー
IFT フォントのエンコード方法は、パッチファイルの転送からコンテンツについて 推測できる情報量へ大きな影響を与えます。この節では、IFT フォントをエンコードする際に行われる 選択のプライバシー上の影響を評価する方法について、一般的な指針を示します。
IFT フォントは、関連する有効化条件を持つパッチの集合へ分割されます。 パッチのリクエストが行われると、そのパッチの有効化条件と交差する何らかのものが コンテンツに含まれていることが伝達されます。そのため、フォント内の有効化条件の構造が、 エンコーディングのプライバシー特性を評価するうえで最も重要な側面です。
フォントがサポートする一意のコードポイント、機能、およびデザイン空間構成は、それぞれ 潜在的な信号、すなわち存在するかどうかを提供します。有効化条件は選言または連言にできます。 選言条件では、有効化は条件内の個々の項目の少なくとも1つが存在したことだけを伝えるため、 不確実性が生じます。一方、連言パッチは各項目が同時に存在することを必要とするため、 不確実性を加えません。
コードポイントまたは機能の一般的な出現頻度は、その存在が伝える情報量へ影響します。 出現頻度が高い項目は、低い項目より少ない情報しか伝えません。低頻度コードポイントの存在は、 可能なコンテンツ集合をさらに狭めます。大まかには、低頻度項目を含む条件には、 より大きく、粒度の粗い条件を使用するべきであることを意味します。
この仕様の開発中に行われたシミュレーションでは、 4から7項目の最小グループサイズ(選言条件の場合)が、良好な曖昧性を生み出すことが確認されました。 エンコーディングで最小グループサイズを使用することは、パフォーマンス上も適切です。 パッチの粒度が細かすぎると、過度のオーバーヘッドが生じ、パフォーマンスが低下するためです。 低頻度項目は必要になることが少ないため、それらを含むパッチに最小グループサイズを使用しても、 全体的なパフォーマンスへの影響は小さくなります。全体的なパフォーマンスは、 高頻度項目によって左右される傾向があります。
エンコーダーは、生成されたエンコーディング内の各条件を評価し、その実効グループサイズを 判定するべきです。実効グループサイズとは、個々の項目(コードポイント、レイアウトタグ、 デザイン空間)にわたって、その条件の開始に寄与する最小の選言部分条件です。 プライバシーへ配慮が必要なユースケース向けのエンコーディングでは、 エンコーダーはすべての条件が少なくとも4から7の最小グループサイズを持つことを 保証するべきです。たとえば、次の場合を考えます:
-
A or B or C or D:実効グループサイズは4であり、最小要件を満たします。 -
A and B and C AND D:実効グループサイズは1であり、最小要件を満たしません。 -
(A or B or C or D) AND (E or F):(D or E) 部分条件のため、 実効グループサイズは2です。最小要件を満たしません。
ユースケースによって必要なレベルが異なるため、エンコーダーは生成するエンコーディングの プライバシーレベルを構成するための制御を提供するべきです。たとえば、 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 仕様には、過剰なリクエスト数を制限するための複数の緩和策が含まれています:
-
§ 4 フォントサブセットの拡張: 同じ URL を複数回再リクエストすることを禁止し、 拡張処理中に発行できるリクエスト総数へ制限を設けます。
-
パッチファイルを読み込む: ウェブブラウザーの実装で[FETCH]を使用することを指定し、 初期フォント読み込みの CORS 設定と一致させます。その結果、ホスティングサービスが 適切なアクセス制御ヘッダーによってオプトインしない限り、 パッチファイルへのクロスオリジンリクエストは禁止されます。
10. 変更点
2025年7月31日の 勧告候補スナップショット以降(コミット履歴を参照):
- テスト可能な規範的アルゴリズムをマークアップ
- クライアントとエンコーダーの適合性ステートメントを区別し、マークアップとスタイルを追加
- テスト可能なアサーションへスタイルを追加
- 非規範的な注記および導入定義から、意図しない適合性表現(should)を削除
- すべてのテスト可能な(must)アサーションをマークアップ
- 付録 B(例)を非規範的としてマーク
2025年7月15日の 作業草案以降(コミット履歴を参照):
- 参考文献から未使用項目を削除
- 「シェーピング単位」という用語を定義し、公開
2025年2月20日の 作業草案以降(コミット 履歴を参照):
- エンコーダー向けの指針を提供するため、プライバシーの節を拡張。
- 完全な絶対 URL およびホスト名相対 URL の展開例を追加。
- 'url template bytes' からバイトを読み取る方法を明確化。
- 追加のエラー条件を追加:オペコード0(0個のリテラルを挿入)を無効化。 リテラル挿入操作に必要なバイトが残っていない場合は失敗。 失敗する例を追加。
- URL 展開例を、バイト配列に C 構文を使用するように更新。 相対 URL およびクエリパラメーター付き URL を含む、より多様な例を追加。
- TAG レビューを受けて、rfc6570 URI テンプレートを削除し、 オペコードでエンコードされたテンプレートへ置換。
- fetch の呼び出しと processResponseConsumeBody コールバックの使用を追加。
- fetch リクエストの構成に関する、より具体的な情報を追加。
- レビューのフィードバックを受けて、エントリ選択の文言をより明確になるように変更。
- 無効化なしパッチの選択/フェッチ順序を指定。
- URL 解析に失敗した場合の処理を指定。
- 複数パッチが存在する場合のグリフキー方式パッチ適用の最適化に関する注記を追加。
- 形式 2 の解釈では、未指定のエントリ差分/長さの処理が欠けていたため、 その場合の URL を生成する追加手順を追加。
- WOFF2 に関する文言を明確化
- フォント圧縮の節に WOFF2 を推奨する注記を追加。
- 現在の共有 brotli 15 仕様へ更新
- 任意の charstring オフセットの存在を通知するフラグビットを追加。
- CFF テーブルを追加するパッチと charstrings オフセットに関する注記を追加。
- CFF または CFF2 テーブルを持つフォントについて、 CharStrings へのオフセットを持つフィールドをパッチマップへ追加。
- URI テンプレート展開で未定義の変数名を禁止。
- サポートされていない式レベルでエラーとするステートメントを書き換え。
- URL テンプレートをレベル1置換のみに制限。
- rfc3986 URI から whatwg/url へ変更
- 「prefetch list」という用語を定義して使用。
- 無効化パッチ選択で、事前読み込み済みエントリを優先し、ラウンドトリップを最小化。
- URL 事前読み込み一覧を使用するようにフォント拡張アルゴリズムを更新。
- エントリごとの複数 URL を処理するように、形式 2 の解釈およびエントリ削除アルゴリズムを更新。
- エントリごとの複数 URL を任意でサポートするように、形式 2 エンコーディングを再構成。
- グリフキー方式パッチ適用のオフセットサイズに関する指針を追加。
- CFF および CFF2 増分フォントに固有の要件を含む節を追加。
- 機能レジストリ付録を現行版へ更新
2024年7月9日の 作業草案以降(コミット 履歴を参照):
- 子エントリを利用する拡張例を付録 B へ追加
- 形式 2 の解釈で出力するため、以前のエントリをフィルター済み一覧とは別に保持。
- マッピングエントリ内で参照されるエントリを子エントリと命名。
- 参照エントリが交差するかどうかに基づく形へ、コピーインデックス機構を再構成
- 実装作業に基づいて形式 1 および形式 2 のパッチマップエンコーディングを変更 (明確化、エラー処理、見落としの修正など)。
- 増分フォントのキャッシュに関する節を追加。
- 既定のレイアウト機能に関する指針を追加。
- 純粋な brotli パッチ形式を削除し、残るパッチ形式をテーブルキー方式とグリフキー方式に変更。
- IFT フォントがどのコンテンツをレンダリングできるかを確認する手順を追加。
- 明示的なプリフェッチを拡張アルゴリズムへ追加。
- 拡張アルゴリズムの実行例を含む付録 B を追加。
付録 A:既定の機能 タグ
この付録は規範的ではありません。ほとんどのシェーパー実装で既定で使用されると 見なされるレイアウト機能の 一覧を示します。この一覧は次の情報から構成されました:
-
[enabling-typography]で 「既定でオン」と一覧表示されている機能
-
harfbuzz サブセット化ツールの既定集合に含まれる機能。
シェーパーで既定で使用されるレイアウト機能
| タグ | 名前 |
|---|---|
| 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, Table Keyed - Partial Invalidation |
code points: { 'A', 'B', ..., 'Z' }
| //foo.bar/02.tk | 2, Table Keyed - Partial Invalidation |
code points: { '0', '1', ..., '9' }
| //foo.bar/03.tk | 2, Table Keyed - Partial Invalidation |
code points: { 'a', 'b', ..., 'z',
'A', 'B', ..., 'Z' }
| //foo.bar/04.tk | 2, Table Keyed - Partial Invalidation |
code points: { 'a', 'b', ..., 'z',
'A', 'B', ..., 'Z',
'0', '1', ..., '9' }
| //foo.bar/05.tk | 2, Table Keyed - Partial Invalidation |
| テーブル = "IFTX" | 互換性 ID = 0x0000_0000_0000_0002 | |
|---|---|---|
| サブセット定義 | URL | 形式番号 |
code points: { 'a', 'b', ..., 'm' }
| //foo.bar/01.gk | 3, Glyph Keyed |
code points: { 'n', 'o', ..., 'z' }
| //foo.bar/02.gk | 3, Glyph Keyed |
code points: { 'A', 'B', ..., 'M' }
| //foo.bar/03.gk | 3, Glyph Keyed |
code points: { 'N', 'O', ..., 'Z' }
| //foo.bar/04.gk | 3, Glyph Keyed |
code points: { '0', '1', ..., '9' }
| //foo.bar/05.gk | 3, Glyph Keyed |
最適化された拡張例
注:この実行例は、対象サブセット定義に合わせて フォントを拡張するために必要なラウンドトリップ数の削減を目指す、 最適化されたクライアントで実装される場合として説明されています。 この最適化された実行は拡張アルゴリズムへ完全に適合していますが、 一部の URL(グリフキー方式 URL)を拡張アルゴリズムで指定されるより早く読み込みます。 これらのパッチは先行するテーブルキー方式パッチによって無効化されないため、 これは許可されます。
入力:
-
上で定義された IFT および IFTX テーブルを持つ初期フォント。
-
対象サブセット定義:code points = {'f', 'P'}
反復 1:
-
手順1から6 - 初期フォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/01.tk
-
//foo.bar/02.tk
-
//foo.bar/04.tk
-
//foo.bar/05.tk
-
//foo.bar/01.gk
-
//foo.bar/04.gk
-
-
手順8 - その集合から1つのエントリを選択しなければなりません。 完全無効化エントリはないため、部分無効化エントリ(//foo.bar/*.tk)を1つ 選択しなければなりません。§ 4.4 無効化パッチの選択に 従うと、候補エントリと対象サブセット定義との共通部分は次のとおりです:
-
//foo.bar/01.tk - {'f'}
-
//foo.bar/02.tk - {'P'}
-
//foo.bar/04.tk - {'f', 'P'}
-
//foo.bar/05.tk - {'f', 'P'}
//foo.bar/01.tk と //foo.bar/02.tk の共通部分はどちらも、 //foo.bar/04.tk および //foo.bar/05.tk の真部分集合であるため、 選択基準を満たしません。したがって、//foo.bar/04.tk または //foo.bar/05.tk が残ります。 //foo.bar/04.tk はパッチマップ内で最初に一覧表示されているため、これが選択されます。
-
-
手順9 - 選択されたパッチ //foo.bar/04.tk がフェッチされます。 さらに最適化として、2つのグリフキー方式パッチ //foo.bar/01.gk および //foo.bar/04.gk のフェッチも同時に開始されます。テーブルキー方式パッチ //foo.bar/04.tk は部分無効化であり、これは2つのグリフキー方式パッチが //foo.bar/04.tk の適用後も有効であることを意味します。したがって、 クライアントは2つのグリフキー方式パッチが将来の反復で必要になると予想し、 この時点でそれらの読み込みを開始できます。
-
手順10 - フェッチされたパッチ //foo.bar/04.tk を初期フォントへ適用します。 このパッチは glyf および loca を除くすべてのテーブルを更新し、 コードポイント 'a' から 'Z' までのサポートを追加します。 さらに、"IFT " テーブル内のマッピングが次のように更新されます:
テーブル = "IFT " 互換性 ID = 0x0000_0000_0000_0006 サブセット定義 URL 形式番号 code points: { '0', '1', ..., '9' }//foo.bar/08.tk 2, Table Keyed - Partial Invalidation 次の変更に注意してください:
-
'a'、...、'z'、および 'A'、...、'Z' のデータを持つすべてのエントリが削除され、 残りの '0'、...、'9' コードポイント用の1つのエントリだけが残っています。
-
フォントバイナリが変更されたため、以前一覧表示されていたテーブルキー方式パッチは 有効ではなくなりました。その結果、互換性 ID が変更され、残りの '0'、...、'9' エントリの URL も変更されました。新しい URL //foo.bar/08.tk にあるパッチは、更新後のフォントと互換性があります。
-
反復 2:
-
手順2から6 - 前の反復で更新されたフォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/01.gk
-
//foo.bar/04.gk
-
-
手順8 - その集合から1つのエントリを選択しなければなりません。 無効化なしパッチのみが残っているため、クライアントはどちらを選択してもかまいません。 この場合は最初の //foo.bar/01.gk を選択します。
-
手順9 - //foo.bar/01.gk のフェッチは反復1で以前に開始されています。
-
手順10 - フェッチされたパッチ //foo.bar/01.gk を現在のフォントサブセットへ適用します。 このパッチは glyf および loca テーブルへコードポイント 'a' から 'm' の グリフデータを追加します。さらに、"IFTX" テーブル内のマッピングが更新され、 //foo.bar/01.gk のエントリが削除されます。ほかのエントリの互換性 ID および URL は 変更されません。
反復 3:
-
手順2から6 - 前の反復で更新されたフォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/04.gk
-
-
手順8 - 1つのエントリが残っているため、それを選択します。
-
手順9 - //foo.bar/04.gk のフェッチは反復1で以前に開始されています。
-
手順10 - フェッチされたパッチ //foo.bar/04.gk を現在のフォントサブセットへ適用します。 このパッチは glyf および loca テーブルへコードポイント 'N' から 'Z' の グリフデータを追加します。さらに、"IFTX" テーブル内のマッピングが更新され、 //foo.bar/04.gk のエントリが削除されます。ほかのエントリの互換性 ID および URL は 変更されません。
反復 4:
-
手順2から6 - 交差するエントリが残っていないため、アルゴリズムは終了します。 フォントサブセットが返され、対象サブセット定義によってカバーされる任意の コンテンツをレンダリングする準備が整います。
例 2:子エントリを持つ グリフキー方式パッチ
この例では、IFT フォントに、UVS 置換用パッチの包含を正しく処理するため、子エントリを利用する § 6.3 グリフキー方式パッチの集合が含まれます。 基本グリフの各集合には、バリエーションセレクターによって置換される代替グリフの集合があります。 これらは別個のパッチに保持されます。代替グリフパッチは、基本グリフと バリエーションセレクターが同時に存在する場合にのみ読み込まれるよう、 子エントリを通じて構成されます。
初期フォント:次の IFT パッチマッピングを含みます。注: サブセット定義でコードポイント、機能、デザイン空間、または子エントリの集合が指定されていない場合、 それらは既定で空集合になります。
| テーブル = "IFT " | 互換性 ID = 0x0000_0000_0000_0001 | |||
|---|---|---|---|---|
| サブセット定義 | URL | 形式番号 | 無視するか | 注記 |
code points:
{ 'a', 'b', ..., 'm' }
| //foo.bar/01.gk | 3, Glyph Keyed | いいえ | |
code points:
{ 'n', 'o', ..., 'z' }
| //foo.bar/02.gk | 3, Glyph Keyed | いいえ | |
code points: { VS1 }
| N/A | 3, Glyph Keyed | はい | |
child entries: [0, 2], match mode: conjunctive | //foo.bar/03.gk | 3, Glyph Keyed | いいえ | VS1 によって有効化される {'a', ..., 'm'} の代替グリフを含む |
child entries: [1, 2], match mode: conjunctive | //foo.bar/04.gk | 3, Glyph Keyed | いいえ | VS1 によって有効化される {'n', ..., 'z'} の代替グリフを含む |
拡張例 1
入力:
-
上で定義された IFT テーブルを持つ初期フォント。
-
対象サブセット定義:code points = {'f'}
反復 1:
-
手順1から6 - 初期フォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/01.gk
-
-
手順8から10 - パッチは //foo.bar/01.gk の1つだけであるため、 それを選択し、読み込み、適用します。
反復 2:
-
手順2から6 - 交差するエントリが残っていないため、アルゴリズムは終了します。 フォントサブセットが返され、対象サブセット定義によってカバーされる任意の コンテンツをレンダリングする準備が整います。
拡張例 2
入力:
-
上で定義された IFT テーブルを持つ初期フォント。
-
対象サブセット定義:code points = {'f', VS1}
反復 1:
-
手順1から6 - 初期フォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/01.gk
-
//foo.bar/03.gk
-
-
手順8 - 1つのエントリを選択する必要があります。この場合、クライアント実装は どちらを選択してもかまいません。//foo.bar/01.gk が選択されます。
-
手順9 - 交差する両方のエントリが無効化なしであるため、 両方を同時に読み込めます。
-
手順10 - //foo.bar/01.gk をフォントへ適用します。 マッピングテーブルが更新され、//foo.bar/01.gk のエントリが無視されるものとして マークされます。
反復 2:
-
手順1から6 - 現在のフォント内のすべてのエントリへ エントリの交差を確認する確認を 適用すると、次のパッチエントリが交差します:
-
//foo.bar/03.gk
-
-
手順8から10 - パッチは //foo.bar/03.gk の1つだけであるため、 それを選択して適用します(前の反復で読み込み済みです)。
反復 3:
-
手順2から6 - 交差するエントリが残っていないため、アルゴリズムは終了します。 フォントサブセットが返され、対象サブセット定義によってカバーされる任意の コンテンツをレンダリングする準備が整います。