Mar 17, 2009

テキストリンクがFirefox 3で速くなった

テキストリンク 3.0.2009031701で、Firefox 3上では部分的に処理が高速になった。具体的には、Rangeを文字列にする処理がそう。Venkmanでプロファイルを取ってみたらここが滅茶苦茶頻繁に呼ばれてて、ここが遅いと全部が遅くなるという感じで他の部分に影響してたんだけど、nsIDocumentEncoderで代用できる事にやっと気がついた。

nsIDocumentEncoderについては、以前に選択範囲からHTMLのソースを取得する方法を調べてて行き着いたnsISelectionPrivateの実装を見て、存在は知ってた。これを使うことができれば、HTMLを選択してコピー&テキストエディタにペーストした時のように、BR要素の位置で改行されたりP要素の位置で空行が入ったりSCRIPT要素の内容を除外したりといった、よくある処理が行われた後の整形済みテキストを取得できるんじゃないか、と思って色々試してみたんだけど、その時は、JavaScriptからコンポーネントの機能にアクセスできないようだったので結局諦めてた。でも今日になってふと試してみたら、いつの間にかJavaScriptからもCi.nsIDocumentEncoderが見えるようになってて、これ幸いと使ってみたところかなり期待通りの結果が得られたので、そのまま採用した。

使い方はこんな感じ。

// インスタンスを取得
var encoder = Cc['@mozilla.org/layout/documentEncoder;1?type=text/plain']
               .createInstance(Ci.nsIDocumentEncoder);
// 変換対象のドキュメント、変換先の形式、変換ロジックのフラグを渡して初期化
encoder.init(content.document,
             'text/plain',
             encoder.OutputBodyOnly | encoder.OutputLFLineBreak);
// DOMRangeをセットして……
encoder.setRange(range);
// 文字列に変換する
var result = encoder.encodeToString();

前述した通り、HTML的に非表示になる事が期待されてる要素が除外されたり、画面上の改行位置で文字列の方にも改行文字が入ってくれたりと、単純にDOMRangeのtoString()で文字列化するだけだと問題になる点がこれで一挙に解決される。

JavaScriptから使えるのはGecko 1.9以降のみのようなので、Firefoxの場合は3以降に限定ということになる。Firefoxは2のサポートが切れてるからまあいいんだけど、ThunderbirdはまだGecko 1.8系のままなので、恩恵にあずかれないのが残念だ。

nsIDocumentEncoderを使うようにした副次的なメリットとして、<td>URI1</td><td>URI2</td>のようにセルの間にホワイトスペース文字が無いテーブルでも、nsIDocumentEncoderで文字列化する時はセルの間にタブ文字が入ってくれるため、それぞれ別々のURI文字列として検出できるようになった(最初の段階の「Rangeを文字列化してURIっぽい文字列を正規表現で探す」処理において、それぞれのセルに書かれたURI文字列がちゃんと別々の物としてヒットするようになった)。

追記。3.0.2009031801でさらに高速化した。高速化っていうか、なんていうか……今まで「URIっぽい文字列をマッチング→マッチングしたURIっぽい文字列をページ内検索→ちゃんとしたURIかどうか絞り込み」とやってて、ページ内検索が大量に発生すれば発生する程スピードが遅くなってたんだけど、これを「URIっぽい文字列をマッチング→ちゃんとしたURIかどうか絞り込み→ページ内検索」となるように(ある程度)処理の順番を入れ換えたところ、ページによってはアホかってぐらい速くなった。なんでここに気付かなかったんだろう。マヌケすぎる。

エントリを編集します。

wikieditish message: Ready to edit this entry.











拡張機能