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

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

もずはっく日記(2014年7月)

2014年7月31日

Bug-org 496360 [TSF] Severe performance problems pasting into contenteditable editor or designMode editor when TSF is enabled
初回投稿日時: 2014年07月31日23時29分47秒
カテゴリ: Android Fennec Mozilla Core Mozilla34 Thunderbird TSF Windows バグ修正
SNS: (list)

TSFを有効にしていると、膨大な行数の貼り付けのパフォーマンスが異様に悪くなる、というバグです。バグIDを見れば分かるように、かなり長い間修正できなかったバグですが、ここ最近のIMEContentObserver周りや、様々な他の修正により、この修正がようやく可能になりましたが、それでも強引な最適化を行って解決しています。

TSFは、フォーカスのあるエディタの内容が変更される度に、その旨をTSFに通知しないといけないのですが、その際に変更された範囲を示す、最初のオフセット、編集前の選択されていた文字列の最後のオフセット、編集後のオフセットを渡さなければいけませんが、これの計算が非常にコスト高だったことがこのバグの原因です。

もともとは、<textarea>要素でも再現していたのですが、プレーンテキストエディタは途中から、内部処理で、テキストノードと<br>要素ではなく、white-space: pre;なテキストノードで表現されるようになったため、このバグは、contenteditableや、designModeによって生成されたHTMLエディタでのみ発生するようになっていました。ですので、Thunderbirdや、Gmail等はこのバグの影響が大きかったはずです。

テキストが追加された場合、IMEContentObserverのmutation observerに、先頭のノードの追加から順次、通知されます。この際に、毎回、テキストの挿入位置、追加されたテキストの長さを計算し、widgetへ通知していました。

ちなみに、テストでは見つけにくいのですが、削除の場合にも同様の問題があり、IMEContentObserverのmutation observerに、先頭のノードの削除から順次、通知されます。この際に、毎回、削除されるテキストの先頭のオフセットと、削除されたテキストの長さを計算し、widgetへ通知していました。

これらを解決するために、まずは、複数の変更をひとつのテキスト変更と見なして通知できるように、widgetへ通知するオフセットをマージ可能にし、さらに、エディタ上での編集が終了するまで通知を行わないようにしました。これにより、一回の編集につき、一回のテキスト変更、選択範囲変更、レイアウト変更通知がwidgetへ送信されないようになっています。

しかし、この修正では残念ながら、手元の環境ではパフォーマンスは上がりませんでしたが、IME (TIP)の実装・仕様によっては、この修正だけでも劇的にパフォーマンスが上がっていると思います。

次に、連続したテキストの追加時と、連続したテキストの削除時に、何度も似たような、もしくは同じオフセットを計算している部分を改善することにしました。追加時は、追加されたノードの位置と、その終端のオフセットを記憶しておき、次の追加時に同じ範囲を計算する場合にはキャッシュしたオフセット値を使うようにしました。削除時は、削除されるノードの位置とその先頭までのオフセット値を記憶しておき、同じ位置が次に削除される場合にはキャッシュしたオフセットを使うようにしました。

この、ノード位置もキャッシュしておくことで、MutationObserverをJavascriptで利用して複雑な編集作業をエディタがDOMツリーに変更してしまい、キャッシュした値が破損した可能性がある場合には破棄して再計算するようにして、安全策を講じています。

これらの修正により、ひとまず、見つかっている編集時の極端なパフォーマンス低下は解決しました。手元での検証結果では、TSFモードと、IMMモードで同じようなスコアが出ました。理論上はTSFモードの方が、どれだけ最適化していても若干遅いはずではありますが。

また、コードを調べたところ、テキストの変更は、Windows版のTSFモードの他に、Android版でも監視対象となっていました。このため、Androidでもこのバグは発生していたようですが、同様に修正されています。

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

bug-org 496360を含むエントリ