Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

Page 1/2: 1 2

テキストリンクのJetpack版を作ってみた - Nov 06, 2009

いわゆる軽量アドオンであるところのJetpackについて今度の日曜のFirefox Developers ConferenceでAza氏とトークショーじゃなかったトークセッションを行うにあたって、「全くJetpackを触らないまま行くのはさすがに失礼すぎるだろ常識的に考えて」と思ったので、テキストリンクをJetpack featureとして移植してみた

以下、詰まった点。

  • Firebug使ってないからデバッグが面倒だった。
  • クリックされた箇所のURIっぽい文字列、のRangeを取得するにあたり、nsIFind(などのXPCOMコンポーネント)の支援を受けられないので、JavaScriptとDOM Rangeだけで強引に解決するのに手間取った。
  • XPCNativeWrapper同士を==で比較すると、ラップされてるノードが同じノードでもfalseになる。===!==で比較すればちゃんと意図通りに判定される。これは盲点だった。(普通にアドオンを作る時だと==で期待通りに判定されるので)今Jetpack 0.6で試したら問題なく動いた。アルェー?
  • APIリファレンスが貧弱で、何ができるのかまるで分からない。

やっつけ移植なので、URLっぽい文字列をダブルクリックしたら新しいタブを開く、という機能しかないです。そのくせ25KBもありやがる。

スクリプトの中身はぶっちゃけ普通のテキストリンクのコードのコピペです。というか、Jetpackで動かないであろう部分を削っていって残ったのがコレなんで。最後の方にちょこっとだけ、JetpackのAPIを使ってページの読み込み完了を監視する処理が入ってて、そこが本題です。

いいな、と思った点。

  • これは有り物の移植だからあんまり参考にならないけど、ゼロからスクラッチする場合を考えると、アドオンの時に比べて事前の準備が要らないので、確かに楽ではあるだろうなあ。
  • about:jetpackからスクリプトの管理を行えるんだけど、削除・再インストール・リフレッシュ(スクリプトを配布元から再取得する)まで行える。開発中は、仮登録→テスト→編集→リフレッシュ→テスト→... というサイクルになる。
    • 一旦アンインストールした物も、about:jetpack内にリストが残る。「消したけど、やっぱり使いたい」という風な心変わりがあっても大丈夫。
  • スクリプトの登録時に、自動更新のためのチェックボックスが表示される。多分自動アップデートできるということなんだろうけど、この機能はまだ試してない。(でも電子署名とか何も無いし、第三者攻撃に対する安全はどうやって確保するんだ?)
  • Firefoxの再起動無しで入れたり外したりできるのは楽でよい。気軽に試せる。

テキストリンクとpopInとjQuery - Mar 31, 2009

テキストリンクpopInの競合、について調べてる。

popInが入っているとテキストリンクが動かない、ことの理由はどうも以下の2点によるみたい。

  • popInがdblclickイベントをstopPropagation()しているため、テキストリンクにイベントが渡されなくなっている。
  • popInがポップアップアイコンの挿入位置を決定するために(?)、選択位置のテキストノードを動的に分割しており、仮にstopPropagation()されない状態にしてテキストリンク側でイベントを拾って処理を行おうとしても、イベント発生時とテキストリンクが処理を行う時とでDOMツリーの構造が微妙に変わっていて、正常に動かない。

何か有効な対策が無いか考えてる。

ところでpopInは内部的にjQueryを使ってるようなんだけど、その旨の表記を僕には見つけられなかった。jQueryはMITライセンスとGPLのデュアルライセンスで、MITを選択した場合でもThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.(著作権表示とMITライセンスの許諾表示をソフトウェアの全コピーかもしくは重要な箇所で示す必要がある)ということなので、下手したらMITライセンスの違反ということになるような気が…… (一応フィードバックフォームから送ってはみた)

Thunderbird上でテキストリンクを使えるようにしたよ - Mar 27, 2009

テキストリンク バージョン3.1以降で、Thunderbirdでも利用できるようにした。

プレーンテキスト形式のメールでは、Thunderbird自体のURI自動認識の処理を置き換える形で動作する。 Thunderbird上での動作の様子はこんな感じ。 Thunderbird本体のURIの認識部分は結構いいかげんなので、地の文とURIが連続してるとたまに酷い事になる。テキストリンク導入後は、Thunderbird自身による抽出結果を一旦全部白紙に戻して、もう一度URIの認識を自力で行うようになる。

同じような事をするアドオンが他にもありそう(っていうかFirefoxではLinkificationがそうだ)だけど、自分では見つけられなかったので……

ところで、AMOの方にもアップロードしたんだけど、過去にFirefox専用として登録したアドオンは後からThunderbirdにも対応した後も、Firefox専用アドオンとして扱われてしまって、Thunderbird Add-onsの方からは辿る事ができないようだ。これってどうにかならんのだろうか。

テキストリンクがFirefox 3で速くなった - Mar 17, 2009

テキストリンク 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かどうか絞り込み→ページ内検索」となるように(ある程度)処理の順番を入れ換えたところ、ページによってはアホかってぐらい速くなった。なんでここに気付かなかったんだろう。マヌケすぎる。

テキストリンク 3.0.2009030901 - Mar 11, 2009

エントリ書きかけの状態でうっかりタブ閉じたか何だったかで書きかけの文がどっか行っちゃって、書くの忘れてた。

コンテキストメニューの展開が場合によってはとんでもなく遅くなる問題については、一応の解決を見たというかこれ以上は自分の頭では速くできないなあという所まで行き着いた感じ。やったことはというと、メニュー展開時には最初と最後のURI文字列だけ検出して、それ以外は実際に操作を確定するまで検索しないようにしたっていう、実に単純なアレですハイ。すぐに処理を打ち切るようになったから選択範囲の大きさはもう影響しなくて、選択範囲の始点(終点)からその中に含まれる最初(最後)のURI文字列までの間にあるURIっぽい文字列の数によって、遅くなるかどうかが決まるという感じになりました。

その関係で、メニュー項目をポイントした時に選択範囲に含まれてるURI文字列をツールチップで列挙するにあたって、ツールチップの内容をちょっとずつ更新するようにした。これにはJavaScript 1.7以降のyieldを使っていて、yieldがあったからこれができたと言っても過言ではない……と思う(Firefox 2未満を切り捨ててなかったらこの決定はできなかった)。とにかくみんなyieldをもっと活用するべきだよ! と今更ながらに推してみたりして。

細かい事だけど、「一部だけ選択されてるURI文字列」というのを考慮するにあたって、選択範囲の境界がURIに含まれうる文字である場合は、URI文字列らしき文字が出現し続ける間Rangeを前後に拡張する、という風に考え方を変えてみた。今までみたいに固定の文字数で前後にRangeを拡張するのと違って、ある意味では無駄なくURIを検出できるようになったんじゃなかろうか。オーバーヘッドの大きさで相殺されちゃってる気もするけど。

某スレで僕がtextLink.uc.jsの普及を阻害している!これは陰謀だ!的な書き込みがあって吹いた。どっからそんな発想が出てくんだ。……と思ったけど、よく考えてみたら確かに前々からuserChrome.jsスクリプトにはどちらかというと否定的というか批判的な発言をしてきてるから、そういうことをやりかねないと思われるのも無理はないのか。(ちなみに、改めて言っとくと、本来userChrome.jsを使うのに相応しくない知識レベルの人がホイホイ使ってドツボに嵌る事とか、自動アップデートのできないスクリプトをそういう人のために作ったり配ったりする事とかに対して僕は否定的なのであって、全部織り込み済みで使う人や、技術者レベルの人向けにしれっと公開する事とかについては、僕がとやかく言う筋合いではないと思ってますよ。)

で、そういえばちゃんと中を見てなかったなと思ってtextLink.uc.jsを見てみたんだけど、networl.enableIDNがtrueだったらフツーに全角英数字で書かれたURIを読み込めるってマジすか! ってか試したら確かにいけてビビった。これって国際化ドメインの仕様? 無い知恵絞って一生懸命変換ルーチン書いたのは全くの無駄だったのか……今更だけど激しい徒労感に襲われました。あと、もしかしたら前にも書いたかもしれんけど、nsIFindを使わないというアプローチに自分は気付いてなかったので、こういうやり方があったのか……と唸ってしまった。まぁ、選択範囲の複数のURI文字列を収集するという風な事をやろうとするとこのままではうまく行かなさそうなので、今の方法を全面的に捨てた方がいいとまでは言えないみたいなんだけど。

テキストリンクの件についてVenkmanでのプロファイリングを使いながら改善を試みてる - Mar 02, 2009

ページ全体を選択したりしてるとコンテキストメニューの展開が遅くなる件について、処理を色々スキップするようにして、だいぶ速くなった。

やってることというのは、メニューを表示する時に毎回選択範囲の中のURIを全部検出するんじゃなく、選択範囲の中で最初のURIっぽい文字列と最後のURIっぽい文字列だけ検出するようにするという変更。ツールチップで全部のURIを表示する機能はなくさざるを得ない、あるいはプログレッシブ表示みたいな感じになると思う。

で、テスト用に使ってるページでは、最初のURIの検出に約300ミリ秒、最後のURIの検出に500ミリ秒程かかってる。合わせて大体1秒近いので、まだ結構重たい。Venkmanでプロファイルを取って見てみた感じでは、1つ1つの処理は20ミリ秒とかそのくらいなんだけど、それが何十と重なってトータルでこの重さになってる。

「URIっぽいんじゃね?」と思われるものの実はURIではない、という文字列(例えばHH:MM:SS形式で示された時刻やid:XXXXなど)の数が多いとこうなってしまう。URIっぽい文字列の検出条件を厳しくすれば回避できる(例えばXXX://で始まってない物を除外するようにすれば先の例はすべてスキップできる)けど、それはちょっとやりたくない……

テキストリンク 3.0.2009022402 - Feb 24, 2009

逆に考えるんだ。自動テストのおかげでリグレッションがこのレベルにおさまってると考えるんだ。

いや実際これがなかったらほんとに日に5回6回はアップデートすることになってたかもしれんですよ。いつかの頃みたいに。

コンテキストメニューやダブルクリックがめちゃめちゃ重くなることがあったのは、呆れる位しょうもないミスのせい。「クリック位置の前後のテキストからURIっぽい文字列を探す」時に、部分選択されたURIの全体を取得するために、一定の文字数に達するまで前後にRangeを広げるようになってるんだけど、この時にループを回す方向を逆にしてしまってて、一番近いノードじゃなくて一番遠いノードから数えてた。そりゃ遅くもなるって。ログによると18日の変更によるリグレッションだった。

改善されたとはいっても原理的に若干のもたつきは避けられない(特にページ全選択した状態でメニュー開いたりしたらやっぱり死ぬ程時間かかる)んだけど、まあ、ページの中をうっかりクリックする度に数秒間固まるのに比べればまだマシってことで……

Venkmanのプロファイラの使い方がやっと分かったんで、パフォーマンスの改善にも取り組みたいところです。

テキストリンク 3.0.2009021901とUxU 0.5.4 - Feb 19, 2009

ロケール更新ついでに。

直した問題は、「www.」で始まるドメイン名をダブルクリックした時の補完結果が「http:\/\/www.」になってしまうせいで読み込みに失敗するというもの。これはデフォルト設定として指定していた補完ルールのミスで、変更したのも設定ファイルだけ。デフォルト設定から変更して使ってる人は、「http:\/\」となっている所を「http://」に書き換えると、問題が直ります。

で、何故この問題を見落としてしまっていたのか、なんだけれども。

この設定が影響する処理については、既にUxU用のテストを作成してあって、自動テストを走らせた時にはこの問題は発生していなかった。テストの内容自体には問題はなくて、問題はUxUの方にあった。

テキストリンク用のテストでは、UxU 0.5.3で追加した新しいヘルパーメソッドのutils.loadPrefs()を使っていて、defaults以下にある設定ファイルを読み込んだ上でテストを行っていた。調べてみたら、これがまずかった。

この設定ファイルは元々はcontent以下に置いてあった物で、旧バージョンでは「ファイルの内容を文字列として読み込んだ後に評価して……」てな事を全部自前でやってたんだけど、Firefox 2未満のサポート打ち切りに際して、defaultsフォルダ以下にファイルを置いて読み込み処理はFirefox自身に任せるようにしたという経緯がある。

アドオンの設定ファイルはJavaScriptの関数呼び出しの形で設定が保存されている。なので旧バージョンでは、ファイルの内容を文字列として読み込んだ後、eval()でJavaScriptとして評価して設定内容を読み込んでいた。文字列の設定値として「http:\/\/」と書かれた箇所は、無意味なエスケープになるので、この時自動的に「http://」と解釈される。なので、冒頭に書いたような問題は今まで起こっていなかった。

defaults以下に置かれたファイルをFirefox自身が読み込む時も同じような感じなのだろう、と思いこんでたんだけど、よく調べてみたらそうじゃなかった。defaults以下に置かれた設定ファイルはlibprefモジュールのprefreadという、JavaScriptパーサではない独自のパーサによって解釈されていて、よくよく見てみると、\"\'\\r\n\xXX(16進数表記でのエスケープ)、\uXXXX(Unicodeエスケープ)以外のエスケープはエスケープ文字を含んだ文字列として取得されるという事が判明した。例えば\tはタブ文字ではなく"\t"になるし、\/"\/"になる。これは予想外だった……

で、このあたりの挙動を再現するコードをゼロから書こうとしたら死ねると思ったので、結局、prefreadをまるごとJavaScriptに移植する事にした。といってもJavaScriptの文法はCに近い(らしい)ので、コピペして少し書き換えたという感じ。

UxU自体のライセンスはGPLなんだけど、ソースコードとして入手する限り、このファイルのライセンスは元バージョンと同じMPL/GPL/LGPLとして使えるはずなので、まぁ、そんなに使い出はないと思うけど使いたい人がいたらどーぞ。

テキストリンク 3.0.2009021801 - Feb 18, 2009

直った直った書いてたけど見落としがありましたごめんなさい。

コンテキストメニューを開くと固まる、という極端なケースの事例としてGMailでの現象を見て、他の所で起こってるらしいコンテキストメニューがらみの問題もこれ(スタイルシートに対してマッチングを行って激遅になってる)に違いない!と思い込んでしまってたんだけども、それ以外に、テキストノードが細かく分割されてる場面でも超スローになってしまうことがあることに、今朝やっと気付きました。

修正箇所を見ると分かるけど、何でか手抜きでXPath式の評価をループごとに毎回行うように書いてたせいで、表みたいにテキストが細かく分割されてる場面でXPath式の評価が無駄に何度も行われてしまい、それで時間を食ってた。式の評価を最初の1回だけにしたら、場合によっては100倍くらい速くなった。正直、document.evaluate()の実行コストを甘く見てた。

実に恥ずかしいミスですね。

テキストリンクをテキスト入力欄の中でも使えるようにしてみた - Feb 16, 2009

テキストリンク 3.0.2009021601で、inputやtextareaの中のURI文字列も処理できるようにしてみた。といっても、テキスト入力中にダブルクリックするだけで開かれるとかそんなのはウザすぎるので、あくまでURI文字列選択中にコンテキストメニューを開いた時だけの機能だけど。ブログとか日記とか書いてる途中でふと確認したくなった時、なんかに使えるんじゃないかと思う。

DOM2 RangeのcompareBoundaryPointsをnsIDOMNSEditableElementの編集領域の中のRange同士の間で使うと、何故だかNS_ERROR_DOM_WRONG_DOCUMENT_ERR例外が発生してしまったので、仕方ないからnsIDOMNSRangeのcomparePointで解決するようにしてみた。独自仕様な上にどうにも動作が怪しい感じなので、できればcompareBoundaryPointsだけで済ませたかったんだけど、なかなかうまくいかない。

GMailでコンテキストメニューが固まる問題は、本文だけじゃなくヘッダ領域の中のstyle要素の内容までURI文字列の検索対象にしてしまってたせいだった(全面リライトにあたって、DOM3 XPathで代用できそうな所を片っ端からDOM3 XPathに置き換えたんだけど、XPath式の評価結果が書き直し前と違ってたことに気付いてなかった)。スタイル宣言が全部URI文字列らしき物として検出されてしまって、それで無限ではないんだけど数千回のループが発生して、途中で処理を打ち切られてたという感じ。XPath式を工夫してbodyの中だけを検索対象にするようにしたら直った。

この辺の修正に際してもまたテストを書き足した。こんな感じでテストが充実してくれば、多分、将来的にはregressionは減る方向に向かうと思うんだけど……

Page 1/2: 1 2

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき