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

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

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 スライドも縦書きができなかった
  2. 今回話す内容 • TextViewの話 • 文字コードという概念 • フォントという概念 • 縦書きテキストの作り方 •

    IMEの話 • AndroidのIMEをViewから利用する方法 • AndroidのTextViewのその他の便利機能について
  3. テキストを表示する 入力 テキスト描画系 出力 バイト列 画像 文字コードの 知識 参照する (テキスト)

    フォントファイ ル バイト列と文字コードを照ら し合わせて適切な文字の形 状をフォントから取得して画 像に出力する
  4. Unicodeについて簡単に • バイト列を文字列として扱うための規格 • 符号化文字集合のひとつ ◦ U+0000 ~ U+10FFFFを文字に対応づけたもの ◦

    U+xxxxがコードポイント、U+後ろは16進数表記 • UTF-8 / UTF-16 / UTF-32は文字符号化形式 ◦ U+0000 ~ U+10FFFFの21bitの情報をどのようにバイト 列で表現するかを定めたもの
  5. AndroidのStringとその周辺 • AndroidのString (CharSequence) はchar[]で構成される ◦ charは16bit整数=内部データはUTF-16 • 表のInterfaceは下が上を継承している Interface

    Object(実装) 役割 CharSequence String 文字列へのアクセス Spanned SpannedString 文字列とマークアップへのアクセス Spannable SpannableString 編集可能なマークアップ Editable SpannableStringBuilder 編集可能な文字列とマークアップ
  6. 余談: Android StudioとString • Android Studioを使ったAndroidアプリのデバッグ ◦ ブレークポイントを置くと変数の中身を確認できる ◦ CharSequenceのtoString()経由でAndroid

    Studioが取得 • これを知らずにデバッグ中にブレークポイントで止めるとクラッ シュする問題で困った ◦ CharSequenceのtoString()は初期前でも空文字列を返す ようにした
  7. 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を使うとだいたいのことができる
  8. 余談: 最近のAndroidとフォント • Variable Font (OpenType 1.8で導入された新機能) ◦ Android 8.0からVariable

    Fontをバンドル可能になった ◦ 合わせてfonts.xmlの仕様も一部拡張されている ◦ font-weight等が無段階になる機能
  9. 改行には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
  10. 改行には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: 行を進める
  11. グリフ列を画像にするまで 出力 画像 グリフ列 A あ 安 Aあ安 画像化 {画像,

    座標}の列 A, {0, 0} あ, {100, 0} 安, {200, 0} 1. グリフを置く 2. グリフの幅だけ進む ただし改行文字で次の行にジャンプ
  12. 折り返しにもUnicodeの知識が必要です • UAX #14: Unicode Line Break Algorithm ◦ Unicode標準の一部

    ◦ テキストのどこが折り返し可能かを定義している ◦ 行頭/行末禁止・分割禁止 • ICU (International Component for Unicode) ◦ これのLineBreakIteratorを使うと良い ◦ ICUはAndroidにも組み込まれている ◦ もともとIBM主導のOSSで今はUnicodeに属してる
  13. 書字方向(文字の進む方向) • 横書き(左から右) • 右横書き(右から左) ◦ アラビア語など ◦ 昔の日本のメディア ◦

    トラックや屋台の右側面の文字 • 縦書き(上から下) ◦ 今回のトピック https://commons.wikimedia.org/wiki/File:RIKEN_VITAMIN.png
  14. 改行方向(行が進む方向) • 書字方向とは直交する方向 ◦ 横書き(上から下) ◦ 右縦書き(右から左、vertical-rl) ▪ 日本語 ◦

    左縦書き(左から右、vertical-lr) ▪ モンゴル語(モンゴル文字を使った場合) • 今はキリル文字が一般に使われている
  15. 縦書きの要件 • 文字が水平方向ではなく、垂直方向に進む • 行が垂直方向ではなく、水平方向に進む • 上の2つの他に以下2つの要件がある ◦ フォントの縦書き用のグリフを使用する ▪

    「。」「、」「ょ」「㍻」「(」「)」「ー」 ◦ アルファベット等の文字を90度回転させる ▪ 半角だと回転する、全角だと回転しない
  16. 縦書きの際グリフをどう描画すべきか • UAX #50: Unicode Vertical Text Layout ◦ 4つに分類して定義されている(U/T/Ur/Tr)

    分類 内容 対象コードポイント U (Upright) 正立(そのまま)で表示 漢字等 R (Rotated) 時計回りに回転して表示 Alphabet etc... Tu Uだが専用グリフが必要 、。ょ㍻ Tr Rだが専用グリフが必要 ()ー
  17. Unicodeとカラー絵文字の話 • UTS #51: Unicode Emoji (ごく最近version 12.0が出た) ◦ 絵文字の大雑把な類型

    ▪ 国旗 ▪ 囲み数字 ▪ 結合文字 (ZWJ) ▪ Presentation Selector ▪ Emoji Modifier ▪ Tag Sequence 2/7 15:40~のTakeichi Yukiさ んのセッション「Androidエンジ ニアが抑えておくべき Unicode Emojiの知識」が参 考になります
  18. OpenTypeフォントとカラー絵文字 • OpenTypeのカラー絵文字の仕様は大きく4種類 形式 主なプラットフォーム 中身の形式 CBDT / CBLC Android

    / Linux PNG画像 COLR / CPAL Windows 普通のグリフと色情報 SVG␣ / (CPAL) Adobe / Mozilla SVG画像(と色情報) sbix Apple macOS: PNG画像 iOS: emjc画像
  19. 余談: OpenTypeフォントとカラー絵文字 • カラー絵文字に関する責務が散らばっているので大変 ◦ Unicodeの領域 ▪ 何をどう表示すべきかという仕様 ◦ フォントの領域

    ▪ 表示することのできる文字の提供 ◦ テキスト描画系の領域 ▪ カラー絵文字を使うか白黒文字を使うかの判断
  20. IME APIの概観 • IME APIがViewに要求するのは ◦ テキストの取得と変更 ◦ 選択範囲の取得と変更 ◦

    View上での文字の位置情報 ◦ 未確定文字列の管理(例: スクショの「変換」が未確定文字 列=挿入されていない) ◦ Viewのテキスト・選択範囲・レイアウトの変更通知
  21. 各プラットフォームの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は素晴らしい
  22. アンドゥ・リドゥ • TextViewに標準で実装されている ◦ android.R.id.undo / android.R.id.redo ▪ API Level

    23~ • キーボードなどからアンドゥ・リドゥができる ◦ キーイベントでアンドゥ・リドゥを実行する ◦ 編集履歴は自分で作る必要がある
  23. まとめ • テキストを表示 ◦ Unicodeのコードポイント ◦ OpenTypeのグリフ ◦ 改行と折り返し •

    テキストの編集 ◦ BaseInputConnectionの継承 ◦ InputMethodManagerの呼び出し