この日記はMozillaのプロダクトへの貢献者としての私の成果を中心に、気になったバグやWeb界隈の話題について書いていますが、 断り書きがある場合を除き、いかなる団体のオフィシャルな見解ではありません。あくまでも個人的なものです。 Mozilla Foundation、Mozilla Corporation、及び関連企業の公式情報ではないことに注意してください。

現在、XHTML 1.0 (もどき)から、HTML5なコンテンツに修正中です。古い日記は修正が完了していませんので表示が崩れます。 順次、修正していく予定ですのでしばらくお待ちください。

もずはっく日記(2015年12月)

2015年12月31日

Bug-org 1234422 [TSF] Google Japanese Input sometimes fails to update its candidate window at converting the composition string
初回投稿日時: 2015年12月31日00時40分57秒
カテゴリ: IME Mozilla Core Mozilla44 Mozilla45 Mozilla46 TSF Windows バグ修正
SNS: (list)

Windows 8以降ではGoogle日本語入力はTSFTIPとしてインストールされますが、Firefox 43以降のTSFモードでは変換候補ウインドウが出ている状態で変換キー(スペースキー)を押しても未確定文字列は更新されても、候補ウインドウ内の表示が更新されなかったり、候補ウインドウ自体が表示されないことがあるというバグです。

このバグは、Bug-org 1204519の修正で削除した、Google日本語入力向けのハックが別の未発見だった問題を洗い出してしまったというものでした。いわゆる、単純なregressionではありません。

TSFにはドキュメントロックという概念があります。TIPが未確定文字列を挿入・変更する際には、ドキュメントをロックし、ロック中はアプリ側でそのドキュメントの内容が変更されることは無いことになっています。しかし、ブラウザで単純にTSFを実装してしまうと、ドキュメントのロック中にcompositionupdateイベント等を発火することになり、Javascriptによって何らかの変更が行われる可能性があります。Geckoはこれを防ぐために、ドキュメントがロックされている間は発火すべきイベントをキューに保存し、アンロック時にまとめて発火することで対応しています。

しかし、この挙動を実現するためには、ドキュメントロック中に来る、未確定文字列の矩形の問い合わせに対して即、回答することはできません。未確定文字列をイベントを使ってエディタに送信するのがドキュメントがアンロックされてからだからです。TSFではこれに対応するために、TS_E_NOLAYOUTというエラーコードが用意されていて、これを返した場合、TIPは、レイアウトの計算が終了後に必ず呼び出さなくてはいけないITextStoreACPSink::OnLayoutChange()の呼び出しを待ち、再度、レイアウト情報の取得をリトライできるようになっています。

しかし、問題はこのITextStoreACPSink::OnLayoutChange()の呼び出しタイミングです。これまでGeckoは、ロックされた状態の最後にこれを呼び出していました。しかし、よくよくログを調べてみると、TSFからOnLayoutChange()の呼び出し中にドキュメントのロックのリクエストがネストされて呼び出されていました。しかし、もちろん、そのドキュメントロックには必ず失敗します。

最初はこれが原因かと思い、ドキュメントがアンロックされた直後にOnLayoutChange()を呼び出すパッチを書いてみました。しかし、TSFからドキュメントロックの要求が来るものの、そのロック中には何もしなかったり、選択位置だけを確認して終了し、肝心のTIPには通知が行っていないようでした。

そこで苦肉の策として、PostMessage()を利用して、ITextStoreACP::RequestLock()が完全に終了後、次のイベントループ処理でOnLayoutChange()を呼び出してみると、ようやくGoogle日本語入力がレイアウトの再取得を行う様になりました。ひとまず、この修正がNightlyには既に入っています。

ただし、PostMessage()を利用したハックでは、WM_KEYDOWNメッセージ等の入力メッセージが優先されてしまい、期待通りに機能しない可能性があります。そこで、WM_KEYDOWNをTSFに送信した最中にこのハックが動作した場合には、その直後に(次のメッセージを処理する前に)、このハックを走らせるべきかを検証中です。それが終わり次第、BetaとAuroraでも修正の予定です。

ちなみにMS-IMEやATOKで同様の問題が発生しないのは、TSFTextStoreのログで確認する限り、未確定文字列の編集のためのドキュメントロック中にはITextStoreACP::GetTextExt()を候補ウインドウのためには呼び出さず、ITextStoreACP::RequestLock()の後に能動的にITextStoreACP::GetTextExt()のためのロックを再度要求してきて処理しているためです。

個人的にはGoogle日本語入力もこのような動作に修正した方がアプリ側の微妙な挙動の変化で「相性問題」が出なくて良いのではないかと思います(もっとも、MSDNのTSFのドキュメントの内容からすると、TSFがOnLayoutChange()の呼び出しを確実にTIPに後から伝えるのがあるべき姿だとは思うのですが……)。

関連するかもしれないエントリ

bug-org 1234422を含むエントリ