2014 年やったこと - Chromium 編
Chromium 関係,コードはあまり書いていない一年でした.数字としてはコミット 17 回,コードレビュー 13 回となります.一方 Issue Tracker 上での活動はまあそれなりにで,Issue 登録 19 回,コメントを書き込んだり状態を変更したりといった Issue の数は 173 件となりました.
自分でやったこと
Windows 版 Chromium の Aura 移行完了後不要になった IME 関連コードの削除
2014 年 1 月から 2 月にかけて,Aura + Ash 移行に伴い不要になった IME 関連コードの削除をやっていました.既にチームを移っていたこともあり,最後の後片付けという感じです.書くだけ書いて後片付けを次の人に任せるのは気が引けたというのもありますし,Chromium に関わり始めた 2012 年ごろ,おっかなびっくり書いたやっつけコードを自らの手で消し去る良い機会だったというのもあります.
Windows 版 Chromium で HiDPI 有効化時に IME の候補ウィンドウの位置がずれる問題の修正
2013 年に自分が登録したバグですが,普段使っている Windows ノート PC がこの影響を受けていてあまりにも不便だったので,土日の空き時間を使って自分で直してみたものです.
Android 5.0 の新 IME API への対応 (未完)
後で改めて書くかと思いますが,2014 年のメインプロジェクトの仕事のひとつで Android 5.0 にいくつか IME API を追加,というのをやっておりました.追加した API は InputMethodManager.html#updateCursor API の置き換えを狙ったもので,変換中の文字列のスクリーン座標を IME に伝えられるようにするものです.さて,この種の新 API の宿命として,IME だけでなくテキスト入力 widget 側にも新 API 対応が必要になります.Android の標準 TextView を使っているアプリケーションであれば何もしなくてよいのですが,独自にテキスト描画を行っているアプリケーションではそうはいきません.Chromium も当然ながらこのカテゴリに属し,Android 5.0 の SDK を使用して割と面倒なコードを追加する必要がありました.この仕事,当初は Chromium Android 版チームの人に頼もうかと漠然と考えていたのですが,Android 5.0 の開発期間中にとりあえず動く検証用コードを書き上げてしまったこともあり,なし崩し的に自分で対応コードを追加することになったという感じです.
とはいえコードレビューでのリクエストに色々応えていたらだいぶ規模が大きくなり,そのまま年末休暇シーズンに突入してしまったため,実現は 2015 年に持ち越しとなりました.
Issue Tracker 上で情報提供しつつ直してもらったものからいくつか
base::SHA1HashBytes に 4 GB 以上のデータを渡すと誤ったハッシュ値を返す
別件で SHA1 Hash の計算式を調べていたときに,参考に見てみた Chromium の内部関数に問題を見つけてしまったというものです.ざっと見てみた範囲では問題になるケースは見つけられませんでしたが,念のためセキュリティバグとして報告,修正してもらいました.
Chrome Remote Desktop (Chromoting) のウィンドウ上ではクライアント環境の IME は常にオフにすべき
仕事で Chrome Remote Desktop (内部コードネーム Chromoting) を使うことが良くあるのですが,IME 関係で不満があったので変更を提案して対応してもらったというものです.
Windows 環境から Linux 環境に Chrome Remote Desktop で接続するケースを考えてみます.このとき,Chrome Remote Desktop のウィンドウ上でクライアント側 (Windows 側) の IME を有効にすることができてしまっていました.しかし,確定した文字列は単に捨てられてしまうという状況でした.
これは,特に機能として役立っていないだけではなく,パスワードを意図せず IME に学習させてしまうなど望ましくない動作でした.そこで,クライアント側の IME を完全にオフにするという提案をしてみた次第です.
以前 Pepper SDK の IME 周りを担当されていた kinaba@ さんの的確なアドバイスのおかげで,数日のうちに対応していただくことができました.
Time::EnableHighResolutionTimer(false) が無視されることがある
http://t.co/JTur7YYQ3y
これ,Chromiumのソースを読むと若干印象が違うんですよね.
timeBeginPeriodは気を付けろ的な長いコメントは実際書いてあるし,バッテリー駆動時にはtimeBeginPeriod(1)呼ぶのを避けようとしてたり.
— NyaRuRu (@NyaRuRu) July 15, 2014
かなり初期からそうなっていたはず.2009年1月のGoogle Chrome Out of Beta Partyにお呼ばれしたときにこのネタでLTした記憶が……
http://t.co/8jPmv2kGHo
— NyaRuRu (@NyaRuRu) July 15, 2014
んで,まずいのは実はこの辺の挙動が継続的にテストされていないということかなぁと.実際,2009年1月当時LTしたときも,実は電源抜き差しイベントのモニタリングの実装が壊れていてなんかずっと電源つながっている状態と誤認されていました的な状態だったと.
— NyaRuRu (@NyaRuRu) July 15, 2014
2013年にも,WM_POWERBROADCASTイベントのモニタリングが8ヶ月ぐらい壊れたままだったのに誰も気づかなかった事件とか.
https://t.co/2je9isJfdJ
— NyaRuRu (@NyaRuRu) July 15, 2014
教訓としては,継続的テストの実行環境の中に,バッテリーモード動作をテストするための環境をちゃんと作るのが重要,というあたりでしょうか.でないと,バッテリーモードで動作するとき特有の挙動がテストできないですよ,と.
— NyaRuRu (@NyaRuRu) July 15, 2014
2014 年 7 月頃,ネットメディアを中心に Windows 版 Chrome の電力消費量が話題になったことがありました.報道に関して色々言いたいことはあったものの,実際うまく動作しないケースが存在することも知っていたので,念のため知っていることを Issue Tracker にコメントしておきました.実際には他にも色々問題があったらしく,しばらくしてまとめて修正していただきました.マルチスレッド絡みバグがたくさん見つかったそうです.
base::PowerMonitor::AddObserver と base::PowerMonitor::RemoveObserver が同じスレッドで呼ばれないことによる use-after-free
たまたま自分の目の前で Google Chrome Canary がクラッシュしたので,クラッシュダンプを頼りに Issue Tracker 上で原因究明に協力したものです.Issue としては以下のものになります.(Chromium ではクラッシュバグは原則セキュリティバグ扱いのため,特定アカウントでログインしていない限り以下のページは表示されません.面倒な仕組みですみません)
仮想関数呼び出しで EXCEPTION_ACCESS_VIOLATION_EXEC という一見不可思議なクラッシュだったのですが,イベントリスナーとして使われている仮想関数だったことから use-after-free を疑って関連コードを読んでいくと,以下のようなコードを発見.これ,AddObserver と RemoveObserver が同じスレッドで呼ばれないと,RemoveObserver はサイレントに何もしないという実装だったという.
http://src.chromium.org/viewvc/chrome/trunk/src/base/observer_list_threadsafe.h?revision=212281#l125
// Remove an observer from the list if it is in the list. // If there are pending notifications in-transit to the observer, they will // be aborted. // If the observer to be removed is in the list, RemoveObserver MUST // be called from the same thread which called AddObserver. void RemoveObserver(ObserverType* obs) {
「このせいじゃね?」とコメントしておいたところ,直前にコミットされていた Issue 482333003: Reland r290125: Close all active PeerConnections upon OS suspend - Code Review がまさにこの問題を踏んでいたことを特定していただきました.これにコードレビューで気付けというのはちょっと無理ですかね.ライブラリの設計ミスとでも言うべきか.
Google Cloud Messaging クライアントの exponential backoff が約 7 日でオーバーフローする
利用者からバグ報告に担当者が割り当てられていなかったので,関係しそうな人々を CC しただけ仕事です.Chrome が特定条件で (Google のサーバーの?) port 5228 に大量のパケットを送信する,という問題.原因だけは気になっていたのでその後もやりとりをウォッチしていたのですが,exponential backoff の計算方法に問題があって,約 7 日送信失敗し続けると double の精度を超えてしまっていたというオチでした.
Windows 10 Technical Preview 上で動く Chromium の User Agent が "Windows NT 6.3" と返す
Windows 8.1 のときにもあった,GetVersionEx 嘘つき問題です.マニフェストファイルに GUID を追加すれば解決する話ではあるのですが,実際手を出してみたら大量の yak shaving に付き合わされたのが前回.今回は Issue として登録して直してもらいました.
感想
何となくそうではないかと予想していましたが,Issue Tracker で人に作業を振ったりあれこれ意見を述べるだけってのはだいぶ楽ですねこれ.チームを移ったこともあり,基本的に休日や通勤中の空き時間でできる作業に専念していたのですが,これぐらいの作業なら空き時間との相談で続けてもいいかなというところです.
一方で Chromium のコードを書く人の負担が半端なく大きいという問題は未解決のままと言えます.かなり厳しいコードレビュー,法外に高いクロスプラットフォーム対応コスト,不安定なテスト,コミット後忘れた頃にやってくる regression とクラッシュの報告.実際に問題を修正してくれている人たちは何故そんな面倒な仕事をしてくれているのか,そこをうまくシステム化していかないとブラウザ開発というプロジェクト自体の持続可能性が危ういんではないかなと.Issue Tracker であれこれ意見を言うだけの人が 100 人いても,大変めんどくさいコード変更作業に立ち上がってくれる人が 1 人現れない限り問題は解決しないという構造をプロジェクト運営にどう反映させていくのか.思うことは色々あるのですが,この辺についてはまた改めて別のエントリで書いてみたいと思います.
2015 年ですが,Android 5.0 の新 IME API 対応はさっさと終わせないとですね.その先はあんまり考えていないです.まあなるようになる感じで.
References
コミット一覧
- Do not provisionally send ImeCompositionRangeChanged message on Android
- Revert "Plumb composition character bounds from C++ to Java"
- Replace #updateCursor with #updateCursorAnchorInfo
- Plumb composition character bounds from C++ to Java
- Plumb composition character bounds for Android 5.0
- Treats the returned value from ui::TextInputClient as DIP
- Remove obsolete files and comment from skia/
- Unify InputMethodIMM32 into InputMethodWin again
- Remove ui::TextInputClient::GetAttachedWindow
- Remove WM_DEADCHAR/WM_SYSDEADCHAR handler
- Revert r151669 and r155589 as non-Aura Metro mode is gone
- Logically revert r206996, which is no longer used in the era of Aura
- Remove non-Aura stuff from InputMethodWin
- Revert "Revert 249234 "Use MessagePumpDispatcher instead of MessageFilter""
- Use MessagePumpDispatcher instead of MessageFilter
- Revert r156303 as non-Aura Metro mode is gone
レビューした CL 一覧
- Show autofill popup after keyboard (if any) is shown.
- Do not use vector<scoped_ptr<>>.
- Fix DOM code for VKEY_LCONTROL and VKEY_RCONTROL
- Web MIDI: distributes MIDIPort information asynchronously
- Get IME's to work in Chrome OS mode on Windows 7.
- The message length should be serialized as a 64-bit value.
- Web MIDI: make input_ports_ and output_ports_ members private
- Web MIDI: introduce pending client count limit to start sessions
- Web MIDI: add an unit test to check MidiManager instantiation
- Add PGO targets to Chrome.
- Removed the unnecessary TODO
- Revert 249234 "Use MessagePumpDispatcher instead of MessageFilter"
- Remove InputMethodTSF, TSFEventRouter, TSFTextStore, TSFBridge
報告した Issue 一覧
- Issue 304691: Support IMEs and keyboard input for --open-ash on Linux
- Issue 326777: Win/Ash: Ctrl+{Left, Right}Shift does not flip the text direction
- Issue 334380: IME is not available under Ash mode on Windows
- Issue 343826: Remove ui::TextInputClient::GetAttachedWindow
- Issue 344209: Unify ui::InputMethodIMM32 into ui::InputMethodWin
- Issue 347363: Revise obsolete comments that were written in the era of IBus
- Issue 348333: Security: base::SHA1HashBytes produces wrong SHA1 hash when |len| >= 4GB
- Issue 350649: depot_tools.zip is obsolete and requires multiple self update
- Issue 350656: Design Documents? of Text Input is obsolete
- Issue 350659: Specify /Zc:strictStrings for release build
- Issue 350660: Remove unused IDS_OPTIONS_SETTINGS_LANGUAGES_* messages
- Issue 360334: Needs a spec of whether ui::TextInputClient uses DIP (Density Independent Pixel) or not
- Issue 401371: IME should never be enabled in Chromoting window
- Issue 402239: (restricted)
- Issue 402244: (restricted)
- Issue 404132: (restricted)
- Issue 420629: User agent string reports "Windows NT 6.3" on Windows 10 Technical Preview
- Issue 424866: Support InputMethodManager#updateCursorAnchorInfo for Android 5.0
- Issue 427090: Monitor the performance impact on real devices when CursorAnchorInfo is enabled
コメントした Issue 一覧
- Issue 1970: ctrl+shift+t conflicts with Google Pinyin IME
- Issue 65712: Autofill eats keystrokes when SCIM is enabled
- Issue 86460: GoogleJapaneseInputMethod shows the candidate window inappropriate position
- Issue 113805: Chromium wrongly add text to clipboard while using input method with preedit under linux
- Issue 125161: Please do not use GtkIMContextSimple for password fields.
- Issue 125888: SSH extension doesn't permit use of IBUS input method (and maybe also other input methods, not tested)
- Issue 128475: Search setting incorrectly unfocus the input field cause text commit
- Issue 135135: Does not remove committed string with an IME on cancelling
- Issue 139764: Can't render double underline on composition
- Issue 142823: Some preedit text might be typed in to input box
- Issue 168993: Win/Ash: Cannot commit text via IME on Google Document
- Issue 170186: pdb size being exceeded in non-component=shared_library builds
- Issue 174136: Refactor pdb workaround
- Issue 215520: ibus-mozc: no way to delete input history
- Issue 218382: hterm: incorrect handling of utf-8 input
- Issue 260529: IME UI is not placed at proper position when HiDPI is enabled
- Issue 264288: Blue lowercase letter a displated in top left corner of menu icon on canary
- Issue 265848: pasting a data-uri into Metro address bar makes it completely invisible
- Issue 266660: (restricted)
- Issue 268220: (restricted)
- Issue 271962: Investigate correct focus event propagation path for NativeTextfieldViews and InputMethodTSF
- Issue 272668: Weird painting in the find bar (Win8 Metro)
- Issue 273106: Blue lowercase 'a' badge on Chrome Canary menu icon, but no "Open Ash Desktop" menu item
- Issue 276987: Japanese Input does not respect keyboard layout
- Issue 279097: Web MIDI: implement MIDIConnectionEvent
- Issue 293394: Unable to reopen last closed tab because Google Pinyin always eats 'Ctrl+Shift+T'
- Issue 310698: (restricted)
- Issue 311448: Images can not easily be deleted in contentEditable elements in Chrome for mobile
- Issue 311488: Migrating to Win SDK 8.1
- Issue 313911: Google search page tab title not read by JAWS
- Issue 315010: Regression: Omnibox suggestions flashing just before the 'Google Pinyin IME' candidate window shows up (Win7)
- Issue 317945: Remove support for system V SHM in the sandbox
- Issue 318484: aura: omnibox popup history ignores system font foreground colour
- Issue 319122: Remove TSFEventRouter(Observer), InputMethodTSF, and related unused code.
- Issue 321294: Crash with Matrox Power Desk software (TripleHead2Go and DualHead2Go devices)
- Issue 323376: Cannot activate an IME in Omnibox (Aura)
- Issue 326837: (restricted)
- Issue 330735: Remove non-Aura Windows code
- Issue 331419: (restricted)
- Issue 332729: Regression - Other elements are clickable in presence of "Confirm New App" dialogue box.
- Issue 333011: Windows 8.1 Color Emoji on Segoe UI Emoji is not supported on Chrome
- Issue 334600: (restricted)
- Issue 335386: (restricted)
- Issue 335471: Don't show the input mode indicator when it's located in a weird position.
- Issue 335912: Chrome: Crash Report - Magic Signature: views::DesktopWindowTreeHostWin::HandleIMEM...
- Issue 335972: IME input mode should change dynamically as an IME becomes active/inactive
- Issue 336740: IME can't be enabled in FlashPlayer when Chrome settings for plug-ins is set to "Click to play".
- Issue 337927: Google English keyboard inserts extra string
- Issue 338357: (restricted)
- Issue 338644: In some Win8 + Chrome32, unicode glyphs with 4-byte codes are not shown
- Issue 340199: X keyboard layout / input handling is wrong
- Issue 340569: Can't delete U+FF8A U+FF9E in the text area
- Issue 340972: Chrome crashes with an error message asking me if I want to restart Chrome
- Issue 343622: Can't activate Chinese/Japanese input method in Hangouts chatting window
- Issue 343875: Check failed: text_input_type_ != ui::TEXT_INPUT_TYPE_NONE in render_widget_host_view_aura.cc (2344)
- Issue 344091: Chrome_Win: Crash Report: 'views::corewm::InputMethodEventFilter::DispatchKeyEventPostIME'
- Issue 344410: Web MIDI: midi_manager_alsa requires exclusive access to device
- Issue 344773: Omnibox suggestions overlaps candidate window on selecting Google Pinyin IME
- Issue 345080: IMEs are disabled on Hangout chat window after link navigation
- Issue 347360: 'ols.bat"' is not recognized as an internal or external command
- Issue 348194: Linux Aura : Tool tip background color is shown incorrectly
- Issue 348437: Linux Aura: Task manager should have native window dressing
- Issue 348907: The 'Chrome hangs when we select 'Google Pinyin' and click on 'Load Unpacked extension' on 'chrome://extensions' page
- Issue 348983: Chrome: Crash Report - views::DesktopWindowTreeHostWin::HandleIMEMessage
- Issue 349163: Key modifier doesn't work when cursor is in text box with some IMEs
- Issue 349576: git runs out of memory cloning https://chromium.googlesource.com/chromium/reference_builds/chrome_win.git
- Issue 349788: Chrome crashes on startup when using Matrox software with dual monitors
- Issue 349896: (restricted)
- Issue 350018: Use some new flags to improve the VS build
- Issue 350260: (restricted)
- Issue 350639: Large PDB hack no longer required post VS2013 Update 2
- Issue 350694: "fetch --nohooks chromium" fails with an error because reference_build\\_gclient_chrome_win_xxxxxx is not found
- Issue 351991: Notifications from extension disables ibus-based input methods until refocus
- Issue 352598: The 'Choose Folder' window opens behind the Feedback' app when Google Pinyin is selected.
- Issue 353914: Can't delete unicode6 emoji of surrogate pair in Google Search of Chrome.
- Issue 354495: The last Korean character before space is inserted after a space in all input field
- Issue 355122: (restricted)
- Issue 355995: Can't delete certain Thai characters in text box on Chrome 33 Android
- Issue 356467: Sometimes, IME switching doesn't work properly
- Issue 359843: Directwrite causes tab crashes on some pages
- Issue 359892: (restricted)
- Issue 360317: Joining multiple same type devices to Windows PC, inputs method return only one entry.
- Issue 360351: Some websites (twitter/github) crash when DirectWrite is enabled
- Issue 360388: Ignores all keyboard input
- Issue 362155: Ugly fonts in address bar, tab title and sandwich menu
- Issue 362698: ozone: implement input method support on ChromeOS
- Issue 363358: Hangouts does not work on Google Chrome beta
- Issue 363604: Cannot type into Chromium
- Issue 363921: keyboard input is broken in a forked version of Chromium 34 shipped with Ubuntu 14.04
- Issue 364571: Chrome breaking devanagari input using IBUS input method.
- Issue 364707: selecting url from address bar no longer includes the scheme
- Issue 365015: Aura shows garbage font when Droid Sans enabled
- Issue 365063: Cannot type any text in any text field
- Issue 365152: Korean Character Input Problem
- Issue 365208: Japanese fonts shipping with Windows look bad in DirectWrite mode
- Issue 366952: HTML5 color picker isn't using a native window
- Issue 367919: (restricted)
- Issue 368100: Keydown fires extra event (key 229)
- Issue 368218: Task manager does not match with the browser window border color
- Issue 368679: Smilies in Google search textfield are not deleting when "Delete key" is pressed
- Issue 369190: Copying from the URL bar no longer includes http:// prefix
- Issue 369229: Titlebar mouse events are no longer passed to underlying window manager
- Issue 369788: Closing extension popup breaks chrome
- Issue 369846: Accept suggestion not working in console
- Issue 370778: Extension IME doesn't works fine
- Issue 371478: ozone/freon: make X11 optional for chromeos builds
- Issue 371652: IMEs cannot activate
- Issue 372650: IME stops working when switching focus between native input fields and <INPUT type='text'> field
- Issue 373174: CJK IME disabled after inserting a hyperlink on Google Blogger
- Issue 373181: Chromium packet storm on port 5228
- Issue 373712: (restricted)
- Issue 373756: accessibility: accented/currency/emoji keys entered via on screen keyboard do not show (ee£????????)
- Issue 373934: Not able to delete a letter followed by a space on Google search box
- Issue 373946: Keyboard stopped to work in Chromium
- Issue 374077: MacViews: Implement a ui::InputMethod for Mac
- Issue 374882: problem to install the new version on Ubuntu 10.04
- Issue 374950: AltGr moves curses to the left in input boxes (but not address bar).
- Issue 375659: Tooltip text isn't visible when using dark GTK theme + Aura
- Issue 375670: Deadkey (apostrophe) shows up after first hit
- Issue 375684: Problem with national characters
- Issue 375758: Chrome V.35 seems to no longer provide WM hints used by some window manegers like WindowMaker
- Issue 375827: Web MIDI api completely broken on linux
- Issue 375866: libappindicator support broken in Fedora 20
- Issue 375909: Chrome 35 on Ubuntu x64 does not pick up OpenJDK 1.7
- Issue 376258: Error typing accented letters
- Issue 376346: Weird text-rendering in Korean Italic case only on ubuntu.
- Issue 376515: Omnibox has dark background since Chrome 35 (Linux, KDE, Aura)
- Issue 376616: REGRESSION: Chromium raises even if click-to-raise is disabled on the current WM
- Issue 377203: Cursor moves back if Rigth Alt is pressed in text box
- Issue 379931: Japanese IME doesn't work at all
- Issue 381597: Chrome doesn't handle Linux X11 forward key event anymore (breaks our language's IME)
- Issue 382201: infolist_window grabs the focus which causes a weird effect on Japanese input
- Issue 383009: (restricted)
- Issue 390190: Microsoft Word / RichEdit specific keyboard shortcuts for international characters are no longer supported
- Issue 391668: (restricted)
- Issue 392875: Cannot input letter "i"
- Issue 393691: Cannot enter aA umlauts while
- Issue 394416: (restricted)
- Issue 395019: linux: XLookupString doesn't support some characters.
- Issue 395470: Cannot type the letters "c" and "h" in web pages
- Issue 397143: M36 Regression: Custom keyboard layouts extensions don't work on startup.
- Issue 398799: IME does not work 64-bit Chrome
- Issue 398890: Caret position randomness when using Google Japanese IME
- Issue 399864: a, o and u not working
- Issue 400736: Can't delete Emoji at google.com search box.
- Issue 402307: With Dvorak International, altgr falls back to qwerty instead of 3rd level
- Issue 403347: On Windows laptops with touch screens the virtual keyboard pops up incorrectly
- Issue 404752: (restricted)
- Issue 404767: (restricted)
- Issue 406233: Chrome crashed, no specific step to reproduce just I was running debug version of he chrome. and doing random operation.
- Issue 407207: Add a visual indicator for internal IME states
- Issue 407233: IME: Empty compositionend event fired after complete composition in Pinyin on Linux, signals cancellation
- Issue 407256: IME: Chrome does not fire any composition events for CJK spaces
- Issue 408561: cannot choose other layouts than US or Japanese with Japanese IME (like AZERTY etc.)
- Issue 409016: Memory leak in MidiManagerAlsa implementation
- Issue 409709: ideographs in Chinese and Japanese show as empty space in Linux in UI elements like tooltips, addressbar and Ctrl+F search entry
- Issue 411747: Chinese input method doen't work correctly sometimes, for unknown reason
- Issue 411768: Can't input non-default language
- Issue 411788: Notifications from extension disables the connection to ibus
- Issue 414258: Regression: "Ctrl+tab" keyboard shortcut doesn't work after reloading sad/crashed tab.
- Issue 417152: Regression:Touch selection quick menu appears on deleting url from chrome://settings/startup on touch device.
- Issue 421645: (restricted)
- Issue 421980: IME does not work in Chrome OS mode on Windows 7
- Issue 422203: (restricted)
- Issue 422685: Backspace submits composition string unexpectedly
- Issue 424680: Update and start using Android SDK 21
- Issue 424902: Web pages containing Java Applets not working well
- Issue 427780: Out-of-order & slow key input on Linux/ChromeOS
- Issue 428516: new Korean IME: cannot enter a number and a punctuation after a standalone Hangul consonant or vowel
- Issue 429957: Korean input issue while deleting characters
- Issue 430997: Roll android aosp to lollipop
- Issue 433715: Chinese font selected while typing Japanese font in search box
- Issue 437764: ibus-based IMEs may not work with Google Chrome after rebooting the computer
2013年やったこと - Firefox, LibreOffice, Gyp 編
2013年やったこと - Firefox, LibreOffice, Gyp 編.
Firefox: TSF 無効時の HTML5 Forms のtype 指定と InputScope の対応作業
866736 – InputScope support for IMM32 with CUAS
TSF モードの Firefox は InputScope に対応既なのですが,IMM32 モードでは特に何も考慮されていませんでした.実は SetInputScopes API を使えばレガシー IMM32 アプリでも InputScope に対応できるので,Firefox でもやってみた,という変更です.以下のように InputScope 周りを重点的に見ていた時期だったので,タイミングが良かったというのもありました.
- 同様の方法で InputScope に対応するコードを Chromium 向けに書いていた
- 同時期に Mozc の InputScope 対応を実装していた
ゴールデンウィークに Mozilla Japan の六本木オフィスで行われたハッカソンで書き上げたものです.パッチの送り方も一緒に教えてもらえたので大変助かりました.
ビルドを壊しちゃったり コードに CRLF が混ざっていたりと,チェックイン後も色々ご迷惑をおかけすることに.中野さんをはじめフォローしていただいた Mozilla の皆様ありがとうございました.
LibreOffice: IMR_QUERYCHARPOSITION 対応
Bug 64298 – Support IMR_QUERYCHARPOSITION for better integration with IMEs
LibreOffice に IMR_QUERYCHARPOSITION サポートを追加して,各種 IME が適切な位置にサジェストウィンドウを表示できるようにするというパッチです.
LibreOffice Writer 4.0 (修正前)
LibreOffice Writer 4.1 (修正後)
この問題との付き合いは長く,Mozc リリース直後にOpenOffice.org でサジェストウィンドウの表示位置が変というレポートがたくさん来て以来となります.3 年半のときを経てやっと根本的に対処できました.
- 変換候補の表示位置 ほか
- OpenOffice.org 使用時に
- openofficeで使用したとき、検索窓が画面の右下に来るため視線の移動が大きすぎます。
- Open Officeとの接続について
- OpenOffice Calcを利用する際、変換候補のポップアップ表示が画面右下に移動してしまう
IMR_QUERYCHARPOSITION を (直接的または間接的に) 利用している全 IME で表示位置が改善されます.
このパッチもたしかゴールデンウィークを利用して書いています.パッチの送り方からチェックイン後のビルド失敗の後始末まで LibreOffice チームのみなさんにたくさんフォローしていただきました.この場をお借りして改めてお礼申しあげます.
Gyp Issue 385: ninja generator doesn't handle LinkTimeCodeGeneration/ProfileGuidedDatabase for PGO
Issue 385 - gyp - ninja generator doesn't handle LinkTimeCodeGeneration/ProfileGuidedDatabase for PGO - Generate Your Projects - Google Project Hosting
年末休暇で暇つぶしに適当に見つけた Gyp のバグを直してみたというもの.特に困ってはいなかったのですが,たまには Gyp コミッターらしいことでもしておくかという感じ.
Gyp の Ninja 向けジェネレータが PGO 設定の一部をサポートしていなかったので,対応してみました.実装自体は単に対応表を書くだけだったのですが,コードレビューで「実際に PGO ビルドするテストもあるといいね」という流れになってテストを書いてみたら予想を上回る大変さだったという.この体験がもとになって書いたのが次の記事です.
Chromium で PGO が有効化される場合はもしかしたら意味があるかもしれません.もっとも,そのまえに Chromium のビルドシステムが Gyp から GN (Generate Ninja) に移行しちゃうかもしれませんが.
Gyp Issue 389: ninja generator is not aware of VCLinkerTool.GenerateManifest
Issue 389 - gyp - ninja generator is not aware of VCLinkerTool.GenerateManifest - Generate Your Projects - Google Project Hosting
上の Gyp Issue 385 のテストを書くのにどうしても必要になった機能です.
感想
メインプロジェクトと関連があるところを攻めつつ,みんなが便利になる方向の改良にもっていけたように思います.
今年の話とか
今年も隙を見て OSS プロジェクトにパッチを投げていきたいです.
2013年やったこと - Chromium 編
2013年やったこと - Chromium 編,いつもどおりコードが公開されている範囲で.
HTML5 Forms の type 指定と InputScope の対応作業
HTML5 Forms の type 指定と Windows 環境での InputScope を連携させるという変更です.Windows 8 以降のオンスクリーンキーボードは InputScope でレイアウトを切り替えるため,IME を必要としない言語でも有効なのがポイントです.
変更自体はそれほど難しくなく,特にトラブルもないまま無事リリースされていきました.
メジャーブラウザの InputScope 対応状況については,以下の記事にまとめています.
Omnibox フォント問題
Omnibox のフォントサイズが微妙に変わった/特定文字が□になったから直すべし,という案件.
- Issue 168480 - chromium - omnibox uses strange multi-sized font rendering in Windows - An open-source project to help move the web forward. - Google Project Hosting
- Issue 163135 - chromium - Texts in Chrome showing different height - An open-source project to help move the web forward. - Google Project Hosting
- Issue 178695 - chromium - Square boxes are displayed in Omnibox when Selected Chinese letter from candidate window - An open-source project to help move the web forward. - Google Project Hosting
なんでこのバグを担当する羽目になったかというと,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 投入にあたっては以下のように段階的な移行が行われました.
- non-Aura + Native Textfield Views 無効
- non-Aura + Native Textfield Views 有効
- 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 をサポートしない
- Issue 236733 - chromium - Native Textfield Views does not support IMR_QUERYCHARPOSITION - An open-source project to help move the web forward. - Google Project Hosting
- Issue 239629 - chromium - IME candidate window is far away from text input field when input text in Chrome UI using IME - An open-source project to help move the web forward. - Google Project Hosting
ゴールデンウィークの暇つぶしに軽い気持ちでパッチを投げたもの.Desktop Aura や Ash のリリースプランを当時の私は全く知らなくて,村の近くに出没したゴブリンでも退治する感じでパッチを投げてしまったのでした.ちなみにこの後どうなるかというと,
- Native Textfield Views 導入編 (ゴブリンの巣)
- Native Textfield Views + non-Aura完結編 (なんか最初の山場)
- Desktop Aura 編 (魔王城)
- Ash 編 (宇宙)
みたいな流れになります.
この時直したバグは,Native Textfield Views が有効だとサジェストウィンドウ位置が揃わないというものでした.
このパッチのせいで,Omnibox 上でカーソルが点滅しなくなるというバグを引き起こしてしまいあわてて直したりもしています.
Native Textfield Views で変換中の文節区切りが分からない
ゴールデンウィークのゴブリン退治その 2.
IME で入力中,文節区切りが分からないという問題の修正です.Chrome OS 版で発見されたまま直っていなかった問題ですが,さすがにこのまま Windows 版に出すのはまずかろうという気持ちで (特に担当だったわけではないのですが) 直してみました.
Native Textfield Views + non-Aura 環境での IME 対応
6 月ごろだった気もしますがやや記憶があいまい.
既に一月は復活IMEバグと戦い続けていた.
「このバグで最後のはずだ」
「ん,なんだこのコピペされたコードは」
「聞いてないぞ」
「Ben Goodgerのレビューでコミットされてたんだ」
「なんてこった,ここはIMEバグの巣だ!」
今,IMEの平和をかけた最後の戦いが始まる.
— NyaRuRu (@NyaRuRu) May 31, 2013
思っていたより事態が深刻だと気付き始めます.というのも,既に 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 対応
- Issue 287620 - chromium - TextInputFocus is wrong for textfield on popup window - An open-source project to help move the web forward. - Google Project Hosting
- Issue 287624 - chromium - TextInputFocus is wrong for textfield in webcontent area just after full-screen. - An open-source project to help move the web forward. - Google Project Hosting
- Issue 294943 - chromium - Cannot turn on IME after cloging a popped up window - An open-source project to help move the web forward. - Google Project Hosting
- Issue 296505 - chromium - Layout of on-screen keyboard is not aware of HTML5 input type - An open-source project to help move the web forward. - Google Project Hosting
- Issue 265461 - chromium - Typing accented characters is bad using US International keyboard - An open-source project to help move the web forward. - Google Project Hosting
- Issue 319100 - chromium - Holding enter upon navigation triggers web content form submission. - An open-source project to help move the web forward. - Google Project Hosting
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 サポート
- 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
- Issue 326774 - chromium - Win/Ash: IME candidate window overlaps OmniBox suggest - An open-source project to help move the web forward. - Google Project Hosting
- Issue 328237 - chromium - Win/Ash: IME's candidate window is not shown at the caret position - An open-source project to help move the web forward. - Google Project Hosting
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 で入力するときは,
- WinRT プロセス
- ブラウザプロセス
- レンダラプロセス
- プラグインコンテナプロセス
と 4 つのプロセスが非同期 IPC で連携しながら動作することになるのですが,その綱渡り具合を真に理解できる人がはたして世界に何人いるのかにも興味があるところ.
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 のシェア推定とかやっているところには影響があったはず.
@NyaRuRu FYI: http://t.co/Ary1YgDNhu
— なかのん -Nakanon- (@d_toybox) 2013, 7月 11
@NyaRuRu あー、確かに、Win8.1でUA名、6.2のままですね。
— なかのん -Nakanon- (@d_toybox) 2013, 7月 11
という感じの,のどかな会話から思いがけず発覚したのが印象的でした.Mozilla 側でも直後に修正されています.
まあついでということで Chromium にはパッチを投げてみました.メジャーブラウザ の User Agent 文字列に影響する変更というのはなかなか貴重な体験でした.
全部の *.exe にアプリケーションマニフェストファイルを設定すべき
先ほどの GetVersion(Ex) API 問題を修正するために chrome.exe のマニフェストファイルをアップデートしたわけですが,コードレビューで「ユニットテストとプロダクションバイナリで動作が変わるのは良くないから,全部の *.exe に同じアプリケーションマニフェストを設定できないかな」的なコメントが付いたで急遽やることになった仕事です.
Mozc で培った Gyp 誰得ノウハウをいかんなく発揮して華麗に解決! といけばよかったのですが,実際全部の *.exe にマニフェストファイルを埋め込んでみたら今度は「ユニットテストのビルドが 30 倍遅くなった!」と怒られます.えー
結局いくつかのユニットテストではマニフェストファイルを埋め込まず隣に置く方式になりました.
後日談としては,Gyp r1813 でマニフェストファイルの扱いが大幅に見直されたので,パフォーマンスを悪化させずにマニフェストを埋め込むことができるようになりそうです.
Web MIDI: Windows 対応
- Issue 303599 - chromium - Web MIDI: implement MIDIManager for Windows - An open-source project to help move the web forward. - Google Project Hosting
- Issue 317355 - chromium - Web MIDI: MIDIInput.cpp does not handle SysEx message properly - An open-source project to help move the web forward. - Google Project Hosting
- Issue 329964 - chromium - Web MIDI: receivedTime is incorrect on Windows - An open-source project to help move the web forward. - Google Project Hosting
社内 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 周りのクリティカルな部分のコードレビューに費やす時間ぐらいはまあなんとか捻出したいところ.
2013年やったこと - Mozc 編
2013年やったこと - Mozc 編,いつもどおりコードが公開されている範囲で.
Mozc IPC の Windows 64-bit 対応
Windows 環境で動く Mozc は名前付きパイプ使ってプロセス間通信を行うのですが,いわゆる "Squatting Attack" 対策として,GetNamedPipeServerProcessId API で接続先のプロセス ID を取得し,さらにそのプロセス ID から GetModuleFileNameExW API で実行ファイル名を取得して検証しています.が,この仕組みが今は動いていても将来的にうまく動かないことがあるかもという問題.
このころ mozc_server や mozc_renderer を 64-bit で動かす実験を行っていて気付いたわけですが, 32-bit プロセスから 64-bit プロセスに対して GetModuleFileNameExW API を呼び出すと必ず失敗するようです.仕方ないので GetProcessImageFileNameW API を使うように変更して対処.これまで mozc_server と mozc_renderer は常に 32-bit プロセスだったので問題が表面化していなかったというわけでした.
TSF-Mozc 使用時に ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0) が動作しない
IMM32 の頃には,アプリケーション側から進行中のコンポジションをキャンセルするという API が存在しました.TSF になってそういう API はなくなったのですが,CUAS はなにかしらの方法でこの IMM32 API を エミュレートする必要があります.実際これは「コンポジションの範囲を空にする」という形で行われています.ということで TSF-Mozc でも対応する必要があるというわけでした.
Excel が,インライン補完のためにこの機能に依存しているので割と重要だったりします.
TSF-Mozc で候補ウィンドウの候補をマウスで選択・決定できない問題の修正
経験上ほとんどの人はマウスで候補ウィンドウを選択しないのを知っていたので,TSF-Mozc ではマウス関係の処理を後回しにしていました.とはいえ,タッチイベントでも動作しないのはそろそろよろしくないというのもあって修正という感じです.
TSF-Mozc での InputScope のサポート
InputScope も登場後 10 年以上経っている仕組みで,いまさらという感もありますが,Windows 8 以降はだいぶ InputScopeへの移行が進んでいます.最近はブラウザの HTML Forms の種類が InputScope で通知されたり,Windows 8 以降でImmSetConversionStatus API が (デフォルト設定では) 実質廃止になったりで,IME 側も InputScope 対応が割と重要になってきています.というわけで TSF-Mozc でも対応してみました.
アプリケーション開発者様におかれましても,Windows 8 以降,ImmSetConversionStatus API は大多数のユーザー環境で期待通り動作していない可能性が高いため,この機会に InputScope に移行してしまうのが良いのではないかと思います.詳細については下記資料等を参照してください.
- Switch text input changed from per-thread to per-user (Windows)
- IMEモードの切り替えをWindows 8以降の環境で行う方法 - InputMan for Windows Forms 7.0J - ナレッジベースの詳細 | GrapeCity Developer Tools
さて,デスクトップ IME の文脈で気を付けるべき点として,アプリケーション側からのモード変更リクエストを永続的なものとして扱うか,一時的な変更リクエストとして扱うかという問題があります.たとえば次のような順序でテキストフィールドを移動していったとしましょう.
- 通常のテキストフィールド
- パスワードフィールド
- 通常のテキストフィールド
多くの場合,ステップ 1 で IME がオンの状態であれば,ステップ 3 でIME がオンの状態に復帰します.つまり,パスワードフィールドで IME が自動的にオフになるのは,永続的なモード変更ではなく一時的なモード変更というわけです.
では次の場合はどうなるべきでしょうか?
- 通常のテキストフィールド
- 全角カタカナが期待されるテキストフィールド
- 通常のテキストフィールド
ステップ 2 で IME の入力モードが「全角カタカナ」になるのはまあ良いとします.では,ステップ 3 に移動したときにも「全角カタカナ」のままであるべきでしょうか? それともステップ 1 のときのモードに復帰すべきでしょうか.
TSF-Mozc に関しては,InputScope によるモード変更リクエストはその場限りの一時的なものであるという解釈を行いました.したがって,上記ステップ 3 ではステップ 1 のときのモードに復帰します.簡単に Design Doc を書いていますので詳細についてはそちらを参照してください.
Windows 版 Mozc での Mode Indicator のサポート
これ.
位置形状とフォントサイズの決定以外のほぼ全てを担当しました.個人的にはカーソル直下よりもカーソルに対して左揃えの方が良いんではないかとか,ちょっと大きすぎるんではないかとか色々思うところはあるのですが,まあデザイナーさんがそう言っているわけで案件.個人的にはもうちょっと作りこみたかったのですが,別の仕事が忙しくてあんまり専念できなかったのが心残りです.
InputScope で自動モード変更を行う以上,この種の視覚的フィードバックは必須ですね.というわけで InputScope 対応とセットで実装されました.
周辺文字列を利用した変換の (部分的) サポート
周辺文字列を利用した変換も十数年以上の歴史があるいまさら技術ではあります.前世紀の IMM32 時代から IMR_DOCUMENTFEED メッセージをサポートしたアプリケーションでは周辺文字列を利用した変換は可能でした.
さて,周辺文字列を利用した変換というのは実際のところあんまりコストパフォーマンスの良くないアプローチだと思っています.細切れ変換対策という意味では,変換エンジン側で前回コミットされた文字列を覚えておけばすむ話です.というわけで,今回注目したのは,IME をオフにして入力しがちな文字種,つまり半角英数です.
たとえば「明日1日」という文章を入力するのに,
- 「明日」を入力
- IME をオフにする
- 「1」を入力
- IME をオンにする
- 「日」を入力
という使い方をする人は一定いることが分かっています.以前の Mozc では,ステップ 4 実行時に内部ステートは「文頭」状態でした.というのも,IME がオフの状態で入力された内容はモニタリングしていないので,ステップ 5 で入力する内容がどういう文章に続くものなのか把握できません.今回救いたかったのはまさにこういうケースで,カーソル前にある文字種がアルファベットか数字かどうかだけを判定します.このあたりの詳細についても Design Doc を書いておきましたので詳細が気になる人はどうぞ.
imm32-mozc と tsf-mozc,ibus-mozc および mozc_server の実装を担当しました.
IMM32 版では IMR_DOCUMENTFEED を単純に使うだけですが,TSF では Transitory Extensions という拡張的な仕組みも使っていて,メモ帳や Internet Explorer にも対応しています.軽く調べてみた限り,ATOK 2013 も MS-IME 2013 も Transitory Extensions までは使っていないようなので,ちょっとしたアピールポイントではないかと思っております.
このとき書いたコードは別のオープンソースプロジェクトで使われたりもしているようです.
C++11 対応
最近社内コード規約的に C++11 が解禁されつつあるので Mozc でもいくつかコードのクリーンアップを行っています.具体的には,
- 自前 scoped_ptr から std::unique_ptr への置き換え
- COMPILE_ASSERT マクロの static_assert への置き換え
- auto での書き換え
- NULL から nullptr への置き換え
あたりをちまちまやってます.
最近は Visual C++ の C++11 適応度合が上がってきていてだいぶ楽なのですが,意外に足を引っ張るのが Mac OS X だったり.というのも,libc++ の実行時ライブラリが標準で入るようになったのが Mac OS X 10.7 以降.未だに Snow Leopard をサポートしていたりすると C++11 の大部分の機能が使えないのでした.
UCS2 しかサポートできない内部関数の削除
Mozc コードベースに残っていた UCS2 専用関数をすべて削除しました.
TSF-Mozc でタッチに最適化されたオンスクリーンキーボードを表示するように
ITfFnGetPreferredTouchKeyboardLayout を実装するだけ,というわけでもなくて Windows のオンスクリーンキーボードは U+F003 と U+F004 に特別な意味を持たせたりしているのでその対応とか.詳しくは下記資料参照のこと.
可能なら LogicalToPhysicalPointForPerMonitorDPI API を使う
Mozc の候補ウィンドウや Mode Indicator は,入力中のプロセスとは別のプロセスで動いているので,DPI 仮想化にともなう座標変換が必要になることがあります.Windows 8.1 Preview で LogicalToPhysicalPoint API が動作しなくなっていたので,新しく追加された LogicalToPhysicalPointForPerMonitorDPI API が利用可能ならそちらを使う,といった修正を行っていました.Windows の DPI 周り,ほんと落ち着かないですね.
次の資料とかが詳しいです.
http://go.microsoft.com/fwlink/?LinkID=307061
アプリケーションマニフェストに Windows 8.1 対応宣言を追加
恒例行事.
ITfLangBarItemButton::GetIcon で返すモノクロフォントを実行時に描画
Accessibility (a11y) 案件.
Windows 版の Mozc は,控えめに言っても Accessibility 関係の機能が全然足りていないのですが,珍しく対応している機能のひとつに言語バーのテキストアイコン色があります.Windows では,デスクトップテーマをハイコントラストモード(背景色黒・文字色緑) に変更すると,言語バーのテキストアイコンも緑色に切り替わります.
ではこれどうやって実装するかですが,大まかに方法は 2 つ.
A. 実行時にアイコンを描画する.この場合,テーマカラーを実行時に取得できるので文字色は問題ない.テーマが変更されるたびにアイコンを再生成する必要がある.
B. モノクロアイコンを事前に生成しておき,言語バーAPI に TF_LBI_STYLE_TEXTCOLORICON フラグを渡す.この場合,言語バー側で色変更を行ってくれる.
Mozc はながらく B の方法を使っていました.が,最近になってビットマップハンドルのリークが発生しているという報告を受けて調べてみると驚きの事実が! ITfLangBarItemButton::GetIcon にモノクロアイコンを渡すと,言語バー内部でビットマップハンドルのリークが発生するようです.というわけで方向 A で書き直しました.
この問題,原因の発見までがとにかく大変だったのが印象的でした.ハンドルリークが全然再現できず困っていたのですが,ユーザーの方からアップロードしていただいたスクリーンショットがクラシックテーマだったことが気になってテーマを変更してみたところやっと再現できた,というケースです.どういうやりとりが行われたか興味がある人は以下のスレッドをどうぞ.
TF_LBI_STYLE_TEXTCOLORICON を使用している IME 作者様はご注意ください.
Adobe Sandbox をサポート
@corvussolis さんから Adobe Flash および Adobe Acrobat Reader で使われている Sandbox の動作について教えてもらって Mozc でも対応してみたという話.これでやっと Firefox でも「保護モード」オンのままニコニコ動画にコメントを書けるようになりました.
ご協力いただいた皆様に感謝.
Windows 8 以降で MS-IME からのユーザー辞書インポートが動かなくなっていたのを修正
詳細については diff を参考にしてください.
Owner Rights SID を設定
Windows では,オブジェクト所有者に暗黙に WRITE_DAC および READ_CONTROL 権限が許可されるという仕様がありましたが,Vista 以降この挙動を拒否することが可能になりました.
というわけで Mozc でも不要な権限を削除してみたという話.追加すると権限が減る系の SID ですね.
Windows 版 Mozc のビルド時に Cygwin が不要になった
Mozc のビルドは,もともと Cygwin に依存しないように作られていました.しかし,Mozcのビルドシステムを SCons から gyp に変更したときに,gyp に引っ張られる形で Cygwin 依存が生まれてしまいました.
外部コマンドの呼び出しに時に色々気を付ければ Cygwin は不要というのは分かっていたのですが,とりあえず重要度は低いので後回しのままとなってはや数年,いい加減直すかということでやっと依存関係を解消したという話です.Windows 版 OSS Mozc のチェックアウトサイズもだいぶ減ったはず.
ちなみに Chromium も同様の問題があって,以下のようにビルド時の Cygwin 依存を取り除く努力が行われています (こっちも数年がかり).
以下 OSS Mozc 固有っぽいもの
Issue 42: get rid of absolute path in unix/ibus/gen_mozc_xml.py
https://code.google.com/p/mozc/issues/detail?id=41
ibus-mozc のバイナリとアイコンファイルのインストール先はカスタマイズできるべきだという案件.3 年ぐらい放置されていのですが (すみません) リファクタリングの一環として対応.
Issue 180: Mozc and IBus does not respect xinerama at all
https://code.google.com/p/mozc/issues/detail?id=180
マルチディスプレイ環境で mozc_renderer が画面境界の判定に失敗するというバグ.gdk_screen_get_monitor_at_point を使うことで解決.
Issue 182: mozc property titles are empty in gnome-shell
https://code.google.com/p/mozc/issues/detail?id=182
Red Hat で ibus-mozc をメンテナンスされている Tagoh さんから転送されてきたバグの対応.Gnome-Shell はいくつかの IBus メタデータに依存しているのですが,ibus-mozc がそれらを設定していないという問題.具体的には,
- IBus 1.5 以降にのみ存在する symbol というプロパティをセットするようにする (これを行わないと現在の入力モードがアイコンとして表示されない)
- Gnome Shell は "InputMode" という名前のプロパティに現在のモード (全角カタカナとか直接入力とか) が設定されていることを期待しているので,プロパティ名を変更
という感じです.ちなみにこのあたりの Gnome-Shell の仕様はどこにもドキュメント化されていません.自分でソースを読んで調べる必要があります.結果的に以下のような見た目になりました.
このパッチがあたっていないバージョンの Mozc (具体的には 1.6.1187.102 以前) では,入力中のモードは分かりませんし,入力モードを Gnome Shell から選択することもできません.
Issue 188: Add Session command for ConvertPrevPage and ConvertNextPage
https://code.google.com/p/mozc/issues/detail?id=188
Fcitx の開発者から来た機能追加リクエスト.Fcitx の候補ウィンドウには次頁・前頁に相当するボタンが存在するのですが,その動作に対応するメッセージが Mozc のプロトコルに存在しなかったという問題.たまたま Windows 8 のソフトウェアキーボード対応で似たような需要があったので合わせて対応となりました.
Issue 189: use_libprotobuf=1 does not work in Mozc 1.10.1390.102
https://code.google.com/p/mozc/issues/detail?id=189
Red Hat で ibus-mozc をメンテされている Tagoh さんから,システムにインストールされている libprotobuf を使用する場合のビルドが壊れているとの報告があったので粛々と修正.壊したのも私なのでマッチポンプ案件だったりします.
Issue 195: Candidate Popup is hidden by Cinnamon menu
https://code.google.com/p/mozc/issues/detail?id=195
Linux で Cinnamon を使っていると,mozc_renderer がメニューの後ろ側に行ってしまうという問題.修正は 2 行で済んだんですが,環境のセットアップやら調査やらで結局 1 日ぐらいかかっているという.ちなみにこのケースでは日曜日が消えました.
Issue 198: 'build_mozc.py gyp' fails when gyp r1667 or higher is used
https://code.google.com/p/mozc/issues/detail?id=198
Mozc 開発ではビルドに使用する gyp のリビジョンを固定しているのですが,OSS Mozc をビルドする人は推奨リビジョン以外の gyp と組み合わせている人もいるらしく,gyp 側の変更でビルドできなくなることがあります.
今回は,Mozc r171 以前と gyp の r1667 以降を組み合わせるとビルドに失敗するという問題でした.
Issue 199: ibus-mozc must be locked down on the Gnome Shell's locked screen
https://code.google.com/p/mozc/issues/detail?id=199
CVE-2013-4509 の ibus-mozc 側の対処を一通りやりました.
私も完全に背景を把握できているか怪しいのですが,概ね以下のような感じだと理解しております.
- 2013年1月4日,Gnome 3 環境で IME をオンにしたままスクリーンをロックし, Gnome-Shell のスクリーンロック解除画面からパスワードを入力してロック解除しようとすると,パスワードフィールドで IME がオンのままになっているというバグが Red Hat の Jens Petersen さんから報告される.Red Hat Bug 891835
- 2013年1月9日,Red Had の Ueno さんから,GTK の "input-purpose" と "input-hints" を,パスワードフィールドにセットすることで問題が回避したらよいのではという提案がなされる.Gnome Bug 691392
- 2013年1月10日,Red Hat の Ueno さん,ibus-gtk2 にパッチをコミット (927e9f58).この変更は IBus 1.5.3 としてリリースされる.変更は ibus-gtk2 に対するもので,IM Engine 側では何もする必要がない.具体的には,"input-purpose" が password であれば,使用している IM Engine に関わらず IM Engine が無効化される.
- 2013年8月14日,Red Hat の Ueno さん,ibus-gtk にパッチをコミット (3b3a7cec).この変更は IBus 1.5.4 としてリリースされる.この変更によりまたしても挙動が変わり,"input-purpose" が password のときの振る舞いは各 IM Engineの責任になる.具体的には,IM Engine が IBus 1.5.4 以降の環境で動作する場合のみ,このコミットで追加された ibus_engine_get_content_type 等の新しい API を使って IM Engine の動作を変更する必要がある.
- 2013年9月21日,Red Hat の Fujiwara さんから IBus 1.5.4 のリリースがアナウンスされる.この中で "Handle GTK+ input purose for gnome-shell password dialog and each engine need to implement it" として各 IM Engine 開発者向けにアナウンス.
- 2013年9月21日,俺のターン! IBus 1.5.4 のリリースノートを受けて OSS Mozc Issue 199 をファイル.この時点では状況を完全に把握できていませんでした.
- 2013年9月30日,俺のターン! やっと状況を把握.急いでOSS Mozc Issue 199 へのパッチを公開.帰宅後色々弄っていて事態の深刻さに気付き急いで書き上げた感じの奴です.翌日ほんと眠かったです.
- 2013年10月1日,Red Hat の Mike FABIAN さんから,IBus 1.5.4 側の問題で "input-purpose" が正しく通知されないことがある問題が報告される.Red Hat Bug 1013948 この問題はすぐに修正されるものの,対応する IBus の安定板リリースは行われておらず,各ディストリビューションでは独自にパッチを取り込んで IBus 1.5.4 として配布している.
- 2013年10月25日,openSUSE のコミュニティメンバーの Takeyama さんから,Novel Bug 847718 がファイルされる.
- 2013年11月4日,Red Hat の Kurt Seifried さんにより今回の問題に CVE-2013-4509 が付与される.
この後 IBus を採用する各種ディストリビューションで色々対応が進んだようです.
Issue 201: making initial mode customizable for ibus-mozc
https://code.google.com/p/mozc/issues/detail?id=201
1.5.2 のころまでの IBus は,各 IM Engine は「直接入力 (いわゆる IME オフ)」というステートを持たないことを前提に設計されていました.従って,ibus-mozc は起動直後にひらがなモードである必要があります.
が,IBus 1.5.3 頃から,日本語 IME に関しては各 IM Engine 内部でオンオフ状態を切り替える方向に IBus 上流の人たちは心変わりしたようです.Red Hat の Fujiwara さんが ibus-anthy の挙動変更について下で説明されています.
https://code.google.com/p/ibus/issues/detail?id=747#c31
この変更にともない,以前の使い勝手を再現するためには,ibus-mozc が起動直後に「直接入力 (いわゆる IME オフ)」になって欲しいという要望が来たのが OSS Mozc Issue 201 です.
とはいえ Mozc は IBus 1.4 もまだ対応していますから,IBus のバージョンによらずデフォルトモードを変えてしまうと今度は IBus 1.4 ユーザーが困ることになります.また,デフォルトモードを選択する UI を追加しようにも,Mozc の設定画面は imm32-mozc, tsf-mozc, ibus-mozc, uim-mozc, fcitx-mozc, emacs-mozc, Mozc for IMKit で共有されているため,IBus 1.5.3 以降専用の項目を追加するのは躊躇するところです.
とりあえず初期状態をオフにするパッチだけは公開しましたが,以後のリリースでどうするかは未定です.
https://code.google.com/p/mozc/issues/detail?id=201#c8
ちなみに,初期値を変更するぐらい簡単だろうと思われる方もいらっしゃるかもしれません.が,実際は結構面倒です.事実,上のパッチを適用すると,mozc_server が予想外のクラッシュをした時のプレイバックの仕組みが壊れることが分かっています.初期値が変わっちゃったわけですね.
その他 OSS Mozc でメンテナンスしていたページ
その他 OSS Mozc 関係でやったこと
2013年4月ぐらいに fcitx-mozc のマニュアルテストを行って 6 件ぐらいバグを見つけたところ,作者様にものすごい勢いで修正していただきました.
あと,fcitx-mozc の再変換には,ibus-mozc の再変換用に私が書いたコードが使われていたりするようです.
今年の話とか
入社後なんだかんだでずっと Mozc に関わってきましたが,2014 年 1 月から社内の別プロジェクトに移ることにしました.オープンな場で何をやったか話すのはいつも通り書いたコードが公開されてからにしようかと思います.
Windows 版 Mozc は 20% の枠内で今後も協力していきたいところですが,ibus-mozc のメンテナンスまでやる余裕はなさそうです.ibus-mozc の今後の開発・メンテナンスを引き継いでもいいという方がいらっしゃいましたら社内外問わずお知らせください.
「ファイルの中身に依存しつつそのファイル自体を更新する」コマンドラインツールはビルドシステムと相性が悪い
関数型プログラミングのメリットについて語られることはあっても,「ファイルの中身に依存しつつそのファイル自体を更新する」コマンドラインツールがビルドシステムと相性が悪い,みたいな話をする人はあんまりいないようなので書いてみた.
Windows には signtool.exe というデジタル署名ツールがある.実行ファイル myapp.exeに署名したい場合は以下のようにする.
signtool sign /a myapp.exe
十分にシンプルなように見える.が,典型的なビルドシステムはこの処理がお気に召さない.試しに Chromium や node.js で使われているメタビルドシステムである Gyp で書いてみる.
{ 'targets': [ { 'target_name': 'myapp', 'type': 'executable', 'sources': [ 'main.cc', ], }, { 'target_name': 'sign', 'type': 'none', 'dependencies': [ 'myapp', ], 'actions': [ { 'action_name': 'run_signtool', 'inputs': [ '<(PRODUCT_DIR)/myapp.exe', ], 'outputs': [ '<(PRODUCT_DIR)/myapp.exe', ], 'action': ['signtool', 'sign', '/a', '<(PRODUCT_DIR)/myapp.exe'], 'msvs_cygwin_shell': 0, }, ], }, ], }
この Gyp ファイルから生成された Ninja 用ビルドファイルは,以下のようにビルド時にエラーとなる.
C:\work\dag>ninja -C out/Default sign ninja: warning: multiple rules generate myapp.exe. builds involving this target will not be correct; continuing anyway ninja: Entering directory `out/Default' ninja: error: dependency cycle: myapp.exe -> myapp.exe
myapp.exe をビルドするのに myapp.exe が必要なのはけしからん,とのこと.
私の場合,ラッパースクリプトを書いて署名前後でファイルパスの一部が変わるようにして回避することが多い.
例1.
mysigntool --input=myapp.exe --output=myapp.signed.exe
例2.
mysigntool --input=unsigned/myapp.exe --output=signed/myapp.exe
デジタル署名に限らず,mt.exe を利用したマニフェストファイルの埋め込み,rebase.exe を利用した事前バインド,Profile Guided Optimization (PGO) などで,うっかり入力ファイルと出力ファイルを同一パスにすると同様の問題に直面する.
なんでこんな話を書く気になったかというと,暇つぶしに Gyp にパッチを書いていて突然気付いたからである.
https://codereview.chromium.org/82703007#msg3
Directed Acyclic Graph (DAG; 無閉路有向グラフ) を事前に構築できることを前提としているシステムというのは,ビルドシステムにしろ MapReduce にしろ,案外日常的にお世話になっている.そういうシステムで「ちょっとした処理」を行うとして,なんだかうまく書けないなぁという処理,実はそれ入力と出力に循環があったりしませんか,というまあただそれだけの話.
こうやって考えてみると,世間のビルドシステムというのはファイルシステムと割とべったりくっついているということに気付かされる.
まとめ
入力パス名と出力パス名が同じになる操作は,一般的にビルドシステムと相性が悪い.典型的なビルドシステムでは,ファイルの内容ではなくパス名だけを用いて依存関係を記述する必要があることに注意.
Windows の IME を変換エンジンとして使う
プロセス分離型の IME の開発に携わった以上,一度は試してみたいと思っていた奴,の基礎実証実験っぽいのをやってみた.Windows向け IME を (とくに個人規模で) 作っている人にはもしかしたら役に立つかも.
テーマ
メインテーマは,Windows で IME を実装するとして,バックグラウンドで別 IME を有効化し,その IME に対してクエリを投げ,返ってきた結果を利用するための技術的な枠組みについて.ここではプロセスモデル的に Windows で可能かどうかという点のみを考える.
大まかな流れ
今回試した手法では,Windows 8 で TSF に追加された ITfFnSearchCandidateProvider という仕組みを活用する.このインターフェイスは,複雑なことはできない反面,1) 文字列を投げて文字列のリストが返ってくるというシンプルな仕組みである,2) ステートを持たず,IME でユーザーが入力中かどうかに関わらず自由に使える,という点で大変使いやすい.ただしすべての IME が実装しているわけではない.これについては後述.
また,このインターフェイスには "Windows 8 [desktop apps only]" と注釈がついている.ここで,プロセス分離型の IME 実装を前提とするのが生きてくる.プロセス分離型の実装では,好きにデスクトッププロセスと連携できるのでこれは特に問題にはならない.
具体的な流れ
以下の手順で,キーボードフォーカスを持たないバックグラウンドプロセス内で,ITfFnSearchCandidateProvider をサポートした IME を変換エンジンとして使用できる.
- バックグラウンドスレッドを作る
- スレッド内で COM を初期化する (STA 推奨)
- ITfInputProcessorProfileMgr.ActivateProfile を使用して,使用したい IME を有効化する.
- ITfThreadMgr2.ActivateEx を呼んで IME に初期化処理を行わせる.
- ITfThreadMgr2.GetFunctionProvider に,対象 IME の CLSID を渡して ITfFunctionProvider を取得
- GetFunctionProvider.GetFunction 経由で ITfFnSearchCandidateProvider を取得
- ITfFnSearchCandidateProvider.GetSearchCandidates で任意のクエリを行う
罠ポイント
上記手順の 3 が問題. Windows 8 以降はデスクトッププロセス間で IME 関係の設定を共有するようになったため,うかつに別 IME を選択すると他スレッド/他プロセスにも影響が及んでしまう.これについては, API を使って一時的にこの挙動に関する設定そのものを変更することで回避できそう.具体的には,SystemParametersInfo API に SPI_GETTHREADLOCALINPUTSETTINGS/ SETTHREADLOCALINPUTSETTINGS を指定して,以前の「スレッドごとに IME 関係の設定を保持」に変更する.変更は永続的である必要はなくて,IME を変更するごく短い間だけで十分なようだ.というわけで先ほどの手順をもう少し改良する.
- バックグラウンドスレッドを作る
- スレッド内で COM を初期化する (STA 推奨)
- 「スレッドごとに IME 関係の設定を保持」が有効でなければ SETTHREADLOCALINPUTSETTINGS を使って有効にする
- ITfInputProcessorProfileMgr.ActivateProfile を使用して,使用したい IME を有効化する.
- ITfThreadMgr2.ActivateEx を呼んで IME に初期化処理を行わせる.
- ITfThreadMgr2.GetFunctionProvider に,対象 IME の CLSID を渡して ITfFunctionProvider を取得
- GetFunctionProvider.GetFunction 経由で ITfFnSearchCandidateProvider を取得
- 「スレッドごとに IME 関係の設定を保持」を変更していれば,SETTHREADLOCALINPUTSETTINGS で元に戻す
- ITfFnSearchCandidateProvider.GetSearchCandidates で任意のクエリを行う
実際には「スレッドごとの IME 設定」を元に戻すのはもう少し手前でも問題ないかもしれない.
また,ユーザーが「アプリウィンドウごとに異なる入力方式を設定する」を有効にしている場合,GETTHREADLOCALINPUTSETTINGS は TRUE を返す.この場合はスレッドごとに異なる IME を有効化できるため何もしなくてよい.
応用
上の罠ポイントさえ回避できれば,複数のバックグラウンドスレッドを用意し,それぞれに別 IME をロードして構わない.つまり,複数の IME に対して同時にクエリを行うことができる.
ITfFnSearchCandidateProvider をサポートしている IME はどれぐらいあるのか?
手元の Windows 8.1 環境でしらべたところ,MS-IME 日本語版と ATOK 2013 はサポートしている.Google 日本語入力 / OSS Mozc は1.12.1599.102 の時点で未サポート.以下,実験したい人のための GUID 一覧.
{ name: "MS-IME Japanese (Windows 8.1)", langid: 0x0411, clsid: "03B5835F-F03C-411B-9CE2-AA23E1171E36", profile: "A76C93D9-5523-4E90-AAFA-4DB112F9AC76", }, { name: "ATOK 2013", langid: 0x0411, clsid: "E7602D3E-204C-4662-B92F-78DF0DE5752D", profile: "3C4DB511-189A-4168-B6EA-BFD0B4C85615", }, { name: "Google Japanese Input", langid: 0x0411, clsid: "D5A86FD5-5308-47EA-AD16-9C4EB160EC3C", profile "773EB24E-CA1D-4B1B-B420-FA985BB0B80D", }, { name: "OSS Mozc", langid: 0x0411, clsid: "10A67BC8-22FA-4A59-90DC-2546652C56BF", profile: "186F700C-71CF-43FE-A00E-AACB1D9E6D3D", }, { name: "Corvus-skk", langid: 0x0411, clsid: "EAEA0E29-AA1E-48ef-B2DF-46F4E24C6265", profile: "956F14B3-5310-4cef-9651-26710EB72F3A", },
まとめ
Windows 8.1 環境で ITfFnSearchCandidateProvider を利用すると,MS-IME 日本語版と ATOK 2013 を(同時に)フォールバックエンジンとして使う IME が作成可能.
速度とか所感
MS-IME Japanese は大体 10 msec 以内で返ってくるのでサジェストでも大丈夫かも.ATOK 2013 はクエリが返ってくるまで 100 msec 以上かかっていて,リアルタイムのサジェストに使うのはちょっときついかも.
サンプルコード
次のコードは,現在使用中の IME からのみ ITfFnSearchCandidateProvider を取得することで色々処理を簡略化したもの.起動後に何か入力すると,その入力を ITfFnSearchCandidateProvider.GetSearchCandidates に渡した結果が返ってくる.空行入力で終了.
ビルドには要 NuGet.Package Manager から TSF.SearchCandidateProvider を追加.
PM > Install-Package TSF.SearchCandidateProvider
using System; using System.Linq; using TSF; static class Program { static void Main(string[] args) { using (var provider = SearchCandidateProvider.FromCurrentProfile().Result) { if (provider == null) { Console.WriteLine("No provider found."); return; } Console.WriteLine("{0} is found", provider.Profile.Name); while (true) { var line = Console.ReadLine(); if (string.IsNullOrEmpty(line)) { return; } var result = provider.GetSearchCandidates(line).Result; Console.WriteLine("Elapsed time: {0} msec", result.Elaplsed.TotalMilliseconds); result.Candidates.ToList().ForEach(s => Console.WriteLine(" " + s)); Console.WriteLine(); } } } }
ビルドするのは面倒なのでビルド済みファイルが欲しいという人はこちら.
http://d.hatena.ne.jp/NyaRuRu/files/SearchCandidateProviderSample.zip
TSF.SearchCandidateProvider のコードが見たい人はこちらから.
NyaRuRu/TSF-SearchCandidateProvider · GitHub
類似研究
アレ用の何か
ITfFnReconversion を使う例.
HTML5 Forms の type 指定がデスクトップ IMEに影響するという話
最近やっていた仕事について,一通りリリースが終わって誰でも試せる段階になったので書いてみる.Web アプリ開発者の人や,IME 作成者の人には影響があるかも知れない.ただし Windows デスクトップを相手にしていなければ,ここで読むのをやめてもなんら問題はない.
最近 Chromium と Firefox にパッチを書いて,HTML5 Forms の type 指定が InputScope として TSF ベースの IME (いわゆる Text Input Processors; TIP) やソフトウェアキーボードに通知されるようにした.これは,基本的に Windows 8 上での Internet Explorer 10 の動作に合わせたものである.具体的には,以下の環境で,各種ブラウザが InputScope をサポートするようになった.
- Microsoft Internet Explorer 10以降 (ただし Windows 8以降)
- Google Chrome 26以降 (ただし Windows Vista以降)
- Mozilla Firefox 23以降 (ただし Windows Vista以降)
なぜこれが問題になるのか.それは,一部の InputScope が指定されたとき,(Windows Vista 以降の) MS-IME は自動的に自分自身をオフにするからだ.
モダンなブラウザの実装では,HTML5 Forms input 要素の type 属性に,number, email, tel, time (Firefox 23+ の場合のみ), url のいずれかを指定したときこの「一部の InputScope」に該当する.結果として,対応する InputScope を受け取った MS-IME は自分自身のモードをオフに設定する.
ポイントは,これが IME 自身の判断によって行われるモード変更ということだ.この挙動についてブラウザベンダーを責めるのは難しい.ブラウザは単に対応する InputScope を IME に伝えているだけである.この点で,非標準の CSS に存在する ime-mode とは大きく異なる (ただし,type = password だけは以前からブラウザ自身が IME をオフにしている).
影響を受けないのは,
- TSF 非対応の IME を使っている場合
- InputScope を無視する IME を使っている場合 (たとえば ATOK 2013 とそれ以前)
- Windows XP で上記ブラウザを使っている場合
である.なお,各 InputScope に対する挙動は各 IME にゆだねられているため,今後のアップデートで振る舞いが変化する可能性もある.
まとめ
InputScope に対応したデスクトップブラウザ
- Microsoft Internet Explorer 10以降 (ただし Windows 8以降)
- Google Chrome 26以降 (ただし Windows Vista以降)
- Mozilla Firefox 23以降 (ただし Windows Vista以降)
InputScope に対応した IME
- Microsoft IME (Windows Vista以降)
- Mozc / Google 日本語入力 1.11.x 以降 (TSF モードのみ)
HTML5 Forms の input 要素の type
- number
- tel
- time (Firefox 23+ の場合のみ)
- url
の組み合わせで,(結果として) IME がオフになる.これは IME が自主的に行っているもので,ブラウザ側から IME のオフを設定しているわけではない.この動作に関して意見がある場合,基本的には IME ベンダーへどうぞということになる.
謝辞
Mozilla Firefox への InputScope 対応パッチについて,Mozilla Japan の中野さんにレビュー等たいへんお世話になりました.この場をお借りしてお礼申し上げます.
余談 0
各ブラウザでの Forms の type と InputScope の対応については Mozc のデザインドキュメントでまとめておいた.詳細についてはそちらを参考にしてほしい.
https://code.google.com/p/mozc/wiki/InputScope#Scope
余談 1
Windows 8 の Immersive モードで,MS-IME 2012 は入力モードをカーソル周辺に表示するようになった.今後,自動モード変更が受け入れられていくためには,このようなモード表示は必須と考えられる.
余談 2
InputScope に応じて,IME は変換に関する挙動を最適化することができる.たとえば,InputScope が「サーチ」のときに名詞中心のサジェストを行う,といった最適化が考えられる.実際すでに MS-IME 2012 は InputScope が「サーチ」のときに,挙動を変えている.
余談 3
現在 W3C で (主にデスクトップ向けの) IME API が議論されている.その流れの中で Microsoft から inputmode という追加の属性が提案されている.
https://dvcs.w3.org/hg/ime-api/raw-file/tip/proposals/IMEProposal.html#inputmode-attribute
この属性を使うと,ひらがなモードやカタカナモードといった,より日本人になじみが深い入力モードを指定できるようになる.InputScope にはこういったモードが既に存在するため,将来的には「半角カタカナモード」が期待される入力フィールド,といったものが HTML5 で実現可能になる可能性がある.興味がある人が議論に参加して欲しい.
余談 4
Tablet PC の時代に InputScope が設計され,10 年以上たってようやく HTML と InputScope が結びついたわけであるが,ブラウザでの InputScope への取り組み自体は以前から存在する.
たとえば Google Summer of Code 2008 では,Mozilla に対して -moz-input-scope という拡張が試みられた.
https://wiki.mozilla.org/Community:SummerOfCode08:TSF
余談 5
Input 要素の type 指定だが,実際のところモバイル用途の方が需要は高い.理由として,ソフトウェアキーボードのレイアウトが Input 要素の typeによって変化すると便利であること,CJK以外の国でもソフトウェアキーボードが使用されること,が挙げられる.