Uniscribe でテキストを表示する
アプリケーションでは、Uniscribe API 関数を使用して、文字体裁と国際テキストの表示と編集をサポートできます。 Uniscribe は段落をテキスト表示の単位として使用し、Uniscribe 機能は段落全体に対して使用する必要があります。
テキストの表示に Uniscribe を使用する場合、通常は Uniscribe を使用して、書式設定 ("レイアウト") プロセスを進める必要があります。 アプリケーションは、テキストの段落を、"実行" と呼ばれる同じスタイルの文字列に分割します。 スタイルは特定の実装によって決まりますが、通常はフォント、サイズ、色などの属性が含まれます。 実行を定義する際、アプリケーションでは、字句解析ツールで使用するために保持されている言語やロケール データなどの他の情報も使用できます。 たとえば、あるアプリケーションでは、主に英語のテキストの一節をフランス語でレンダリングしたものを、別の実行として扱う場合があります。
すべての段落の実行が決定されると、アプリケーションは各段落を同じスクリプトと方向 ("項目") を含む文字列に分割します。 アプリケーションは、項目情報を適用して、スクリプトと方向が一意で、かつ単一の項目 ("範囲") 内に完全に収まる実行を生成します。
項目を範囲に分割するのは若干任意ですが、範囲は、スクリプトで定義された連続する 1 つ以上の分割できない文字グループ ("クラスター") で構成される必要があります。ヨーロッパ言語の場合、クラスターは通常 1 つのコード ページ文字または Unicode コード ポイントに対応し、単一のグリフで構成されます。 ただし、タイ語などの言語では、クラスターはグリフのグループであり、複数の連続する文字またはコード ポイントに対応します。 たとえば、タイ語のクラスターには、子音、母音、トーン マークが含まれる場合があります。 クラスターを壊さないようにするため、アプリケーションは通常、可能な限り長い範囲を使用するか、独自の字句解析情報を使用して、クラスターの中央ではない場所の範囲の間で区切る必要があります。
各範囲のクラスターを特定したら、アプリケーションは各クラスターのサイズを決定する必要があります。 Uniscribe を使用してクラスターを合計し、各範囲のサイズを決定します。 次に、アプリケーションは、行をオーバーフローするまで、つまり余白に達するまで範囲のサイズを合計します。 行をオーバーフローする範囲は、現在の行と次の行の間で分割されます。 各行に対して、アプリケーションは、各範囲の視覚的位置から論理的位置へのマップを構築します。 次に、アプリケーションは、各範囲のコード ポイントをグリフに形成し、そのグリフを配置してレンダリングすることができます。
アプリケーションはテキスト レイアウトを 1 回だけ実行します。 その後、表示目的でグリフと位置を保存するか、速度とメモリとでトレードオフして、テキストが表示されるたびに生成します。 一般的なアプリケーションでは、レイアウト プロセスが 1 回実装され、テキストが表示されるたびにグリフと位置を生成します。
複雑なスクリプトを使用するアプリケーションでは、レイアウトと表示に対するシンプルなアプローチで次のような問題が発生します。
- 複雑なスクリプト文字の幅は、そのコンテキストによって異なります。 シンプルなテーブルで幅を保存することはできません。
- タイ語のようにスクリプトで単語を区切るには、辞書のサポートが必要です。 たとえば、タイ語の単語間に区切り文字は使用されません。
- アラビア語、ヘブライ語、ペルシャ語、ウルドゥー語、およびその他の双方向テキスト言語は、表示前に並べ替える必要があります。
- 複雑なスクリプトを簡単に使用するには、多くの場合、何らか形式でフォントが関連付けられる必要があります。
Uniscribe が表示単位として段落を使用している事実は、アプリケーションがこれらの複雑なスクリプトの問題に適切に対処するのに役立ちます。
Note
段落のセクションが複雑なスクリプトでない場合でも、段落全体に対して Uniscribe を使用する必要があります。
次の表に示すように、Uniscribe バージョン 1.6 以降では、OpenType タグを利用するいくつかの関数がサポートされています。 これらの関数は、対応する標準の Uniscribe 関数に置き換えることができます。 通常、アプリケーションは、完全にどちらか一方のセットの関数から動作する必要があり、関数を "ミックス アンド マッチ" するべきではありません。
標準の Uniscribe 関数 | 同等の OpenType 関数 |
---|---|
ScriptItemize | ScriptItemizeOpenType |
ScriptShape | ScriptShapeOpenType |
ScriptPlace | ScriptPlaceOpenType |
Uniscribe を使用してテキストをレイアウトする
アプリケーションでは、次の手順を使用して、Uniscribe でテキスト段落をレイアウトできます。 この手順では、アプリケーションが既に段落を実行に分割していることを前提としています。
ScriptRecordDigitSubstitution は、開始時または WM_SETTINGCHANGE メッセージを受信する場合にのみ呼び出します。
(省略可能) ScriptIsComplex を呼び出して、段落に複雑な処理が必要かどうかを判断します。
(省略可能) Uniscribe を使用して双方向テキストや桁の置換を処理する場合は、ScriptApplyDigitSubstitution を呼び出して、SCRIPT_CONTROL 構造体と SCRIPT_STATE 構造体を ScriptItemize への入力として準備します。 この手順をスキップしても桁の置換が必要な場合は、各国の桁を Unicode U+0030 から U+0039 (ヨーロッパの桁) に置き換えます。 桁の置換の詳細については、「桁の形状」を参照してください。
ScriptItemize を呼び出して、段落を項目に分割します。 文字の入力にキーボード レイアウトが使用されている場合など、桁の置換に Uniscribe を使用せず、双方向の順序がわかっている場合は、ScriptItemize を呼び出します。 呼び出しで、SCRIPT_CONTROL 構造体と SCRIPT_STATE構造体の Null ポインターを指定します。 この手法では、形成エンジンのみを使用して項目を生成し、エンジン情報を使用して項目を並べ替えることができます。
Note
通常、左から右へのスクリプトでのみ動作し、桁の置換を行わないアプリケーションでは、SCRIPT_CONTROL 構造体と SCRIPT_STATE 構造体にのみ Null ポインターを渡す必要があります。
項目情報を実行情報とマージして範囲を生成します。
ScriptShape を呼び出してクラスターを特定し、グリフを生成します。
ScriptShape がコード USP_E_SCRIPT_NOT_IN_FONT または出力に不足しているグリフが含まれる S_OK を返し、別のフォントから文字を選択します。 ScriptShape に渡された SCRIPT_ANALYSIS 構造体の eScript メンバーを SCRIPT_UNDEFINED に設定することで、別のフォントに置き換えるか形成を無効にします。 詳細については、「フォント フォールバックの使用」を参照してください。
ScriptPlace を呼び出して、連続するそれぞれの範囲のグリフの詳細な幅と x と y の配置を生成します。 これは、テキスト サイズが考慮されるようになる最初の手順です。
行がオーバーフローするまで範囲のサイズを合計します。
論理属性で fSoftBreak メンバーと fWhiteSpace メンバーを使用して、単語の境界の範囲を区切ります。 実行中の単一のクラスターを中断するには、ScriptBreak を呼び出して返される情報を使用します。
Note
前の範囲の最後の文字が必要になるため、範囲の最初のコード ポイントを単語のブレーク ポイントにするかどうかを決定します。 たとえば、ある範囲がコンマで終わる場合は、次の範囲の最初の文字を単語のブレーク ポイントと見なします。
段落内の各行に対して、手順 6 から手順 10 を繰り返します。 ただし、行の最後の実行を中断する場合はScriptShape を呼び出して、その実行の残りの部分を次の行の最初の実行として再形成します。
Uniscribe を使用してテキストを表示する
アプリケーションでは、次の手順を使用してテキスト段落を表示できます。 この手順では、アプリケーションが既にテキストをレイアウトしており、レイアウト プロセスからグリフと位置を保存していないことを前提としています。 速度が心配である場合、アプリケーションはレイアウト手順からグリフと位置を保存し、表示手順の手順 2 から開始できます。
Note
テキストに右から左へのスクリプトの文字が含まれず、双方向制御文字も含まず、左から右への基本埋め込みレベルを使用している場合、アプリケーションで手順 2 を省略できます。
実行ごとに、次の手順を実行します。
- 前回の実行以降にスタイルが変更された場合は、デバイス コンテキストに対するハンドルを解放して再び取得することで更新します。
- ScriptShape を呼び出して、実行のグリフを生成します。
- ScriptPlace を呼び出して、各グリフの詳細な幅と x,y オフセットを生成します。
次の手順を実行して、行内の実行の正しい視覚的順序を確立します。
- 双方向の埋め込みレベルの配列を範囲ごとに 1 つずつ抽出します。 埋め込みレベルは、(SCRIPT_ITEM) si.(SCRIPT_ANALYSIS) a によって付与されます。 (SCRIPT_STATE) s.uBidiLevel。
- この配列を ScriptLayout に渡して、視覚的位置のマップを論理的位置に生成します。
(省略可能) テキストを両端揃えするにはScriptJustify を呼び出すか、テキストの専門知識を使用します。
視覚から論理へのマップを使用して、実行を視覚的な順序で表示します。 行の左端から ScriptTextOut を呼び出して、マップ内の最初のエントリで指定された実行を表示します。 マップ内の後続の各エントリに対してl ScriptTextOut を呼び出し、前に表示した実行の右側に指定された実行を表示します。
手順 2 を省略する場合は、行の左端から開始し、ScriptTextOut を呼び出して最初の論理実行を表示し、前の実行の右側に各論理実行を表示します。
段落のすべての行に対して、上記の手順を繰り返します。
関連トピック