ネイティブTextBoxへの双方向サポートの追加

はじめに



双方向テキストのサポートを自分のテキストエディタに追加した経験を長年共有したいと考えていましたが、利己的な考慮が私をこれに移動させました。 この記事では、アラビア語をサポートするためにGNU FriBidiをTextBoxに統合する方法を説明します。 アラビア語のテキストをサポートする良い資料を見つけるのが難しいので、私の記事が役に立つことを願っています。



持っていたもの



アラビア語のサポートを追加する必要が生じる頃には、TextBoxの自己作成コントロールはすでに多くのことを知っていました:テキストの編集、カーソルの制御、テキストの一部の選択、貼り付け、切り取り、多くの行のサポート、整列など もちろん、彼はWordと比較することはできませんが、基本的なことをする方法は知っていました。 TextBoxは、WindowsおよびMac OS Xのアプリケーションでも使用されていました。



こんにちはHabru



グリフ画像を取得するために、FreeTypeがOpenGL出力に使用されましたが、これは重要ではありません。 FreeTypeのコントロールは、グリフの位置を正しく計算するためのグリフのメトリックを受け取りました。



FreeType文字メトリック



タスクは何ですか



皆さん、アラビア語のサポートをすぐに追加しましょう
-それが仕事でした。



当時、アラビア語については、右から左に書かれており、文字が単語でつながって合字になることを知っていました。 しかし、実際には、すべてが少し複雑になりました

この機能を使用するには、ライブラリを選択する必要があります。 通常、これらの目的には、 GNU FriBidiPangoHarfBuzzが使用されます。 GNU FriBidiを選んだ理由は 最も簡単で、最小限の変更が必要であるように見えました。



アラビア語のいくつかの機能



一見、アラビア語(اللغةالعربية)はロシア語や英語とは非常に異なっているようです。 しかし、その違いは一見するとそれほど大きくありません。 実装中に、次の機能に出会いました。



  1. アラビア語は右から左、つまり 最初の文字は右端の文字です。 この場合、キーを右または左に押すと、カーソルも右または左に移動します。 ロシア語とは異なり、右を押すと、カーソルは行内の位置を増やし、アラビア語では減少します。

    Delはカーソルの後の文字を削除し、前の文字をバックスペースします。 アラビア語の場合、Delは右の文字を削除し、左の文字をバックスペースします。

    しかし、アラビア語とロシア語が同じ行に混在しているときに楽しみが始まります。

    ブレンドされたテキスト内でカーソルを移動します。

    これは、マウスを使用したテキストの選択にも適用されます。 以下のテキストをマウスで選択してみてください。

    اللغةالعربيةロシア語اللغةالعربية英語言語اللغةالعربية


  2. 2番目の機能は合字です。 単語を合字のように見せるために、ほとんどすべての文字には、単語内の異なる位置(末尾、先頭、中央)に異なるUnicode文字があります。 気にする人は、 ウィキペディアに良い表があります。

  3. 合字。 2つの文字が次々に移動する場合は、1文字に置き換えることができます。 たとえば、これらの2つの文字 "ل" "آ"はこのلآに変換されます。

  4. ダイアクリティックス。 ロシア語の場合、分音記号は「¨」が「é」または「˘」が「」です。 これらの発音区別記号には特別な問題はありません。 これらはすでにこれらの文字のグリフに「縫い付け」られています。 つまり 「I」と「Y」はフォント内の個別の文字です。Yを取得するために個別のチェックマークを取って文字「I」に追加する必要はありません。

    アラビアの発音区別記号の例

    アラビア語のアルファベットの文字は黒で表示され、母音(発音区別記号)は灰色で表示されます。

    写真からわかるように、興味深いケースが1つあります。

    1文字以上の発音区別記号

    1つの文字に同時に2つの発音区別記号。

  5. まだ機能はあると思いますが、それらに遭遇せず、ユーザーは報告しませんでした。



実装



GNU FriBidiの使用方法


GNU FriBidiの使用は非常に簡単です。 ライブラリは、文字のUnicode文字列を受け入れ、多くの関数を呼び出した後、単語内の文字の位置、文字、文字列内の文字の位置を考慮して、Unicode文字列を返します。

int nLength; //   uint* pInputLine; // /  Unicode FriBidiCharType* pBidiTypes; //      FriBidiLevel *pEmbeddingLevels; // Embedding Levels FriBidiJoiningType *pJtypes; //    FriBidiArabicProp *pArProps; //      FriBidiStrIndex *pPositionLogicToVisual; //     ------------------------- //     . fribidi_get_bidi_types(pInputLine, nLength, pBidiTypes); //  Resolving Embedding Levels (http://www.unicode.org/reports/tr9/#Resolving_Embedding_Levels)   . FriBidiParType baseDirection = FRIBIDI_PAR_RTL; FriBidiLevel resolveParDir = fribidi_get_par_embedding_levels(pBidiTypes, nLength, &baseDirection, pEmbeddingLevels); //       fribidi_get_joining_types(pInputLine, nLength, pJtypes); //     . memcpy(pArProps, pJtypes, nLength * sizeof(FriBidiJoiningType)); fribidi_join_arabic(pBidiTypes, nLength, pEmbeddingLevels, pArProps); //   Unicode    .         ,     . fribidi_shape (FRIBIDI_FLAG_SHAPE_MIRRORING | FRIBIDI_FLAG_SHAPE_ARAB_PRES | FRIBIDI_FLAG_SHAPE_ARAB_LIGA, pEmbeddingLevels, nLength, pArProps, pInputLine); //            . FriBidiLevel res = fribidi_reorder_line(FRIBIDI_FLAGS_ARABIC, pBidiTypes, nLength, 0, baseDirection, pEmbeddingLevels, pInputLine, pPositionLogicToVisual);
      
      





テキストボックスは、文字とカーソルの位置を更新する前にGNU FriBidiの呼び出しを追加しました。



既存のコードの変更


文字の位置の計算を簡単にするために、データ構造を少し複雑にする必要がありました。 最初は、カーソルが移動する文字のリストがあり、各文字の位置を計算するために同じリストが使用されました。

役職 0 1 2 3 4 5
手紙 P p そして e t


アラビア語の場合、2つのリストを追加する必要がありました。最初のリストは、文字、つまりユーザー入力の順番の数字の論理ストレージです。 2番目のリストは、左から右へ(アラビア語でも)描かれた順番の文字です。 このアプローチを使用すると、段落の配置が実装しやすくなります。

ブレンドされたテキストの例:

ブレンドされたテキストの例

役職 0 1 2 3 4 5 6 7 8
入力順 خ ط أ ああ w そして b でも
表示順序 ああ w そして b でも أ ط خ


概して、GNU FriBidiは文字表示リストの作成に使用されました。

したがって、すべてのカーソル作業は、文字の入力、選択、削除、移動という入力順序の文字のリストを使用して実行されました。 また、表示と整列のために、文字のリストが表示順序で使用されました。 ちなみに、ロシア語の場合、両方のリストは同じです。



結果


その結果、アラビア語のサポートをかなり迅速に追加できました。 すべてが機能しているように見えました。

やった!

しかし、その後、アラブのユーザーから発音区別符号が正しく表示されないという報告を受けました。 FreeTypeは、発音区別記号が個別に追加される場合の難しいケースに対処できませんでした。 FreeTypeには情報がないため、 批評家の位置は、それが使用される文字によって異なります。



次は...



分音記号のサポートを追加するには、ソリューションを複雑にする必要がありましたが、これは次の記事のトピックです。 私はただ一つのことしか言えません、私はこれにHarfBuzzを使用しました。



免責事項



はい、バイクを書いているので、TextBoxをゼロから実装しています。 そして、私たちはパンゴを使用しませんでした、なぜなら彼とは以前は悪い経験でしたから。 たぶん、Pangoの方が簡単でしょう。 私はアラビア語を話せません。何かを見逃したかもしれません。



便利なリンク






All Articles