2013年やったこと - Chromium 編

2013年やったこと - Chromium 編,いつもどおりコードが公開されている範囲で.

HTML5 Forms の type 指定と InputScope の対応作業

HTML5 Forms の type 指定と Windows 環境での InputScope を連携させるという変更です.Windows 8 以降のオンスクリーンキーボードは InputScope でレイアウトを切り替えるため,IME を必要としない言語でも有効なのがポイントです.
変更自体はそれほど難しくなく,特にトラブルもないまま無事リリースされていきました.
f:id:NyaRuRu:20140104120453p:plain
メジャーブラウザの InputScope 対応状況については,以下の記事にまとめています.

Omnibox フォント問題

Omnibox のフォントサイズが微妙に変わった/特定文字が□になったから直すべし,という案件.

f:id:NyaRuRu:20140104120504p:plain
なんでこのバグを担当する羽目になったかというと,Omnibox で使っていた RichEdit のバージョンを上げたのが私だったからです.なぜバージョンを上げる必要があったかというと,Immersive Mode で IME をサポートするためには TSF を使う必要があって,古い RichEdit は TSF をサポートしていなかったからです.欲しかったのは TSF の機能だけで,その他は前と同じように動いてほしかったのですが,そうはいかなかったようでした.
問題自体は i18n 対応でありふれたものです.様々な経験則を駆使しつつ複数フォントで文字をレンダリングしたいという需要があるのですが,それはそれでうまく動かないことがあるというもの.RichEdit ではいくつか制御フラグがあるものの (e.g., IMF_DUALFONT, IMF_AUTOFONT) あちらを立てればこちらが立たずで,直ったーと思ってリリースしてみると予想外の言語から「見た目が変わったー」「文字が□になるー」とバグが報告されるという.
ちなみに後で分かったのですが,Aura という UI フレームワークへの移行することがだいぶ前に決まっていて,その過程で RichEdit は使われなくなるとことも決定事項だったのでした.実際,このとき書いたコードは 1 年と経たず使われなくなりました.

破損 msftedit.dll 問題

これも同じく RichEdit のバージョンを上げたら壊れた問題です.RichEdit 4.1 は msftedit.dll という DLL で提供されているのですが,どうも世の中には msftedit.dll が破損している環境というのが一定数あるらしく,その場合は Omnibox が真っ黒になって何も文字が入力できなくなってしまうとのこと.ユーザーフォーラムに多数問い合わせが来て発覚.議論の末 LoadLibrary("msftedit.dll") が失敗したらダイアログを出してヘルプページに誘導する,ということになりました.ダイアログを表示するような UI 周りのコードを書くのは初めてだったのでだいぶ苦労したのを憶えています.がその後数か月のうちに RichEdit は使われなくなるわけで,このコードも今は使われていません.(たぶんもう消されてるはず)

用語整理

以後のトピックを理解する上で必要になる用語整理をここで軽く済ませておきます.

Aura

上の資料はだいぶ古くなっているのではないかと思いますがかといってあんまりいい資料もないかも.
一般的には「全てを GPU でレンダリングするための変更」という説明をされることが多い Aura ですが,何年もかけて移行していると関係者が増えすぎていて一言でいうのはもう無理なのではという印象もあります.
Chrome OS はとっくの昔に Aura に移行していて,現在 Windows と Linux で移行の最終段階です.Windows については次の Chrome M-32 で安定板にも Aura が投入されそうではありますが正式にリリースはまだなのでご注意を.
基本的には Chrome OS / Linux / Windows で共有されるコードが増える方向のプロジェクトです.ウィンドウを抽象化し,UI イベントを抽象化し,IME 処理も抽象化し,レンダリング API も抽象化し,という流れ.イベント処理周りのコールスタックは数割深くなる印象.また,いわゆる抽象化の漏れによるバグの比率が増えます.
一方,UI イベントの型と描画 API がプラットフォーム間で統一されることから,新規プラットフォームへの移植時に必要なコード量は確実に少なくなります.WebView として Chromium を使いたい人は特にこの点を重視している模様.たとえば Intel の人たちが中心になって行っている Chromium 派生プロジェクト Crosswalk は Aura が前提だったりします.
ちなみに,Aura は大規模にコードを入れ替えるため,ビルドオプションで有効無効を切り替えます.実行時スイッチで切り替えられず,安定性・互換性・パフォーマンスに関する影響は非常に大きいということで,リリースエンジニアリングの観点では非常に厄介なタイプの大規模変更です.

Ash (Aura Shell)

Aura のウィンドウモデルやイベントモデルの上に作られたウィンドウマネージャで,Chrome OS のために作られました.実際 Chrome OS では,はるか昔に投入済みです.
経緯は知りませんが Windows 8 以降の Immsersive Mode でも使われることになり,すでに開発版等ではリリースされています.Windows での実装は,ブラウザプロセス + レンダラプロセスで構成されている Chromium にさらに WinRT プロセスが追加されるという非常にトリッキーなマルチプロセス構成となっており,IME サポートもだいぶ面倒なことになりました.詳しくは後ほど.
後になって知ったのですが,Immsersive モードに Ash を投入するという構想自体はだいぶ前からあったようです.Windows 版での Ash モードで IME が動かないというバグ登録されたのは,2012 年12月7日のことでした.
Issue 164964 - chromium - Support basic functionality of IMEs in Chrome Metro ASH on Windows 8 - An open-source project to help move the web forward. - Google Project Hosting

Desktop Aura

ウィンドウマネージャは従来通り OS のものを使いつつ,独立した各ウィンドウの内側だけを Aura に置き換えるというもの.デスクトップモードの Windows と Linux で投入されます.現在の Chrome OS にこの動作形態はありません.
IME に関していえばウィンドウマネージャは OS のものを使うという点がやっぱり罠で,Ash 環境では表面化しなかったタイミングバグやイベント順序バグが沢山表面化することとなりました.
先ほど述べたように,予定通りいけば次の Chrome M-32 安定板からWindows 版でも有効化される見込みとなっています.IME に限らず,アクセシビリティ系ツールとの互換性,パフォーマンス,GPU ドライバとの互換性等,あちこち大変みたいです.

Native Textfield Views

従来ネイティブウィンドウを使って実装していたテキストフィールドを自前の Window-less コントロールに置き換えようというものです.なお Web コンテンツ領域はもともと自前のテキストフィールドだったので,ここで置き換えられるのは Omnibox 等外側の部分のテキストフィールドのみなことに注意.
Desktop Aura ではトップレベルウィンドウ以外はネイティブウィンドウを持たないので, Aura 移行のためには必須となります.Aura 移行が完了している Chrome OS 環境では当然のことながら置き換え済みです.
Native Textfield Views の実装自体は Aura から独立していて,Windows 版 Aura 投入にあたっては以下のように段階的な移行が行われました.

  1. non-Aura + Native Textfield Views 無効
  2. non-Aura + Native Textfield Views 有効
  3. Aura + Native Textfield Views 有効

このいずれの構成でも IME は動作する必要があり,移行期には考慮すべきケースが増えてしまうので大変でした.
Aura と異なり,起動時のフラグで有効無効を切り替えるという特徴があります.上の 1 と 2 は同じバイナリで提供することが可能です.

構成

一時的にテストされたものも含むと,IME に関しては以下の 7 パターンの構成を見ることになりました.

  • IMM32 で動作する non-Aura モード (Windows XP, Vista, 7, 8, 8.1 のデスクトップモード)
    • Native Textfield Views 有効の場合
    • Native Textfield Views 無効の場合
  • TSFで動作する non-Aura モード (Windows 8, 8.1 の Immersive モード)
    • Native Textfield Views 有効の場合
    • Native Textfield Views 無効の場合
  • IMM32 で動作する Desktop-Aura モード (Windows XP, Vista, 7)
  • TSF で動作する Desktop-Aura モード (Windows 8, 8.1) [のちに不要だったことが判明]
  • TSFで動作する Ash モード (Windows 8, 8.1 の Immersive モード)

不運だったのは,この「TSF で動作する Desktop-Aura モード (Windows 8, 8.1)」が,非常に不安定だった割に,実際のところ全く不要だったとあとになって判明することです. 2013 年 4 月ごろ,将来の必要性を見越して Windows 向け Aura/Ash を担当しているチームから追加されたこのモードは,その後 5 か月にわたって安定化のためにエンジニアリングリソースを吸い込み続け,そして一度も安定板に投入されることなく削除されることになります.
なお,移行が概ね完了した Chromium M-33 以降では,以下の 2 つの構成にまで簡略化されています.

  • IMM32 で動作する Desktop-Aura モード (Windows XP, Vista, 7, 8, 8.1 のデスクトップモード)
  • TSFで動作する Ash モード (Windows 8, 8.1 の Immersive モード)

というわけで用語説明終わりです.

Native Textfield Views が IMR_QUERYCHARPOSITION をサポートしない

ゴールデンウィークの暇つぶしに軽い気持ちでパッチを投げたもの.Desktop Aura や Ash のリリースプランを当時の私は全く知らなくて,村の近くに出没したゴブリンでも退治する感じでパッチを投げてしまったのでした.ちなみにこの後どうなるかというと,

  1. Native Textfield Views 導入編 (ゴブリンの巣)
  2. Native Textfield Views + non-Aura完結編 (なんか最初の山場)
  3. Desktop Aura 編 (魔王城)
  4. Ash 編 (宇宙)

みたいな流れになります.
この時直したバグは,Native Textfield Views が有効だとサジェストウィンドウ位置が揃わないというものでした.
f:id:NyaRuRu:20140104120522p:plain

このパッチのせいで,Omnibox 上でカーソルが点滅しなくなるというバグを引き起こしてしまいあわてて直したりもしています.

Native Textfield Views で変換中の文節区切りが分からない

ゴールデンウィークのゴブリン退治その 2.
IME で入力中,文節区切りが分からないという問題の修正です.Chrome OS 版で発見されたまま直っていなかった問題ですが,さすがにこのまま Windows 版に出すのはまずかろうという気持ちで (特に担当だったわけではないのですが) 直してみました.

Native Textfield Views + non-Aura 環境での IME 対応

6 月ごろだった気もしますがやや記憶があいまい.

思っていたより事態が深刻だと気付き始めます.というのも,既に Aura への移行を済ませてしまっている Chrome OS と違い,Windows 版では Native Textfield Views と non-Aura という組み合わせでも IME を完璧に動作させる必要があります.もちろん最終的には Windows での Aura ビルドでも IME サポートを行う必要もあります.ともあれ,Native Textfield Viewsの投入は近そうだということで,何とか 7 月末に Native Textfield Views + non-Aura という環境で概ね問題なく動くところまでこぎつけました.
コードだけでなく Design Doc もこのタイミングで書くことにもなりました.しかし既に Aura への移行を済ませた Chrome OS の IME 実装を大きく変えるわけにもいきません,必然的に Design Doc の大半は,既にコミットされているコードの説明に費やされました.

Desktop Aura 対応

8 月から 9 月にかけて.Native Textfield Views がひと段落したと思ったのもつかの間,すぐにも Desktop Aura が Windows に投入されそうと知らされ再び戦場へ.
ウィンドウのフォーカス処理を OS に任せるか Aura で行うかの違いは思った以上に大きく,Chrome OS では表面化しなかったイベント順序問題やタイミングバグが頻発します.
さらに IMM32 と TSF という異なる実装を同時に安定化させる作業は困難を極めました.また,コードが共有される関係上,変更が Chrome OS での IME サポートを壊すリスクもあり,頻繁にマニュアルテストを行う必要がありました.特定の操作でのみ発生する use-after-free バグが頻発し,GC が恋しくなった時期でもあります.
そして9 月中旬.ラスボスだと思っていたものがラスボスではなかったことを知ります.Immsersive モードで Ash を使用する予定であること,およびそれが WinRT プロセスとデスクトッププロセスが入り混じったものになることを初めて把握します.と同時に,4 月に Windows 版 Ash チームの人がデスクトップモードでも TSF を有効化したその意図をやっと理解したのでした.ここにきての伏線回収.結局それは Ash モードでの動作を見越して投機的に行われたものだったのでした.
が,改めて実験してみると,TSF ランタイムに嫌な制約があって,ブラウザプロセスで TSF を有効にしても Ash モードでの IME サポートの役には立たないことが明らかに.伏線を回収してみたら事件の真相は単にコミュニケーション不足だったという.人類はなんど同じネタを繰り返さなければならないのでしょうか.
最終的には,デスクトップモードでの TSF サポートをやめたことで,IME に関する Desktop Aura の安定化が急激に進むのでした.

Ash での IME サポート

Windows 環境での Ash モードは非常に特殊な動きをします.Win32 的なキーボードフォーカスは WinRT プロセスが保持する一方,UI イベントの処理は全てデスクトップで動いているブラウザプロセスに転送するという動作をします (ウェブコンテンツはさらにレンダラプロセスでレンダリングされます).キーイベントに IME が絡まなければ,基本的にこれはうまく動作します.
さて IME ですが,WinRT プロセス内で IME を動かすか,ブラウザプロセス内で IME を動かすかという選択肢が考えられます.しかし,いくつかの実験から分かったのは,TSF ランタイムはフォアグラウンドプロセスかどうかを監視していて,バックグラウンドプロセスで動く IME は決してフォーカスイベントを受け取らない,という事実でした.消去法的に,WinRT プロセス内に TSF ベースのテキストストアを構築し,IPC を通じてブラウザプロセス内の既存コードと連携させる以外道がないということになります.このことをちゃんと調べられたのが 2013 年 9 月,Ash モードでの IME サポートに関するバグが登録されて実に 10 か月が経過してのことでした.
Issue 164964 - chromium - Support basic functionality of IMEs in Chrome Metro ASH on Windows 8 - An open-source project to help move the web forward. - Google Project Hosting
動作する最低限のコードは 10 月中には完成させたのですが,Desktop Aura の安定化を優先させたこと,変更が大きなことから,実際にチェックイン作業を始められたのは 11 月下旬でした.残念ながら M-32 には間に合わず,M-32 ベースの Ash モードでは IME は動作しません.
とはいえ遅れはしたものの,予定した変更の大半は無事 M-33 ブランチカット前にチェックインを終えることができました.M-34現在,Ashモードでニコニコ動画にコメント入力すら可能です.ニコニコ動画に IME で入力するときは,

  1. WinRT プロセス
  2. ブラウザプロセス
  3. レンダラプロセス
  4. プラグインコンテナプロセス

と 4 つのプロセスが非同期 IPC で連携しながら動作することになるのですが,その綱渡り具合を真に理解できる人がはたして世界に何人いるのかにも興味があるところ.
f:id:NyaRuRu:20140104120535p:plain
Ash モードの Flash 上で候補ウィンドウの位置が正しく設定されない問題は M-34 で直ります.

IME に関係なく行きがかり上担当することになったもの

User Agent 文字列が正しい OS バージョンを示さない

Windows 8.1 で動く Chromium の User Agent 文字列が

Mozilla/5.0 (Windows NT 6.2; WOW64)

みたいになっていました.いわゆる GetVersion(Ex) API 問題.ブラウザの User Agent 文字列から OS のシェア推定とかやっているところには影響があったはず.


という感じの,のどかな会話から思いがけず発覚したのが印象的でした.Mozilla 側でも直後に修正されています.
まあついでということで Chromium にはパッチを投げてみました.メジャーブラウザ の User Agent 文字列に影響する変更というのはなかなか貴重な体験でした.

全部の *.exe にアプリケーションマニフェストファイルを設定すべき

先ほどの GetVersion(Ex) API 問題を修正するために chrome.exe のマニフェストファイルをアップデートしたわけですが,コードレビューで「ユニットテストとプロダクションバイナリで動作が変わるのは良くないから,全部の *.exe に同じアプリケーションマニフェストを設定できないかな」的なコメントが付いたで急遽やることになった仕事です.
Mozc で培った Gyp 誰得ノウハウをいかんなく発揮して華麗に解決! といけばよかったのですが,実際全部の *.exe にマニフェストファイルを埋め込んでみたら今度は「ユニットテストのビルドが 30 倍遅くなった!」と怒られます.えー

結局いくつかのユニットテストではマニフェストファイルを埋め込まず隣に置く方式になりました.
後日談としては,Gyp r1813 でマニフェストファイルの扱いが大幅に見直されたので,パフォーマンスを悪化させずにマニフェストを埋め込むことができるようになりそうです.

Web MIDI: Windows 対応

社内 TechTalk で Toyoshima さんが Windows 版 Chromium 向け Web MIDI の実装者を募集していて,Mac 版が既に動いているならそれほど苦労せずに Windows 版も対応できるかなと思って手を上げました.
実際,10 月19日の Web Music ハッカソンにふらっと立ち寄って半日で単純な入出力までできたのですが,細かいところまで見てみると既にある共通部分のコードにも色々バグを見つけてしまい,基本部分からひとつずつバグを直していくことになりました.私にとっては Blink への初コミットが Web MIDI となります.
Aura/Ash の IME 実装がほんとに大変な時期だったというのもあって,コードレビューの待ち時間等を利用して少しずつ直しながら,一か月半後ぐらいの12月4日にやっと有効化となりました.

Windows で電源イベントのオブザーバーが動いていなかった

Web MIDI 関連で調べているときにたまたま見つけてしまったバグです.Chromium の実装用のライブラリに,電源コードの抜き差しや,サスペンドへの移行・復帰時にコールバックを受けられる仕組みがあるのですが,これが数か月動いていませんでした.
タイマ割り込み精度の変更とか GPU ウォッチドッグタイマの設定とかネットワークのコネクションキャッシュがこれらのイベントに依存しているみたいですが,誰も気づいていなかったみたいですね.

その他社内コンサル業

W3C Working Draft: Input Method Editor API

http://www.w3.org/TR/ime-api/
W3C に提案中の Input Method Editor API について,社内で API 設計の議論をしたり,Chromium での実装に関してアドバイスをしたりしています.

chrome.input.ime

http://developer.chrome.com/extensions/input_ime.html
Chromium OS 専用の内部 API である,chrome.input.ime についてもたまに議論に参加したりしています.

感想

色々思うところのある1年でした.

今年の話とか

2014 年 1 月から社内の (Chromium 以外の) 別プロジェクトに移ることにしました.Web MIDI 等,趣味として参加できそうな部分は引き続きコミットしていければと思いますが,締め切りのあるバグを担当するほどの余裕はたぶんないと思います.社内コンサル業と,IME 周りのクリティカルな部分のコードレビューに費やす時間ぐらいはまあなんとか捻出したいところ.