Home > Latest topics

Latest topics 近況報告

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

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

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

Page 1/248: 1 2 3 4 5 6 7 8 9 »

XUL/Migemo 0.13.xで中身の方をだいぶ変えて(環境によっては)高速化しました - Jul 09, 2010

半分眠ったまんまで作業してたのでしょーもないregressionを仕込む→修正して公開→またregressionということを繰り返した結果、既に0.13.3になってしまったわけですが、バージョン0.13.0で結構大きくいじりました。機能的には全然変わってないですが。

  • 開発メモにちょっと書いてるけど、このバージョンからFirefox 2とThunderbird 2をサポートしなくなりました。
  • Gecko 1.8どころかGecko 1.9.0も切り捨てたという事で、Firefox 3.5より後で入った便利機能を心置きなく使えるようになったり、Firefox 2→Firefox 3の間で大きく変わったAPIの両方に対応するためのめんどくさい場合分けをゴソッと削除できたりしたので、だいぶスッキリした気がします。
    • ウィンドウごとに分ける必要がないコードでXPCOMコンポーネント化してなかった物は積極的にJavaScriptコードモジュール化しました。
    • Thunderbird専用のコードは、XPCOMコンポーネントにしてはあったものの、そんなに汎用性が無かったので、これも全部JavaScriptコードモジュール化しました。
  • 検索でヒットした箇所が多い時に、Safari風の強調表示等の機能を有効にしているとフリーズしてしまう問題について、ヒット箇所の強調表示を段階的に非同期で行うようにしてみました(0.13.4)。
  • Gecko 1.9.2以降ではnsIDOMWindowUtilsのnodesFromRect()を使うようにしたので、見えているスクロール位置から検索を始める処理が相当速くなりました。
  • Minefieldに最近入った機能のおかげで、DOM Rangeから検索用のテキストを取得する部分が爆速になりました。nodesFromRect()の効果と合わせて、Minefield 4.0b2preではページ内検索のストレスがほとんど無くなったと思います。

Minefieldで検索が速くなったのは、Bug 39098 – Elements with visibility:hidden, visibility:collapse, or display:none get copied to the clipboardがfixされたおかげです。

  • これまでXUL/Migemoのページ内検索が非常に重かったのは、Rangeを一旦文字列にして正規表現でマッチングして、その結果を使ってもう一度ページ内検索するという仕組みに理由があります。
  • この時、RangeをそのままtoString()で文字列にすると、CSSで非表示になっている要素のテキストまで一緒に取得されてしまうのですが、その後rangefindで検索する時は非表示のテキストは検索対象にならないため、場合によってはヒット箇所が飛ばされてしまったり検索が止まってしまったりという問題が起こります
  • そこで現在のXUL/Migemoでは、
    DOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIWebNavigation)
       .QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsISelectionDisplay)
       .QueryInterface(Ci.nsISelectionController)
       .checkVisibility(textNode, 0, textNode.nodeValue.length)
    というやり方で個々のテキストノードの可視・不可視の状態を判別して不可視のテキストを除外した結果を取得して、正規表現のマッチングに使うようにしていました。
  • しかしこの方法は、テキストノードの数が増えると判断の回数も同じだけ増えてしまうため、MXRのページのように内容が小さなテキストノードに分断されているページだととんでもなく処理に時間がかかってしまいます。
  • 5月末にBug 39098で入った変更によって、テキストリンクの高速化の時にも使ったnsIDocumentEncoderに、「非表示状態のテキストを結果の文字列に出力しない」というオプションが加わりました。なのでMinefield上では、この機能を使ってRangeの中の可視状態のテキストだけを一気に取得するようにしました。

Minefield 4.0b2preにXUL/Migemo 0.13.xを入れてMXRのページでページ内検索してみると、効果の程がよく分かると思います。僕は、今すぐにでもFirefox 3.6を窓から投げ捨ててしまいたくなりました。

あとはJägerMonkeyが入ってくれれば……

ところで、他のアドオンからXUL/MigemoのAPIを呼び出す時はちょっと注意が必要になってます。

  • ずっと前に「ユーザ辞書の内容がWebページのスクリプトから取れてしまうのはセキュリティ的に宜しくない」という指摘を受けたんですが、どうやってこの問題を回避すればいいものか悩んで、結局、グローバルなJavaScriptのプロパティのmigemoオブジェクトから機能を呼び出す時には常にシステム辞書の内容だけを返すように仕様を変えました。
  • ユーザ辞書に追加された単語も含めた正規表現を取得したい場合、Components.utils.import('resource://xulmigemo-modules/service.jsm')でユーティリティを読み込んでXMigemoCoreの各メソッドを呼ぶか、Cc['@piro.sakura.ne.jp/xmigemo/factory;1'].getService(Ci.xmIXMigemoFactory).getService('ja')てな感じでXPCOMコンポーネントを直接呼び出すかする必要があります。
  • XMigemoCoreでもxmIXMigemoCoreでもどっちにしても、これらが持つ機能で正規表現を生成する時は戻り値は常に文字列(正規表現のソース文字列)になるので、その都度new RegExp()してやる必要があります。
  • 辞書が絡まない機能はmigemoのメソッドを使って問題ありません。XUL/MigemoのUI周りでもそうしてます。

XUL/MigemoのMinefield対応に向けてのメモ - Jul 07, 2010

作業メモ。

  • gFindBarの遅延初期化には対応した。window.watch('gFindBarInitialized', function() { ... })で、遅延初期化のタイミングで初期化を行える。
  • XPCOMコンポーネントの登録方法の仕様変更にも対応した。これから先、できれば仕様は変わらないでいて欲しいけど……
    • classDescriptionにホワイトスペース文字が入ってると、カテゴリへの登録がうまくいかないかも。nsUpdateTimerManagerに対応するマニフェストファイルなんかを見てみた感じでは、実装のクラス名をそのままclassDescriptionにするといいのだろうか?
    • nsSidebar.jsに対応するマニフェストファイルを見て分かったけど、今までカテゴリマネージャに登録する必要があったケースは全部マニフェストファイルでやるという事のようだ。マニフェストファイルの方に書いておかないと、ちゃんと認識されなかった。
  • これまで、Firefox 2からFirefox 3.6の間でメソッド名やプロパティ名が変わった物はFirefox 2に合わせるようにしてたけど、今後はMinefield 4.0b2pre基準にする事にする。今の所はほとんどFirefox 3.6と同じだけど。
  • Firefox 2からFirefox 3.6までの間それぞれのためのコード、特にFirefox 2用とそれ以降用とでコードを書き分けてた部分が多かったので、思い切ってFirefox 2用のコードは全廃する事にした。
  • rangefindを使う時に注意がいる
  • 他アドオンとの連携にも注意がいる

しないといけないなーと思ってる課題。

  • Minefieldに既に入ってる、スマートロケーションバーの候補として出てきたplaceが既にタブで開かれている場合にそのタブに切り替える機能への対応。
  • Thunderbird 3。とりあえずフォルダペイン内での絞り込みはできるようにしとかないと……とは思ってる。

スマートロケーションバー関係を調べて分かった事。

  • Minefieldは、タブで閲覧中のページをtabbrowserが持ってるプログレスリスナで常時監視してて、タブで閲覧中のplaceの一覧をmoz_openpages_tempという名前のテーブルに保存している。
    • このテーブルはplace_idopen_countという2つのカラムを持ち、ページの遷移に応じて内容が随時更新される。
  • 検索でヒットしたplaceについて、このmoz_openpages_tempopen_countが0より大きい物は、オートコンプリートの候補として返される時にURIの前にmoz-action:switchtab,という文字列が付与され、lichlistitemのtype属性用の値にはactionという値が設定される。
  • スマートロケーションバーのオートコンプリートの実装はいつの間にかJavaScriptになっていた。Cより読み慣れてるから助かる。
  • この機能が有効になるのは、オートコンプリート用のtextboxのautocompletesearchparam属性の値にenable-actionsという文字列が含まれている時だけのようだ。
    • 機能が無効になっている時は、単に上記の「URIの前にmoz-action:switchtab,という文字列が付与され~」という処理がスキップされる。
    • この事から分かる通り、moz_openpages_tempopen_countはオートコンプリートの候補の並び順には影響しない。あくまでfrequencyベースで検索していて、ヒットした候補の中にたまたま現在タブで開かれているplaceが含まれていた場合にだけ、この機能が発動するという仕様のようだ。
  • ロケーションバーへの入力時に「タブで開いてる奴だけ表示」という風に制限する時の既定のキーワードは「%」。browser.urlbar.default.behaviorで指定する時のフラグは128(1 << 7)。

nsIVariantを使ってるアドオンが終了していた、と思ったら僕の知識の方が終了していた件 - Mar 23, 2010

SCRAPBLOG : JavaScript 製 XPCOM で配列構造・列挙構造のデータをメソッドの戻り値にする

独自に開発したXPCOMコンポーネントに対して配列を渡したり、あるいは戻り値を配列で受け取ったり、ということをやる方法はいくつかある。上記エントリではコメント欄も含めると4つの方法が紹介されていて、そのうちコメント欄にある2つはJavaScriptの配列をそのまま受け渡せるという点で有用だ。特にnsIVariantインターフェースを使うやり方は、戻り値に使う時に余計な引数を定義しなくていいので、実際にそのXPCOMコンポーネントをJavaScriptから使う時にとても使い勝手がいい。

ということでXUL/Migemoでは積極的にnsIVariantを使ってたんだけど、これがMinefield(検証したバージョンは3.7a4pre)で動かなくなってた。

結論から言うと、これはnsIVariantインターフェースのIIDが6c9eb060-8c6a-11d5-90f3-0010a4e73d9aから81e4c2de-acac-4ad6-901a-b5fb1b851a0dに変更されたせいで起こっている問題で、nsIDOMRangeのIIDが変更された時に起こった問題と同様の物だ。

変更が入ったのは昨年9月で、HTML5の新しい仕様に対応するための作業の一環として、何らかの必要があってインターフェースに機能を加えると同時にIIDも変わったらしい。nsIVariantはFROZENなインターフェースじゃないから、nsIDOMRangeの時のようにIIDが元に戻されることは多分あり得ない。よって、考えられる対策は以下のいずれかということになる 。

  • APIをXPCOM経由で提供する事を諦める。Firefox 2以前、Thunderbird 2以前を切り捨てて、JavaScriptコードモジュールとして書き直す。
  • Firefox 3.6以前用とFirefox 3.7以降用とでXPIDLのコンパイル後のバイナリを分けて、Firefoxのバージョン別に2つのXPIファイルを提供するようにする。

JavaScriptコードモジュールにするデメリットは、Thunderbird 2で利用できなくなってしまう点と、APIが変わってしまう点。バイナリを分けるデメリットは、リリースの時の作業がめんどくさくなる(XPIファイルが2つになるので)という点。どっちを選んでも大変なのは変わらない……

APIが変わってしまうことは避けたかったので、結局、後者の方で対処することにした。

前から使ってるXPI生成用シェルスクリプトに起動オプションでサフィックスを指定できるようにして、

こんなショボいスクリプトを作って、前出のスクリプトと一緒に

call xpidl.bat xulrunner-sdk-1.9.2
bash makexpi.sh -n xulmigemo -v 0 -s "1.9.2"

call xpidl.bat xulrunner-sdk-central
bash makexpi.sh -n xulmigemo -v 0 -s "central"

てな感じで実行するようにして(make.bat / make.sh)、MozillaのFTPサイトからXULRunner SDKのファイル一式を入手して

  • xulmigemo
    • make.bat (make.sh)
    • xpidl.bat (xpidl.sh)
    • makexpi.sh
    • install.rdfなど
  • xulrunner-sdk-1.9.2
    • bin
      • xpidl.exe (xpidl)
    • idl
  • xulrunner-sdk-central
    • bin
      • xpidl.exe (xpidl)
    • idl

という感じにファイルを配置するようにした。

XPIを作りたい時にはXULRunner SDKが必要になってしまうけど、スクリプトいっこ走らせれば xulmigemo-mozilla-1.9.2.xpi と xulmigemo-mozilla-central.xpi という風に複数のXPIを出力できるようになったので、リリースにかかる手間は少しは軽減された……のかな……

追記。Gomitaさんのコメントを見て、IDLファイルからincludeの行を消して試してみたら、それでちゃんとコンパイルできた。なんでだ……!!!

えーと。ずっと勘違いしてたんだけど、#include "nsISupports.idl" みたいな行は、interface xmIXMigemoFileAccess : nsISupports てな感じでインターフェース定義の継承元に別のインターフェースを使う場合にだけ必要で、戻り値や引数に使う分には単に interface nsIVariant; とだけ書いておけばいいみたいですね……そうすると、コンパイル時には余計なIIDが含まれなくなって、Firefox 3.6まででも3.7以降でも問題なく使えるXPTファイルが作られるみたい。

まとめ。

  • IDLファイルの書き方を間違えておらず、最小限の記述だけにしてあれば、コンパイルしたXPTファイルはFirefox 3.6まででもFirefox 3.7以降でも使える。
    • 継承元に使うインターフェースはその内容が定義されたIDLファイルをincludeした上で interface インターフェース名; と書く。
    • そうでない物(引数や戻り値でしか使わないインターフェース)は interface インターフェース名; だけ書く。
  • Minefield 3.7におけるnsIVariantのIIDの変更の影響を受けるのは、nsIVariantを継承元としてさらに拡張したインターフェースを定義する場合だけ。

そんなわけで、xmIXMigemo.idlの頭の所はずいぶんスッキリしました。

#include "nsISupports.idl"
#include "nsIObserver.idl"

interface nsIObserver;
interface nsIFile;
interface nsIVariant;
interface nsIDOMWindow;
interface nsIDOMDocument;
interface nsIDOMRange;
interface nsIDOMElement;
interface nsIDOMNode;


/* Utilities: You can use them for your language without additional implementation. */

[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]
interface xmIXMigemoFileAccess : nsISupports
{
(以下略)

Webアプリケーションからも利用できるAPIを備えたXUL/Migemoをリリースしたよ - Oct 21, 2009

XUL/Migemo 0.12.xで、機能を他のアドオンとかから呼び出すためのAPIを刷新してみたよ。

古いAPI(はてなブックマーク拡張とかが使ってくれてるやつ)は僕自身が色々よく分からないまま作った物だったために、引数を文字列で渡さないといけないとか戻り値も正規表現オブジェクトではなく文字列だとか、色々と使い勝手が悪かったと思う。メインウィンドウ以外では呼び出す時にいちいちXPConnect使わないといかんし。

新しいAPIは、それに比べたらものっそシンプルになった。XPConnect使わなくてもmigemo.getRegExp('hoge')とか書くだけで使えるし、戻り値もすぐに使える正規表現オブジェクトが返ってくるし。互換性を保つために旧APIはそのまま残してあるので、旧APIを使ってるアドオンが動かなくなるということはないけど、今後は使うなら新APIの方を使うのがお勧めです。

で、このAPIはWebページ内のスクリプトでもCPUの使用率を取得できるようにするAPIを提供する例のアドオンの技術の応用なので、Webページ内のスクリプトからもXUL/Migemoの機能を利用できてしまいます。

ただしスクリプトの実行権限の関係で、上記のmigemo.getRegExp('hoge')のような、正規表現オブジェクトを直に受け取る機能は使えません。代わりにJavaScript/Migemo互換の、正規表現のソース文字列を返すAPI migemo.query('hoge') などを使う必要があります。

XUL/Migemo 0.12.2以降が入ってる環境でこのページを表示してれば、以下のデモを試せるはず。


  • コーヒー
  • 紅茶
  • 緑茶
  • 抹茶
  • コーラ
  • 日本酒
  • ビール

ページ内検索系のメソッドもあるんだけど、多分使いでがなさそうなので解説は用意してないです。

すでに上でもリンクしてるけど、エンジンごとページ内に埋め込めるJavaScript/Migemoという実装もあるから、XUL/Migemoを入れてるFirefoxユーザでないと使えないこのAPIってなんか意味あんの?と言われそう。深くはツッコまないでください。

以下、補足事項。

当初このエントリでは、「Webページ上のスクリプトからもmigemo.getRegExp('hoge')のようにして正規表現を取得して利用できる」という風な書き方をしてたけど、これは大間違いだった。戻り値の正規表現オブジェクトが生成された実行コンテキストがUniversalXPConnect特権のある場所なのに対して、呼び出し元は特権のない普通のWebページ上であるため、それぞれの権限が違うので本来ならその正規表現の各メソッドは実行できないのが正しい。

ただ、Gecko 1.9.1(Firefox 3.5)以前のバージョンにはバグがあって、上記のようなセキュリティのチェックが働かないために、戻り値の正規表現の各メソッドを呼べてしまう状態になっていた。

このバグはGecko 1.9.2(Firefox 3.6)以降ではすでに修正済みで、実際、Trunk等で戻り値の正規表現オブジェクトのメソッドを呼ぼうとすると、その場で処理が中断されて Error: RegExp.prototype.toString called on incompatible ChromeObjectWrapper というエラーがエラーコンソール上に出力される。

ということで、JavaScript/Migemo互換のAPIとして正規表現オブジェクトのソース文字列だけを返すような機能を0.12.2で新たに加えた。文字列や数値などのプリミティブ値に対してはセキュリティのチェックが行われないようなので、こっちはGecko 1.9.2以降でもWeb上で使える。

「英語(辞書アシスト検索)」モードは、英和辞書で検索する機能ではない - May 28, 2009

ローマ字入力で日本語ページ内の検索を可能にする「XUL/Migemo」拡張 - SourceForge.JP Magazine

さて、もう一つの検索方法である「英語(辞書アシスト検索)」であるが、これは英単語を入力するとその対訳となる日本語の単語が検索されるというモードだ。なぜか筆者の環境ではうまく機能しなかったのだが、一応使い方を説明しておく。

そんな機能実装した覚えないんですけど……

英語モードは、僕が正式にXUL/Migemoを引き継いだ後に行った大改造において、将来的に日本語だけでなく中国語や韓国語などのIMが必要な他の言語に対応できるよう、言語依存の主要モジュールを差し替え可能にした時に、日本語特有の処理(ローマ字入力を平仮名に変換するなどの処理)を含まないプレーンなモジュールの実装例として用意した物だ。

Firefox自身の通常の検索機能と比較して、このモードで具体的に起こる変化としては、「ext」まで入力した時点で「extension」「extend」等の英単語が強調表示されるようになる、という感じなんだけれども……これってぶっちゃけ無意味なんだよね。

  • 日本語では、入力した文字列(ローマ字)とページ内のヒット箇所(仮名漢字交じり)の文字列とが一致しない。「kanj」と入力した段階で登録済み単語の「漢字」にヒットしてくれれば、総キータイプ数が少なくなる。→メリットがある!
  • 英語では、入力した文字列とページ内のヒット箇所とが原則として一致する。なので、補完が無くても元々キータイプ数は最小で済む。→メリットが無い!

あとは、発音記号付きのアルファベット等を区別せずに検索できるようになるけど、それとて日本語用のエンジンに既に包含されている機能だし。

強いて言えば、日本語とかローマ字とか全然興味がないし必要も無いという英語圏のユーザの人が、Safari風の強調表示だけ利用する時に、ほとんど何も余計なことをしないから邪魔にならない……ということくらいだろうか。英語モードのメリットは。とにかく、「これこれこういう凄いことができるようになる」といった類の意義は皆無だ。そのモードを作った本人が言うんだから、間違いないよ。

予定もしくは野望もしくは妄想 - Apr 21, 2009

今の所、XUL/Migemoの辞書ファイルは全部普通のテキストファイルなんだけど、これをSQLiteデータベースに置き換えてみようかなと思ってる。メリットがあるのかどうかは分からないんだが。

現在の辞書周りは基本的にはplus7さんが作られた物を踏襲していて、起動時に全ての内容を読み込み、JavaScriptの普通の文字列としてオンメモリで保持しておくようになってる。でもこれだとFennecで動かすのって多分きついだろうなあ、とは思ってた。

どうなんだろう、SQLiteって関係ないデータはメモリに読み込まずにいてくれたりするんだろうか? Fennecのデフォルト設定を見た限りでは、履歴の保持日数はFirefoxと同じ90~180日となってるから、これを全部メモリ上に読み込んだらエラい事になるよねぇ。と考えると、必要最小限だけメモリに読み込むようになってる事を期待してると考えていいんだろうか? それとも、これは単にFennec開発陣がSQLiteを過信あるいはモバイルプラットフォームを甘く見てただけで、実は全部オンメモリになっちゃいますとか?

まあとりあえず実装するだけしてみて、それから考えてみよう……

……とりあえずやってみたけど、なんか、めさめさ重い……ちゃんと作ってないから単にどっかで無限ループしてるのかもだけど。しかしそれを抜きにしても、辞書が約4MBだったのがSQLiteにしたら9MBに膨れ上がってしまった。モバイルで使うなんてのはますます非現実的な領域だ。工夫しないと全然お話にならんね……

追記。もうちょっと進めてみたけど、余計泥沼に嵌ってる気がしてきた。バックエンドのSQLite化は無しだな、というのが現時点での結論ですわ。

XPCOMのインターフェースの変更点 on Firefox 3.1と、正規表現検索のアドオン - Jan 30, 2009

落ち穂拾い #6 - Mozilla Fluxで、Firefox 3.0から3.1(beta3前まで)のXPCOMコンポーネントのインターフェースの変化まとめが紹介されてたので見てみた。これはすごいな……だいぶ確認の労力を削減できるんじゃないか? まあインターフェースが変わってなくても実装が変わって影響が出てる、という箇所もひょっとしたらあるかもだけど、大まかなチェックには使える。

ところでこのサイトどっかで見たなと思ったら、Nightly Tester Toolsの作者の人だった。でアドオン一覧のページがあったから見てみたら、/Find Bar/という気になる名前があった。ページ内検索で正規表現を使えるようにする、という物だ。ってこれ、XUL/Migemoともろかぶりじゃん!! 中身見てみたけど、やってることはやはり同じような感じだった。参考にできる所があったらパクらせて貰おう(GPL/LGPL/MPLのトリプルライセンスなので、GPLのXUL/Migemoにはコードを取り込める)。

しかし「Migemo」といい「/Find Bar/」といい、「正規表現(regexp)」というキーワードからはなかなか見つけられない名前なのが困りものだ。

Firefox 3.1のスマートロケーションバーまわりがわけわからん! - Jan 09, 2009

現時点までで、以下の設定項目が新設されたところまでは把握してる。

  • browser.urlbar.restrict.history(文字列型)
  • browser.urlbar.restrict.bookmark(文字列型)
  • browser.urlbar.restrict.tag(文字列型)
  • browser.urlbar.restrict.typed(文字列型)
  • browser.urlbar.match.title(文字列型)
  • browser.urlbar.match.url(文字列型)
  • browser.urlbar.default.behavior(整数型):Bug 463459 – Use a separate pref instead of empty restrict/match values to specify defaults により追加された。restrictとmatchの値が「空の場合は」云々の特例的な処理を一本化するための物。
  • browser.urlbar.search.sources(整数型)

以下は削除された、と。

  • browser.urlbar.matchOnlyTyped(真偽型)

が、どれがどんな風に働くのかがごちゃごちゃして分からんようになってきた……

browser.urlbar.default.behavior(フラグを指定しておくことで、restrictとかmatchとかの指定をしたのと同じ状態から検索をスタートする)に3を指定するのと、browser.urlbar.search.sourcesに3を指定するのとの、違いがいまいち分からない。ので、ソースをあちこち辿ってみた。見てみた感じでは、どうやらnsNavHistoryのProcessTokensForSpecialSearchメソッドが鍵になってるっぽい。

検索対象のテーブルの指定や絞り込みの条件は、すべてmAutoCompleteCurrentBehaviorという1つの変数にフラグとして格納される。

  • 1(最下位ビットがON)は、履歴だけを検索対象にする。
  • 2(下から2番目のビットがON)は、ブックマークだけを検索対象にする。
  • 4(下から3番目のビットがON)は、タグ付けされている項目だけを検索対象にする。
  • 8(下から4番目のビットがON)は、タイトルにマッチする。
  • 16(下から5番目のビットがON)は、URIにマッチする。
  • 32(下から6番目のビットがON)は、ユーザがロケーションバーから手動操作で訪問した項目だけを検索対象にする。

これらを踏まえて、以下の順で処理されている。

  1. browser.urlbar.default.behaviorの指定でmAutoCompleteCurrentBehaviorを初期化する。
  2. browser.urlbar.search.sourcesを見て、
    1. 1だったらmAutoCompleteCurrentBehaviorの最下位ビットをONにする。
    2. 2だったら下から2番目のビットをONにする。
    3. それ以外の時(0や3)は何もしない。(browser.urlbar.search.sourcesが0の時、つまりスマートロケーションバーの検索機能自体を無効にしている時は、ここにそもそも処理が回ってこない?)
  3. スマートロケーションバーに入力中の文字列をトークンごとに分割して、restrictやmatchで設定されている文字列と比較する。一致したらその都度、mAutoCompleteCurrentBehaviorの対応するビットをONにしていく。
  4. 入力中の文字列が空の時は、最下位ビットと下から6番目のビットをONにする。(Bug 426864 – Only show user typed history pages for the urlbar dropdown によって追加された処理で、ユーザが何も入力してない状態でドロップダウンリストを開いたら過去の入力履歴だけを表示する、という挙動をこれによって再現する。)
  5. ここまでの結果のmAutoCompleteCurrentBehaviorを見て、以下の順で、どのSQL文を使うかを決定する。これは排他的な選択なので、どれかの道に分岐したらその時点で検索条件が確定する。
    1. 下から3番目のビットがONの場合、タグ付けされた項目だけを検索するSQL文を使う。
    2. 下から2番目のビットがONの場合、ブックマークだけを検索するSQL文を使う。
    3. 下から6番目のビットがONの場合、ユーザがロケーションバーから手動で訪問した項目だけを検索するSQL文を使う。
    4. 最下位ビットがONの場合、履歴だけを検索するSQL文を使う。
    5. 上記ビットがいずれもOFFの場合、履歴とブックマークの両方を対象に検索するSQL文を使う。
  6. 下から4番目のビットと下から5番目のビットは、次の段階での絞り込みに使われる。

ああややこしい……

  • 5のステップでは排他的な選択になっているので、例えば「タグ付けされた項目で、且つ、ロケーションバーから訪問した事がある物だけを対象に検索する」という風なことはできないようだ。
  • 条件を指定する方法には、browser.urlbar.search.sources、browser.urlbar.default.behavior、検索時のキーワード入力の3つがあるが、これら3つの間には優先順位は無い。優先順位は各ビットの方にあって、常に5-1から5-5の順番に従って判定される。なので、以下のような不可解なことが起こる。
    • browser.urlbar.default.behaviorを使って、ブックマークからのみ検索を行うようにした状態(下から2番目のビットがON)で、検索時語句の中に「^」を含めて履歴のみの検索を指示した(最下位ビットがON)、という場合、手動で指示した検索条件はまるっきり無視されて、あくまでブックマークからのみ検索が行われる。
    • browser.urlbar.default.behaviorを使って、ユーザがロケーションバーから手動で訪問した項目だけを検索対象にするように指定(下から6番目のビットがON)していても、検索時語句の中に「+」が含まれていた(下から3番目のビットがON)場合には、手動で指定した方の条件が優先されて、タグ付けされた項目からのみ検索が行われる。
  • browser.urlbar.default.behavior=3とbrowser.urlbar.search.sources=3の違いは、前者は「ブックマークされていて且つ履歴にも含まれている(=訪問済みのブックマーク)」項目だけが検索対象になり、後者は「ブックマークと履歴の全体」が検索対象になる、という点。search.sourcesが0(検索機能自体が無効になっている)以外で、default.behaviorが3の時は、両方の条件がMIXされて、browser.urlbar.default.behavior=3の条件と同じ(ブックマークと履歴の全体から訪問済みのブックマークだけを検索するのも、ブックマークから訪問済みのブックマークだけを検索するのも、履歴から訪問済みのブックマークだけを検索するのも、全部同じ事ですね)になる。

その場での入力とデフォルト設定のどっちが優先されるのか、がパッと分からないのってどうかと思うんだけど……XUL/Migemoのスマートロケーションバー周りの挙動をこれに合わせないといけないんだけど、こういうわかりにくい挙動をそのまま再現するというのは、モチベーションが上がらないなあ。(ていうかバグ立ってそう)

21日追記。browser.urlbar.search.sourcesが廃止されてこのエントリの内容のかなりの部分は無駄になりました。

XUL/Migemoで、非表示の要素の中にマッチする文字列があったときに検索結果がおかしくなる問題で悩んでる - Dec 05, 2008

掲示板の方で障害報告を受けていた、正規表現にマッチするはずなのに強調表示される物とされない物があるという問題。原因を色々調べてみたら、非表示の要素が問題を引き起こしていた。

<fieldset>
<legend style="display:none">b</legend>
<p>a b a c</p>
</fieldset>

例えばこんな箇所を検索対象にして、a|bという正規表現で検索するとする。

XUL/Migemoはまず一旦検索対象の範囲をDOM Rangeで取得して、文字列に変換し、それに対して正規表現のマッチングを行う。この場合、Rangeからは「b a b a c」という風な文字列が得られ、最初にマッチした「b」がヒット箇所ということになる。

次に、この「実際にヒットした文字列」を使ってFirefox自身の持つ検索機能を呼ぶんだけど、ここで問題が起こる。Rangeの文字列化では要素が表示されてるかどうかというのは考慮されないんだけど、nsIFindのRange内検索では、ヒット箇所が非表示の要素の中だった場合はヒットしなかったものとして次候補を探してしまう。上記の例では、非表示のlegend要素の中に「b」という文字列を見つけても、非表示だからということでスルーされてしまい、実際には次のp要素内の「b」という文字列の方にヒットしてしまう。

XUL/Migemoで次候補を検索すると、次の(2つ目の)「a」にはヒットする。さらに次候補を検索すると、文書の終了に達して文書先頭から検索し直されるのだけれども、この時も上記のような事が起こって、p要素内の1つ目の「a」ではなくp要素内の「b」がヒットする。よって、普通の前方検索を行っている間は永久に、p要素内の1つ目の「a」にはマッチしないという現象が起こる。

Rangeを文字列化する時に、非表示の要素を除外できればいいんだけど……

ちなみに現在のところ、Rangeを文字列化する時は、DOM3 XPathを使ってscript要素などを検出してそこを避けるように文字列化してるんだけど、要素の表示・非表示をキーにしようとするとDOM2 TraversalのTreeWalkerを使わないといけないと思う。TreeWalkerではすべての要素ノードに対してJavaScriptの関数呼び出しと条件判定が行われるので、長いページだとヤバイくらいに速度低下が起こりそう……という懸念があって、手を出せずにいる。

追記。実際にそのように実装して試してみたところ、確かに正しく検索できるようにはなるんだけど、Rangeを文字列化する処理自体が10倍遅くなった。これはまずいなあ。

Adobe AIRでMigemo - Nov 25, 2008

AIRMigemoというライブラリがあることをリファラで知った。AIRアプリにMigemo検索機能を組み込むのに使えるということだろうか。でもライセンスが分からない……

肝心の正規表現の生成処理は、かなり真面目にやってるような印象。XUL/Migemoの現在の実装は長い文字列の一括置換と分割とソートによる擬似的な物なので、「短い入力で長い単語にマッチさせる」という元のMigemoの特徴の一つを損なうことなく持っていると考えられる。

Page 1/248: 1 2 3 4 5 6 7 8 9 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき