Bug-org 790516 [TSF] Should dispatch DOM events when document is unlocked
初回投稿日時: 2013年03月27日19時21分07秒
カテゴリ: Mozilla Core Mozilla22 TSF Windows バグ修正
SNS:
Tweet (list)
TSFのドキュメントロックが、仕様通りに動かないのでデザインを大幅に見直しました。
TSFは、TIP (IME)がアプリにアクセスを行う際に、ITextStoreACP::RequestLock()
を呼び出し、アプリ自身や、他の何らかのテキストサービスが、そのコンテンツを変更できないようにロックを行ってから処理を開始します。
ITextStoreACP
の実装側(GeckoではnsTextStore
)は、ロックを受け入れることができるなら、ITextStoreACP::RequestLock()
内でITextStoreACPSink::OnLockGranted()
を呼び出します。TIPは、この、OnLockGranted()
が呼び出されている間が、ロックが実際に実行されている、という状況になりますので、アプリ側から見ると、OnLockGranted()
を呼び出している最中に、文字列を変更するメソッドが呼ばれたり、キャレット位置を変更するメソッドが呼ばれたり、コンテンツの内容を調べるメソッドが呼ばれたり、コンテンツ中の特定の文字の画面座標を調べるメソッドが呼ばれたりします。
従来のnsTextStore
は、各種メソッドがTSFから呼び出された時に、逐一、DOMイベントを発行して、エディタの内容に反映し、最新のコンテンツの情報を調べて返す、という実装でした。つまり、OnLockGranted()
の最中に、DOMイベントが発生するため、そのイベントハンドラから、エディタの内容や、フォーカスの移動といった、何らかの変更が可能で、実際にはロックができていない状態でした。このため、実際にそのような状況が発生すると、TIPが混乱してしまうということがありました。
今回の修正で、nsTextStore
は以下のように修正されました。
まず、未確定文字列の変更等、ドキュメントの変更に関するアクションが呼ばれた場合、アクションという形で記録だけを行い、OnLockGranted()
から処理が戻ってきてから、ため込んだアクションから、DOMイベントを一気に発行するようになりました。
そして、最新のコンテンツの情報は、アクションがペンディング状態になっている時には取得できませんので、ロック後、最初に、最新のコンテンツ情報や、選択位置の情報をキャッシュし、各アクションが記録される際に、このキャッシュしたコンテンツのみを更新して、TSFにはこの情報をもとに応答する、という形をとっています。
また、コンテンツの任意の文字の位置情報だけはどうしようもありませんので、レイアウトがまだ完了していない、というエラーを発行するようにし、記録されたアクションを全て実行した直後に、TSFに対して、レイアウトの計算が終了した旨を伝えるようにしています。
今回の修正により、まず、コンテンツの情報は、一回のロックにつき、一回しか取得しにいかなくなりましたので、CPUパワーの必要な、クエリイベントを利用を大幅に削減しました。これにより、軽快に動作するようになっています。
また、選択位置の変更と、文字列の変更の合間でクエリが行われた場合に対応するための中途半端な、コンテンツ情報のキャッシュコードをごっそりと削除することができました。
そして余分なtext
イベントを発行して、未確定文字列がちらついてしまうのを阻止するために、最後に発行したtext
イベントを記録し、比較するコードの削除もできました。
これにより、かなり、壊れにくい、安定した、読みやすいコードに生まれ変わったと言えます。
ただし、この修正が入った今でも、RequestLock()
中にDOMイベントが発生することになりますので、そのハンドラにより、何らかの変更が行われた場合に、TSFにそれを通知する手段がありません。これはまた、別のバグで対応予定ですが、XP側に相当量の変更が必要なので、今年中に取りかかれるかすら、見通しが立っていません。