Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ゼロから実装する縦書きTextViewとその周辺技術 / Vertical TextView from Scratch and Related Technologies

cc4966
February 08, 2019

ゼロから実装する縦書きTextViewとその周辺技術 / Vertical TextView from Scratch and Related Technologies

ゼロから実装する縦書きTextViewとその周辺技術

発表者: 六々 (@496_)
View + InputConnection + Editable + Bitmapを使って縦書きのTextViewを実装した話をします。
TextVIewやStringを使わなくても文字入力ができるViewを作ることが可能です。

iOS / UWP / Windows / macOS / Ubuntuなどの他プラットフォームでの縦書きTextViewの実装経験も交えて、Androidでの縦書きTextView実装の概要と注意点について話します。
また周辺技術としてUnicodeの話、OpenTypeの仕様を中心としたフォントの話もあります。

# 内容
- TextViewとは何者か
- 文字列入力系としての側面
- フォント描画系としての側面
- IMEとは何か
- 文字入力の仕組み
- IMEとアプリの関係性
- InputConnectionの罠
- StringとEditableについて
- StringとAndroid Studioの関係 (閑話)
- UnicodeとフォントからBitmapが作られるまで
- テキストレンダリングエンジン実装の概要
- フォントの役割とOpenTypeの仕様
- OpenTypeや文字列描画系から見たUnicode Emoji事情 (閑話)
- 昨今のAndroid内のフォント事情
- Variable Fontの登場
- 縦書きTextView実装で気をつけるべきこと

受講対象者
文字についてUnicode / IME / フォントと言われて何となくイメージが浮かぶ方を対象にしています。

特に: TextViewの独自実装に興味のある方 / 文字入力システムに興味のある方 / 文字描画システムに興味のある方 / 縦書きに興味のある方 に聞いてもらえると嬉しいです。

cc4966

February 08, 2019
Tweet

More Decks by cc4966

Other Decks in Programming

Transcript

  1. ゼロから実装する
    縦書きTextViewと
    その周辺技術
    六々@496_ / DroidKaigi 2019
    Room 6 - 2019/02/08 15:40-16:30
    Keynoteに続いてGoogle スライドも縦書きができなかった

    View full-size slide

  2. 自己紹介
    ● 六々(ろくろく)
    ● @496_
    ● 趣味でTATEditorという縦書きエディタを作ってます
    ○ Windows / macOS / Ubuntu版は公開中
    ○ Android / iOS / UWP版は開発中

    View full-size slide

  3. TATEditor
    ● クロスプラットフォームな縦書きエディタ
    ● C/C++製で2013年から公開

    View full-size slide

  4. 縦書きTextViewって?
    ● カスタムViewの話です
    ○ 縦書きでテキストが表示できる
    ○ 縦書きでテキストが編集できる
    ● AndroidのTextView / EditTextに相当

    View full-size slide

  5. 縦書きTextView
    ● テキストが入力できてる!
    ● 縦書きで表示されてる!

    View full-size slide

  6. 今回話す内容
    ● TextViewの話
    ● 文字コードという概念
    ● フォントという概念
    ● 縦書きテキストの作り方
    ● IMEの話
    ● AndroidのIMEをViewから利用する方法
    ● AndroidのTextViewのその他の便利機能について

    View full-size slide

  7. TextViewとは?

    View full-size slide

  8. AndroidのTextView / EditText
    ● ViewerであるTextView
    ● EditorであるEditText
    ● 実はちょっと違う

    View full-size slide

  9. TextViewとEditTextの違い
    ● テキストを選択する関数が生えているかどうか
    ● getTextでEditableが返ることが保証されているかどうか
    ● デフォルトのプロパティの違い
    ● TextViewでもテキスト編集は可能
    ○ android:enabled="true"
    ○ android:focusableInTouchMode="true"
    ○ android:inputType="text"
    ○ android:textIsSelectable="true"

    View full-size slide

  10. TextViewとは?

    View full-size slide

  11. AndroidのTextViewの機能
    ● テキストを表示できる
    ● テキストを入力できる
    ● テキストを選択できる

    View full-size slide

  12. TextViewとは?
    ● どのOSでも標準のTextViewが用意されています
    →非常にプリミティブなView

    View full-size slide

  13. TextViewとは?
    ● プリミティブなViewだけどちっともシンプルではない
    ● 色々なものが交わる魔窟
    ○ 入力装置(≒人間)
    ○ アプリ
    ○ OS
    ○ IME

    View full-size slide

  14. 一方、縦書きのTextViewは
    ● 縦書きのTextViewが横書きのTextViewと違うところ
    ○ テキスト表示が縦書き(見た目だけの問題)

    View full-size slide

  15. 一方、縦書きのTextViewは
    ● 縦書きのTextViewが横書きのTextViewと違うところ
    ○ テキスト表示が縦書き(見た目だけの問題)
    ○ ほとんどのOSに標準で用意されてない

    View full-size slide

  16. 一方、縦書きのTextViewは
    ● 縦書きのTextViewが横書きのTextViewと違うところ
    ○ テキスト表示が縦書き(見た目だけの問題)
    ○ ほとんどのOSに標準で用意されてない
    ● 縦書きのTextViewを使いたければ作る必要がある
    ○ 一般的なOSなら縦書き含む独自のTextViewが作れる
    ○ そのためには何をすると良いのかを話します

    View full-size slide

  17. タイトルの「ゼロから実装する」について
    ● TextViewやEditTextは使いません
    ○ 縦書きができないので
    ● drawTextなどは使いません
    ○ 縦書きができないので

    View full-size slide

  18. タイトルの「ゼロから実装する」について
    ● 文字コードは作りません
    ○ Unicodeを使います
    ● フォントは作りません
    ○ 端末にインストールされているフォントを使います
    ● IMEは作りません
    ○ 端末にインストールされているIMEを使います
    ● ViewとdrawBitmapは使います

    View full-size slide

  19. アウトライン
    ● TextViewの主な機能の縦書きでの実装可能性
    1. テキストを表示する
    2. テキストを編集する
    3. その他の便利な機能

    View full-size slide

  20. TextViewの機能その1
    テキストを表示する

    View full-size slide

  21. テキストを表示する
    ● このテキストはどうやって表示されていますか?

    View full-size slide

  22. テキストを表示する
    ● このテキストはどうやって表示されていますか?
    ○ ざっくりと言うと画像が表示されています

    View full-size slide

  23. テキストを表示する=画像を作る
    入力 テキスト描画系 出力
    テキスト 画像

    View full-size slide

  24. 画像、Androidなら例えばBitmap
    ● Bitmapを作ればディスプレイに表示できる
    ○ 中身はARGB_8888が推奨されている
    ■ 32bitで上位ビットからAlpha, Red, Green, Blue
    ■ 0xFFFFFFFFだと白
    ○ 表示方法
    ■ ViewのonDrawでcanvas.drawBitmap
    ■ ImageViewでも良い

    View full-size slide

  25. テキスト描画系(テキスト描画エンジン)
    入力 テキスト描画系 出力
    テキスト 画像
    この魔法の箱が
    欲しい

    View full-size slide

  26. テキスト描画系という魔法の箱
    ● 本来ならCanvasのdrawTextがこの「魔法の箱」に相当
    ● drawTextは縦書きができない
    ○ 魔法の箱を自作します

    View full-size slide

  27. この「テキスト描画系」を分解していきます
    入力 テキスト描画系 出力
    テキスト 画像

    View full-size slide

  28. テキストも所詮ただのバイト列
    入力 テキスト描画系 出力 画像
    文字コードの
    知識
    バイト列
    (テキスト)

    View full-size slide

  29. 文字コード
    ● 機械やそれを使う人同士でのプロトコル
    ○ みんなでこのバイト列はこの文字に相当するものとして扱
    いましょうという約束
    ○ でっかい表
    ● プロトコルを取り違えてしまうのがいわゆる文字化け
    ● 最近だとだいたいUnicode

    View full-size slide

  30. テキストを表示するためにはフォントが必要
    入力 テキスト描画系 出力 画像
    文字コードの
    知識
    参照する
    バイト列
    (テキスト)
    フォントファイ

    View full-size slide

  31. フォント
    ● 文字コードのバイト列から人間の目と脳に優しい画像情報を
    生成するための全ての情報を格納したファイル
    ○ どの文字がどういう形なのか
    ○ 文字の大きさはどれくらいなのか
    ● 最近だとだいたいOpenTypeフォント
    https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html

    View full-size slide

  32. テキストを表示する
    入力 テキスト描画系 出力
    バイト列 画像
    文字コードの
    知識
    参照する
    (テキスト)
    フォントファイ

    バイト列と文字コードを照ら
    し合わせて適切な文字の形
    状をフォントから取得して画
    像に出力する

    View full-size slide

  33. 用語
    ● コードポイント
    ○ Unicodeに収録されている文字(意味)
    ● グリフ
    ○ OpenTypeフォントに収録されている文字(形状)
    U+0041
    U+3042
    U+5B89
    A


    B


    コードポイント
    グリフ

    View full-size slide

  34. Unicodeについて簡単に
    ● バイト列を文字列として扱うための規格
    ● 符号化文字集合のひとつ
    ○ U+0000 ~ U+10FFFFを文字に対応づけたもの
    ○ U+xxxxがコードポイント、U+後ろは16進数表記
    ● UTF-8 / UTF-16 / UTF-32は文字符号化形式
    ○ U+0000 ~ U+10FFFFの21bitの情報をどのようにバイト
    列で表現するかを定めたもの

    View full-size slide

  35. AndroidのStringとその周辺
    ● AndroidのString (CharSequence) はchar[]で構成される
    ○ charは16bit整数=内部データはUTF-16
    ● 表のInterfaceは下が上を継承している
    Interface Object(実装) 役割
    CharSequence String 文字列へのアクセス
    Spanned SpannedString 文字列とマークアップへのアクセス
    Spannable SpannableString 編集可能なマークアップ
    Editable SpannableStringBuilder 編集可能な文字列とマークアップ

    View full-size slide

  36. 余談: Android StudioとString
    ● Android Studioを使ったAndroidアプリのデバッグ
    ○ ブレークポイントを置くと変数の中身を確認できる
    ○ CharSequenceのtoString()経由でAndroid Studioが取得
    ● これを知らずにデバッグ中にブレークポイントで止めるとクラッ
    シュする問題で困った
    ○ CharSequenceのtoString()は初期前でも空文字列を返す
    ようにした

    View full-size slide

  37. OpenTypeフォントについて簡単に
    ● フォントファイルの仕様のひとつ
    ○ グリフを最大65534個格納できる
    ○ 最初の1つは.notdefと定められている
    ■ いわゆる豆腐
    ○ グリフは基本的にベクター画像として格納されている
    ■ Bitmapにするにはラスタライズする必要がある

    View full-size slide

  38. テキストを画像にするまで
    入力
    出力
    バイト列 画像
    グリフ列
    文字コードの
    知識
    (テキスト)
    コードポイント列
    U+0041 U+3042 U+5B89
    A あ 安
    Aあ安
    フォントファイ

    View full-size slide

  39. Androidとフォント
    ● システムのフォントファイルのありか
    ○ /system/etc/fonts.xml にフォント情報がある
    ■ Android 5.0からはこれだけを見ればよくなった
    https://github.com/google/skia/blob/master/src/ports/SkFontMgr_android_parser.cpp
    ○ fonts.xmlにフォントファイルのパスが記されている
    https://android.googlesource.com/platform/frameworks/base.git/+/master/graphics/java/android/graphics/FontListParser.java
    ■ 普通に開いて読み込むことができる
    ■ FreeTypeを使うとだいたいのことができる

    View full-size slide

  40. 余談: 最近のAndroidとフォント
    ● Variable Font (OpenType 1.8で導入された新機能)
    ○ Android 8.0からVariable Fontをバンドル可能になった
    ○ 合わせてfonts.xmlの仕様も一部拡張されている
    ○ font-weight等が無段階になる機能

    View full-size slide

  41. テキストを画像にするまで
    入力
    出力
    バイト列 画像
    グリフ列
    文字コードの
    知識
    (テキスト)
    コードポイント列
    U+0041 U+3042 U+5B89
    A あ 安
    Aあ安
    フォントファイ

    今ここ

    View full-size slide

  42. UnicodeとOpenTypeをつなぐもの
    ● OpenTypeのcmapテーブル
    ○ コードポイントからグリフのIDへの変換表
    ○ グリフIDの0は.notdefと呼ばれるいわゆる豆腐文字
    U+0041..U+0042
    U+3042..U+0043
    U+5B89
    1: A 2: B
    コードポイント フォント内のグリフ
    3: あ 4: い
    5: 安
    0: (.notdef)
    U+1F389
    cmap

    View full-size slide

  43. テキストを画像にするまで
    入力
    出力
    バイト列 画像
    グリフ列
    文字コードの
    知識
    (テキスト)
    コードポイント列
    U+0041 U+3042 U+5B89
    A あ 安
    Aあ安
    フォントファイ

    今ここ

    View full-size slide

  44. グリフのラスタライズ
    ● 読み込みにはFreeTypeというライブラリがよく使われる
    ○ PostScript (CFF) 系、TrueType系をまとめて扱える
    ○ コードポイントからグリフIDへの変換
    ○ グリフIDを指定したラスタライズ画像の取得
    ■ グリフは基本的にベクター画像

    View full-size slide

  45. グリフ列を画像にするまで
    出力 画像
    グリフ列
    A あ 安 Aあ安
    ラスタライズ画像列
    A, あ, 安
    画像化
    FreeTypeなど

    View full-size slide

  46. グリフ列を画像にするまで
    出力 画像
    グリフ列
    A あ 安 Aあ安
    ラスタライズ画像列
    A, あ, 安
    どこに?
    画像化

    View full-size slide

  47. グリフをテキストエリアに配置する
    ● 以下を繰り返す
    ○ グリフを置く
    ○ グリフの幅だけ進む
    ● ただし、改行文字や折り返しで次の行にジャンプする
    https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html

    View full-size slide

  48. 改行にはUnicodeの知識が必要です
    ● Windowsの改行は\r\n
    ○ Carriage ReturnとLine Feedの間では改行されない
    U+000D CARRIAGE RETURN \r Mac OS 9まで
    U+000A LINE FEED \n Linux / macOS
    U+000C FORM FEED \f
    U+000B TABULATION \v
    U+2028 LINE SEPARATOR
    U+2029 PARAGRAPH SEPARATOR
    U+0085 NEW LINE

    View full-size slide

  49. 改行にはUnicodeの知識が必要です
    ● Windowsの改行は\r\n
    ○ Carriage ReturnとLine Feedの間では改行されない
    U+000D CARRIAGE RETURN \r Mac OS 9まで
    U+000A LINE FEED \n Linux / macOS
    U+000C FORM FEED \f
    U+000B TABULATION \v
    U+2028 LINE SEPARATOR
    U+2029 PARAGRAPH SEPARATOR
    U+0085 NEW LINE
    Carriage Return: 行頭に戻る
    Line Feed: 行を進める

    View full-size slide

  50. グリフ列を画像にするまで
    出力 画像
    グリフ列
    A あ 安 Aあ安
    画像化 {画像, 座標}の列
    A, {0, 0}
    あ, {100, 0}
    安, {200, 0}
    1. グリフを置く
    2. グリフの幅だけ進む
    ただし改行文字で次の行にジャンプ

    View full-size slide

  51. テキストを表示してみる
    ● 簡単のためまずは横書き

    View full-size slide

  52. テキストを折り返してみる
    ● “textarea” という英単語が分割されてしまった……

    View full-size slide

  53. 折り返しにもUnicodeの知識が必要です
    ● UAX #14: Unicode Line Break Algorithm
    ○ Unicode標準の一部
    ○ テキストのどこが折り返し可能かを定義している
    ○ 行頭/行末禁止・分割禁止
    ● ICU (International Component for Unicode)
    ○ これのLineBreakIteratorを使うと良い
    ○ ICUはAndroidにも組み込まれている
    ○ もともとIBM主導のOSSで今はUnicodeに属してる

    View full-size slide

  54. テキストの折り返しを正しく
    ● いい感じですね

    View full-size slide

  55. テキストの折り返しを正しく
    ● いい感じですね
    ハイフネーションという折り返し方法もあ
    りますが、そのあたりのことは 2/8
    12:50~のSeigo Nonakaさんのセッショ
    ン「Best practice for text on Android
    and its internals.」が参考になります

    View full-size slide

  56. ところで縦書き要素はどこに?

    View full-size slide

  57. テキストについて再考
    ● データ上、テキストの進行方向はひとつ
    ○ 配列のindexが増える方向だけ
    ● 一方、画像は2次元情報
    ○ テキストの進行方向は無数にある
    普通は文字が左から右、行は上から下に進む

    View full-size slide

  58. 書字方向(文字の進む方向)
    ● 横書き(左から右)
    ● 右横書き(右から左)
    ○ アラビア語など
    ○ 昔の日本のメディア
    ○ トラックや屋台の右側面の文字
    ● 縦書き(上から下)
    ○ 今回のトピック
    https://commons.wikimedia.org/wiki/File:RIKEN_VITAMIN.png

    View full-size slide

  59. 改行方向(行が進む方向)
    ● 書字方向とは直交する方向
    ○ 横書き(上から下)
    ○ 右縦書き(右から左、vertical-rl)
    ■ 日本語
    ○ 左縦書き(左から右、vertical-lr)
    ■ モンゴル語(モンゴル文字を使った場合)
    ● 今はキリル文字が一般に使われている

    View full-size slide

  60. 余談: その他の書字方向
    ● 牛耕式(Boustrophedon)
    ○ 書字方向が右から左、左から右と交互に繰り返す
    ○ 古代ギリシャ語
    ● 螺旋形
    ○ ファイストス円盤(未解読文字)
    ○ Unicodeにも収録されている
    ■ U+101D0~U+101FD

    View full-size slide

  61. 縦書きと横書きの違い
    ● 縦書きも横書きも内部の文字列は同じ
    ○ 表示されている画像が違うだけ

    View full-size slide

  62. 縦書きの要件
    ● 文字が水平方向ではなく、垂直方向に進む
    ● 行が垂直方向ではなく、水平方向に進む
    ● じゃあ、縦に並べてみましょう

    View full-size slide

  63. 縦書きのテキストを表示……?

    View full-size slide

  64. 縦書きのテキストを表示……?

    View full-size slide

  65. 縦書きの要件
    ● 文字が水平方向ではなく、垂直方向に進む
    ● 行が垂直方向ではなく、水平方向に進む
    ● 上の2つの他に以下2つの要件がある
    ○ フォントの縦書き用のグリフを使用する
    ■ 「。」「、」「ょ」「㍻」「(」「)」「ー」
    ○ アルファベット等の文字を90度回転させる
    ■ 半角だと回転する、全角だと回転しない

    View full-size slide

  66. 縦書きの際グリフをどう描画すべきか
    ● UAX #50: Unicode Vertical Text Layout
    ○ 4つに分類して定義されている(U/T/Ur/Tr)
    分類 内容 対象コードポイント
    U (Upright) 正立(そのまま)で表示 漢字等
    R (Rotated) 時計回りに回転して表示 Alphabet etc...
    Tu Uだが専用グリフが必要 、。ょ㍻
    Tr Rだが専用グリフが必要 ()ー

    View full-size slide

  67. 横書き専用のグリフに変換する
    ● これはFreeTypeでは対応できないのでOpenTypeの仕様を
    読んで実装すると良い
    ● OpenTypeのGSUB (Glyph Substitution)
    ○ グリフを別のグリフに置換するOpenTypeの機能
    ○ 縦書きの場合は1グリフ↦1グリフ
    ■ vert / vrt2 / vrtrというタグのもの
    ■ 他の用途だとNグリフ↦Mグリフの場合もある

    View full-size slide

  68. 完成!?
    ● だいたい良さそう

    View full-size slide

  69. 完成!?
    ● だいたい良さそう
    豆腐

    View full-size slide

  70. グリフの形式の多様化について
    ● 一昔前までは白黒の世界で全てが閉じていた
    ● カラー絵文字の登場でここが複雑化している

    View full-size slide

  71. Unicodeとカラー絵文字の話
    ● UTS #51: Unicode Emoji (ごく最近version 12.0が出た)
    ○ 絵文字の大雑把な類型
    ■ 国旗
    ■ 囲み数字
    ■ 結合文字 (ZWJ)
    ■ Presentation Selector
    ■ Emoji Modifier
    ■ Tag Sequence
    2/7 15:40~のTakeichi Yukiさ
    んのセッション「Androidエンジ
    ニアが抑えておくべき
    Unicode Emojiの知識」が参
    考になります

    View full-size slide

  72. OpenTypeフォントとカラー絵文字
    ● OpenTypeのカラー絵文字の仕様は大きく4種類
    形式 主なプラットフォーム 中身の形式
    CBDT / CBLC Android / Linux PNG画像
    COLR / CPAL Windows 普通のグリフと色情報
    SVG␣ / (CPAL) Adobe / Mozilla SVG画像(と色情報)
    sbix Apple macOS: PNG画像
    iOS: emjc画像

    View full-size slide

  73. 余談: OpenTypeフォントとカラー絵文字
    ● カラー絵文字に関する責務が散らばっているので大変
    ○ Unicodeの領域
    ■ 何をどう表示すべきかという仕様
    ○ フォントの領域
    ■ 表示することのできる文字の提供
    ○ テキスト描画系の領域
    ■ カラー絵文字を使うか白黒文字を使うかの判断

    View full-size slide

  74. テキストの描画
    ● 完成!

    View full-size slide

  75. 今回話していないこと
    ● 横書きのメトリクス・縦書きのメトリクス
    ● 1コードポイント=1グリフの例外
    ○ IVS(異体字セレクタ)
    ● 日本語組版処理の要件(JLREQ)
    ● 日本語以外のテキストについて
    ○ リガチャ
    ○ bidi
    ● 等々

    View full-size slide

  76. アウトライン
    ● TextViewの主な機能の縦書きでの実装可能性
    1. テキストを表示する ← ここが終わった
    2. テキストを編集する
    3. その他の便利な機能
    入力 テキスト描画系 出力
    テキスト 画像

    View full-size slide

  77. TextViewの機能その2
    テキストを編集する

    View full-size slide

  78. テキストを編集する
    ● 文字列を選択する
    ● 選択範囲を別の文字列で置換する

    View full-size slide

  79. テキストを編集する
    ● 文字列を選択する
    ○ キーボード操作による変更
    ○ マウス操作・タッチ操作による変更
    ● 選択範囲を文字列で置換する
    ○ キーボードから受け取った文字列で置換
    ○ クリップボードの文字列で置換

    View full-size slide

  80. デスクトップのテキスト入力の模式図
    テキストだと
    嬉しいけど……

    View full-size slide

  81. デスクトップのテキスト入力の模式図

    View full-size slide

  82. キーボードからの入力
    ● キーコードのストリームとキー配列からどうにかテキストを生
    成しないといけない
    ○ アルファベットはいいとして日本語は……?
    ■ キーの数が足りない
    ● これを解決するためにIMEというものがあります

    View full-size slide

  83. デスクトップのテキスト入力の模式図

    View full-size slide

  84. スマホのテキスト入力の模式図

    View full-size slide

  85. TextViewのおさらい
    ● TextViewがすべきこと
    ○ テキストの表示
    ○ テキストの編集
    ■ IMEからのテキスト入力を受け取る必要がある

    View full-size slide

  86. TextViewとIMEの関係

    View full-size slide

  87. TextViewとIMEの関係
    ● IMEが必要なのはわかった
    ○ IMEとViewは一体どうやって情報をやり取りするの?
    ■ SDK?
    ■ 通信?

    View full-size slide

  88. TextViewとIMEの関係

    View full-size slide

  89. IME APIとは
    ● OSがTextView実装のために用意するViewとIMEのインター
    フェース
    ○ Viewは具体的な実装を知ることなくIMEを利用できる
    ○ IMEは専用のSDKなどを用意せずにViewにその機能を提
    供できる

    View full-size slide

  90. IME APIの概観
    ● IME APIがViewに要求するのは
    ○ テキストの取得と変更
    ○ 選択範囲の取得と変更
    ○ View上での文字の位置情報
    ○ 未確定文字列の管理(例: スクショの「変換」が未確定文字
    列=挿入されていない)
    ○ Viewのテキスト・選択範囲・レイアウトの変更通知

    View full-size slide

  91. 各プラットフォームのIME API一覧
    IME APIの名称 (View側)
    / 標準実装
    縦書き対応
    (縦書きである事を伝える方法)
    コメント
    Windows ITextStoreACP
    / MSFTEDIT_CLASS
    あり 難解だけど高機能
    macOS NSTextInputClient
    / NSTextView
    あり attributedString() がつらい
    GTK+ GtkIMContext
    / GtkTextView
    あり - Gtk 3.6.18以降
    (ただし対応IMEがない気がする)
    やけにドキュメントが少ない
    Android BaseInputConnection
    / TextView
    不可能ではないはず
    (CursorAnchorInfoのsetMatrix)
    黎明期の闇が垣間見える
    UWP Windows.UI.Text.Core
    / TextBox
    なし 縦書きがあれば……
    iOS UITextInput
    / UITextView
    ないのと同じ UITextPositionは素晴らしい

    View full-size slide

  92. 文字を入力する際の人間を含めたループ
    ● 人間がキーボードを叩く
    ● IMEがキーコードを受け取る
    ● IMEがアプリに確定または未確定文字列を渡す
    ● アプリが現在のテキストをディスプレイに表示する
    ● IMEが必要な変換候補ウィンドウなどを表示する
    ● 人間がディスプレイを見る

    View full-size slide

  93. AndroidでViewをTextViewのようにするには?
    ● 素のViewはIMEとやり取りをすることはできない
    ● AndroidのIME APIに適合する必要がある

    View full-size slide

  94. AndroidでViewをTextViewのようにする
    ● カスタムViewでIMEを使うには2つのクラスが登場する
    ○ BaseInputConnection
    ■ インタフェース
    ■ ViewがIMEの要求を受信する(IMEから叩かれる)
    ○ InputMethodManager
    ■ サービス(システム)
    ■ Viewの変更をIMEに通知する(Viewから叩く)

    View full-size slide

  95. InputMethodManager
    ● キーボードの表示状態を変えるのによく使われる
    ● IMEのためにViewから変更を伝える関数がある
    ○ updateExtractedText ←テキスト
    ○ updateSelection ←選択範囲
    ○ updateCursorAnchorInfo ←選択位置(画面上の)

    View full-size slide

  96. BaseInputConnection
    ● IMEのためにView側が実装するべきこと
    ○ 文字列の取得と編集のInterfaceを提供
    ○ 選択範囲の情報の取得と変更のInterfaceを提供
    ○ 未確定文字列の描画

    View full-size slide

  97. 未確定文字列の描画

    View full-size slide

  98. 未確定文字列
    ● 未確定文字列とはIME上で編集中の文字列のこと
    ○ 確定していないテキスト
    ● Spannedを通して装飾情報が渡される
    ○ TextViewがテキストに装飾を反映する
    ○ 変換中であること・どこが変換対象になっているかなどを
    ユーザーわかるように

    View full-size slide

  99. Viewでテキスト入力を受け付けるためのまとめ
    ● カスタムViewに以下の実装をする
    ○ InputMethodManagerを通しIMEにViewの状態を通知
    ○ BaseInputConnectionを実装しIMEの要求に応える

    View full-size slide

  100. 縦書きで編集
    ● 動画再掲

    View full-size slide

  101. 注意: BaseInputConnection
    ● 実際はInputConnectionというInterfaceを継承したObject
    ○ アプリがInputConnectionを直接継承しても良い
    ○ しかしBaseInputConnectionはInputMethodManagerの
    @hideなプロパティを読み書きしている
    ■ BaseInputConnectionを使った方が良い

    View full-size slide

  102. アウトライン
    ● TextViewの主な機能の縦書きでの実装可能性
    1. テキストを表示する ← ここが終わった
    2. テキストを編集する ← ここが終わった
    3. その他の便利な機能

    View full-size slide

  103. TextViewの機能その他
    その他

    View full-size slide

  104. テキストを表示・編集する以外の機能
    ● アンドゥ・リドゥ
    ● ドラッグ&ドロップ
    ● コンテキストメニュー
    ● 文字選択中のMagnifier

    View full-size slide

  105. アンドゥ・リドゥ
    ● TextViewに標準で実装されている
    ○ android.R.id.undo / android.R.id.redo
    ■ API Level 23~
    ● キーボードなどからアンドゥ・リドゥができる
    ○ キーイベントでアンドゥ・リドゥを実行する
    ○ 編集履歴は自分で作る必要がある

    View full-size slide

  106. ● ドラッグ&ドロップ
    ● TextViewに標準で実装されている
    ● 選択文字列の長押しで以下を呼ぶ
    ○ ViewのstartDrag / startDragAndDrop
    ■ API Level ~23 / 24~

    View full-size slide

  107. コンテキストメニュー
    ● TextViewでテキストを選択したときの編集メニュー
    ● Activity.startActionModeを使うと良い
    ○ TextClassifierを使うと図のようなCallも出せる

    View full-size slide

  108. 文字選択中のMagnifier
    ● Magnifier
    ○ API Level 28~実装された
    ○ 横書き専用の機能
    ○ 縦書きする場合は自作しましょう

    View full-size slide

  109. 縦書きTextView
    ● 動画再掲

    View full-size slide

  110. スマホと縦書き
    ● 縦書きはソフトキーボードとの相性が非常に悪い
    ○ 縦書きのリフローは画面幅ではなく、表示領域の高さの変
    更で起きる
    ○ キーボードの表示の有無で可視領域の高さが変わる
    ○ IMEの変換候補の有無でも高さが変わることがある
    ■ リフロー発生!
    ● キーボードの高さへの追従とリフローの指針はきちんと考える
    必要がある

    View full-size slide

  111. まとめ
    ● テキストを表示
    ○ Unicodeのコードポイント
    ○ OpenTypeのグリフ
    ○ 改行と折り返し
    ● テキストの編集
    ○ BaseInputConnectionの継承
    ○ InputMethodManagerの呼び出し

    View full-size slide