たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。
以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
bugzilla上での活動?としてはこんな感じでした。
成果らしい成果は……パッチが1つだけreview+をもらえたチェックインされたことくらいでしょうか。
コメントも何もしてないけど、目を付けたバグ。
感想。Fennecが実用レベルになるのはまだまだまだまだまだまだまだ先だなあ。
というか今Fennecという名前で開発されているブツは、Mozilla Labsが作る新しいUIデザインのモックアップに過ぎない、という風な位置づけのように感じられる。バックエンドで使ってるXULRunnerはモバイル向けの調整が施されていなくて、印刷関係の機能とか、明らかに不要な物がてんこ盛りになっている。中野さん達と色々話したけど、「実用になる製品」の開発を目指すんだったら、僕がこういう風に手出しできるレイヤでゴチャゴチャと小賢しいことをするんじゃなくて、中野さんに書いて貰ったパッチのように、XULRunner自体の方にもっともっと手を入れていく必要があるのだろう。HTML Canvasを描画に使ってるせいで色々酷いことになってるのも、Canvasに手を入れるかDocShellに手を入れるかして、ネイティブ寄りの所で実現するようにすればずっとマシになるはずなのに。とかなんとかそういう「うわぁ……」な現状が色々見えてきたのが、今回の合宿の一番の成果だったのかもしれない。
世間的にすごい今更だと思うけど、今日やろうとして詰まったのでメモしておく。
Illustrator CS2を使ってた時は、以下のような感じだった。
しかしIllustrator CS4では、「オブジェクト」メニューに「クリエイト」が無い。
実は、IllustratorはCS4から複数のアートボードをサポートするようになって、印刷や出力の基本単位はアートボードごとということになっているらしい。なので以下のようにすれば、CS2の時の結果と同様、アートボードの大きさでトリミングされたPNG画像を得ることができる。
ということでこの件については解決された。しかし「アートボードとぴったり同じ大きさの矩形オブジェクト」を作るのが面倒になったのはやっぱり頂けない(CS2だと、トリムマークを作ってそのまま解除すれば、アートボードと同じ大きさの矩形オブジェクトを得ることができた)。
AMOを見たらリニューアルされてて、好きなアドオンを集めたリストを公開できる「コレクション」という機能が加わってたので、さっそく使ってみた。
リストアップされたアドオンをボタン一発でまとめてインストールできる機能だとばかり思ってたんだけど、そういう機能はなくて、入れたかったらいっこいっこ個別にぽちぽちインストールしないといけない。これは面倒すぎる。なんで一括インストールできるようにしなかったんだ? 方法はいくつかあるだろうに。
The Burning Edge見てたら、こんなバグがFIXEDになっていた。
text/htmlなHTMLドキュメントをXMLとして扱うにあたって、HTML5の仕様に合わせる形になるという事のようだ。namespaceURI
がnull
から"http://www.w3.org/1999/xhtml"
へ、localName
がすべて大文字からすべて小文字へ、それぞれ変わる、と。
以前の挙動は以前の挙動で古い仕様には合致していたはずなので、時代の移り変わりをしみじみと感じる。
もえじら組のバナー画像を夏コミに合わせて更新しなければ→VistaでIllustrator CS2マトモに動かないんだよね……→そろそろCS4買いますか。ということでカカクコムで探してクレジットカード決済のできる店のひとつだったNTT-X Store(初めて使う店)で注文しようと思ったら、カードの情報を正しく入力してるはずなのに認証に失敗する。3回やり直したら「この決済方法は使えません。他の方法を選んで下さい」なんて言われたし。
で、諦めてそこよりちょっとだけ値段が高かったAmazon(言うまでもなくいつも使ってる)で深夜に注文して、昼間に決済手続きが行われたようなんだけど、「クレジットカードで認証できませんでした」という警告っぽいメールがAmazonから届きまして。なんじゃこりゃどういうこっちゃ、とカード会社のコールセンターに電話して聞いてみた。
めんどくさ……
ちなみにAmazonの方は、そのあと認証を勝手にやり直してくれたのか無事決済できたようで、当日のうちに発送された。
ローカルプロキシっぽいことをローカルプロキシを立てずにやろうとして挫折したことのまとめを書いたら、thorikawaさんが別のアプローチを提示してくださったので、その方向で頑張ってみた。
結論から言うと、URIの置き換え(特定のURIにアクセスしようとした時に、別のURIのリソースの内容を返す)についてはできるようになった。成果はUxU 0.6.0に組み込んである。ただし、他のアドオンとの競合の可能性があるので、初期状態では機能を無効にしてある。
実装がどうなっているかはGlobalService.jsの中のProtocolHandlerProxy
、HttpProtocolHandlerProxy
、HttpsProtocolHandlerProxy
の各クラスを参照のこと。thorikawaさんのエントリに挙げられている課題は、一応解決されているはず。
thorikawaさんによるコードからの違いは以下の点だ。
一つは QueryInterfaceの部分で、QueryInterfaceの部分を置換前のXPCOMに丸投げしてしまっているので、その後の個別の処理も全て置換前XPCOMで行われてもよいはずです。だけど実際にはnewURI,newChannelといったメソッドは置換後のXPCOMのものが呼び出されます。
QueryInterface()
は、実はメソッドの返り値を見るまでもなく、メソッドを実行した時点でそのラッパーオブジェクト自体が変更される。なので、そのせいじゃないかと思う。例えば
var pref = Cc['@mozilla.org/preferences;1']
.getService(Ci.nsIPrefBranch);
var value = pref.getBoolPref(...);
このコードは
var pref = Cc['@mozilla.org/preferences;1']
.getService();
pref.QueryInterface(Ci.nsIPrefBranch);
var value = pref.getBoolPref(...);
と書いてもちゃんと動く。後者のような使い方をされている限りは、QueryInterface()
で何を返していようと関係ない、ということではないのかなあ。
C++で書かれたコンポーネントの中ではdo_QueryInterface()
という関数?がよく使われているようで、こいつが中で何をやってるのかまでは僕にはよく分かってないけど、上記の例の前者ではなく後者に相当するものなんだったら、引用部のような現象が起こるのではないかと思う。
ということでそういう場合に備えて、ProtocolHandlerProxy
クラスは、コンポーネント「{4f47e42e-4d23-4dd3-bfda-eb29255e9ea3}」が備えているすべてのインターフェースを実装しておくようにした。具体的には、nsIHttpProtocolHandler、nsIProtocolHandler、nsIProxiedProtocolHandler、nsIObserver、nsISupports、nsISupportsWeakReferenceの各インターフェース。といっても、やってることとしてはやっぱり単に元のコンポーネントに処理を丸投げしてるだけなんだけど。
またもう一つは、このサンプルでも正常に動作しないサイトがいくつかあること。AJAXを多用しているサイトでも基本的には問題なく動くのですが、たとえばGMailにアクセスするとなぜか簡易版HTMLが表示されてしまいます。もしかすると上記の問題と関連しているのかも知れません。
これは推測だけれども、HTTP_USER_AGENT等が正常に送られなくなっていたせいではないかと思われる。
ちゃんと調べたわけではないんだけど、Webページ内のスクリプトのnavigator.userAgent
の値や、HTTPの通信の際に送られるユーザエージェント名の文字列は、コントラクトIDが@mozilla.org/network/protocol;1?name=http
であるコンポーネントがnsIHttpProtocolHandlerインターフェースを通じて返す値を元に生成されているらしい。
然るに、thorikawaさんによるサンプルコードのコンポーネントにはnewChannel()
などのメソッドは定義されているけれども、nsIHttpProtocolHandlerが持つはずのuserAgent
等のプロパティは定義されていない。XPConnect経由でこのコンポーネントにアクセスすると、undefined
が文字列にキャストされて空文字として返ることになる。その結果、サーバに送られるUA文字列も空っぽになってしまう。つまりサーバから見たら未知のUAとなってしまう。GMailにアクセスするとなぜか簡易版HTMLが表示されてしま
うのは、未知のUAに対しては簡易版HTMLを返すようにGMailが作られているからではないかと僕は推測している。
変更点1で書いた話を実施するにあたって、当初はこれらのプロパティもgetterとして定義してみてたんだけど、実際に動かしてみると、期待通りには動かなかった。具体的には、Webページ内のスクリプトからnavigator.userAgent
等にアクセスしようとすると、セキュリティの制限により前述のgetter関数を実行できない、というエラーが出る。
なので、getter関数を使うことは諦めて、ProtocolHandlerProxy
クラスのプロトタイプに、単純な文字列や数値の定数プロパティとしてそれらを設定しておくようにした。general.useragent.* 系の設定の変更を動的に反映しないといけないので(ここでgetterを使えないのが痛い)、とりあえず今のところは、それらの設定の変更を常時監視して、変更があればその都度ProtocolHandlerProxy
クラスのプロトタイプの定数プロパティの値を更新するようにしている。
この実装では、ProtocolHandlerProxy
をスーパークラスとして、HttpProtocolHandlerProxy
、HttpsProtocolHandlerProxy
という2つのサブクラスを定義することにした。これらの違いは単にコントラクトIDだけ。(まあ、モジュールを登録する時にしか使わない情報なので、サブクラスにするまでもなかったんだろうとは思うけど……)
コントラクトIDが@mozilla.org/network/protocol;1?name=http
であるコンポーネントを入れ替える事を考えた時に、一番問題になるのはおそらく、同じ事をしようとするアドオンが2つ以上あった時のことだと思う。テストケース内でリクエストされるURIをリダイレクトするためだけに、いつもコンポーネントを入れ替えた状態にしておくというのは、無駄にリスクを高めるだけのような気がする。なので、必要な時にだけ機能を有効化できるようにしてみた。
当初は、NSGetModule()
が返すモジュールのregisterSelf()
メソッドの中でregisterFactoryLocation()
している箇所を、設定値を見て必要に応じスキップするようにすればいいだろうか、くらいに考えていた。でも2つの理由でこれはうまくいかなかった。
1の問題をもう少し具体的に書くと、例えばこのコンポーネントの有効無効をextensions.uxu.protocolHandlerProxy.enabled
といった名前の設定で切り替えるようにしようと思っても、NSGetModule()
が返すモジュールのregisterSelf()
メソッドが実行される段階ではまだユーザプロファイル内に保存された設定値が読み込まれていないため、その段階でextensions.uxu.protocolHandlerProxy.enabled
の値を取得しても常にデフォルト値(=false
)となってしまう、ということ。
これを回避するためにUxUでは、設定値ではなくファイルを使うことにした。プロファイル内に「.uxu-protocol-handler-proxy-enabled」という名前のファイルがあればコンポーネントを有効に、ファイルがなければコンポーネントを無効に、という風に、ファイルの有無を真偽値型の設定代わりに使うようにしている。泥臭いというか非効率的というかすごく馬鹿っぽいというかそんな気がするけど、これ以上にいい方法を僕は思いつけなかった。
2の問題は、1を解決できたとしても発生する。Firefoxは利用可能なXPCOMコンポーネントのデータベースをプロファイル内にcompreg.datとxpti.datとして保存しているようで、これらのファイルを生成する時にNSGetModule()
が呼ばれるんだけれども、毎回起動時にこのデータベースを作り直していたら無駄が大きすぎる。ということで、アドオンが追加・削除された時などの「コンポーネントの一覧に変更があった可能性がある」場合にだけ、有効なコンポーネントの一覧のデータベースが作り直されるらしい。UxU的には、プロトコルハンドラの乗っ取りのON/OFFを切り替えた後に必ずこのデータベース再作成の処理を走らせないといけない、でもそれができてない、ということだ。
で、これも似たような方法でアッサリ解決した。Firefoxはユーザプロファイル内に「.autoreg」という名前のファイルがあると(ファイルの有無しか見ないので、内容は何でもいい。空ファイルでよい。)、必ずcompreg.datとxpti.datを再作成する。なので、ユーザが設定を変更したらそのタイミングで「.autoreg」を作成してやり、次に起動した時には設定の変更が確実に適用される(コンポーネントが有効かあるいは無効化される)ようにした。
これだけごちゃごちゃと妙なことをやっておいて、できることといったら単にURIをリダイレクトするだけなんだよね。ショボっ!
気がついたら手持ちの弾を全弾撃ち尽くしてた……という感じ。もうどこをひっくり返しても何も出てきませんわ。
ソース表示タブの障害として、「外部のテキストエディタを使う設定にしてる時に、Windowsのアカウント名が日本語だったりするとファイルを開けない」という報告を受けた。それを修正しようとして挫折した。以下はそのまとめ。
当該機能は実はソース表示タブ自身が提供しているわけではなく、Firefox 2以降くらいからFirefox自体に元々備わっている隠し設定のための設定UIを提供しているだけで、実際の処理はFirefox本体の物に丸投げしている。具体的にはviewSourceUtils.jsのopenInExternalEditor()
とかそこら辺。
ただ、Firefox本体のこのコードは国際化のことをきちんと考えられていないようで、テキストエディタの実行ファイルのパスに日本語の文字などが含まれているとダメという既知のバグがある(原因はgetExternalViewSourceEditor()
の中でgetCharPref()
で取得したパス文字列をUTF-8バイト列からUCS2のUnicode文字列に変換していないせい)。なのでソース表示タブではこの部分に動的にパッチを当てる形で問題を回避するようにして、もう少し実用に耐えるようにしようとしてみている。
今回の問題の原因は、エディタの実行ファイルではなく、開こうとしている対象のファイルのパスの扱いにある。
Firefoxは、ソースを表示しようとしている対象がローカルのファイルだとそれをそのまま、Web上のファイルであればそれをダウンロードしたテンポラリファイルを、エディタに渡そうとするんだけど、どうもその時にnsIProcessのrun()
メソッドで渡す引数がUCS2のままなのがいけないらしい。試しに自分の環境(Windows Vista日本語版)で試したところ、引数のeditor.run(false, [path], 1);
とか書かれてる箇所で渡されてるパス文字列をnsIScriptableUnicodeConverterあたりでShift_JISに変換してやったらうまく動いた。IDL定義ではstringの配列としか書かれてないけど、ここはプラットフォームごとのデフォルトの文字エンコーディングにしておかないといけないようだ。
実験段階で明らかなように、nsIScriptableUnicodeConverterで適切なエンコーディングに変換してやれば問題は解決できる。残る問題は、じゃあ一体どのエンコーディングに変換すればいいのか、ということだ。
設定UI上にエンコーディング選択用のドロップダウンリストを付けるという手もあるけど、ユーザにそんな事を意識させるのはダサイ。なるべくなら自動で判別できるようにしておきたい。ということでその方法を模索してみた。
nativePath
から辿ってみた現在のFirefoxでは、ローカルファイルはnsIFileインターフェースで処理されている。このIDL定義を見ると、プラットフォームのデフォルトのエンコーディングでのパス文字列をそのまま保持しているとおぼしきnativePath
プロパティの定義には[noscript]
と書かれていて、JavaScriptからはアクセスできないようになっている。実際、試してみても無理だし。
ちなみに、昔おそらくnsIFileの代わりに使われていたと思われるnsIFileSpecだとnativePath
には[noscript]
が付いてない。なので、これを使ってやればいいか?と思ったけど、リンク先のソースの位置を見ると分かる通りこれは既に廃止されたモジュールで、今のFirefoxのバイナリには入ってないっぽい。インスタンスを作ろうとしてもエラーになる。
nsIFile/nsILocalFileを実装してるWindows用のコード(nsLocalFileWin.cpp)のGetNativePath()
の定義を見ればヒントを掴めるんじゃないか?と思ってみてみたら、CopyUnicodeToNativeという関数?が使われてた。コードが書かれてるnsNativeCharsetUtils.cppを見てみると……おおお、なんか答えっぽい物があるぞ。ifdefでプラットフォームごとに関数の中身の定義をそれぞれ変えてて、例えば頭の方を見てみると、Mac OS XとBeOSでは単純にUTF-8に変換してるという事が分かる。
ただ、下の方に書いてあるWindows用とUnix/Linux用の処理は、見ても訳が分からんかった……単純にこのエンコーディングに決め打ち、という訳にはいかないみたいで、ここからさらに色んな所のコードを見に行かなきゃいけないようだったので、この時点で挫折した。
nsIScriptableUnicodeConverterはエンコーディング名を指定してUCS2との間で相互変換するものだけど、その時に「プラットフォームのデフォルトのエンコーディング」を指すようなキーワードがあったりしないしないか?と思って、そっち関係のコードも見てみた。
nsICharsetConverterManager.idlとかnsUConvModule.cpp見てて、どこをどう辿ったのか忘れたけど、GetDefaultCharsetForLocale()
というメソッドがnsIPlatformCharset.hで定義されているという所まで辿り着いた。
メソッド名から見て、ロケールを指定しないといけないようだけど、それさえなんとかなればこれでいけるか? と思ってこれにJavaScriptからアクセスできないか試してみたけど、ダメだった。Components.classes['@mozilla.org/intl/platformcharset;1']
にはアクセスできるんだけど、QueryInterface(Components.interfaces.nsIPlatformCharset)
してみたら「そんなインターフェースねえよ」と怒られてしまった。検索してみても、どうもC言語用のコードしか無いみたい。
無理でした。以上。
C(C++?)を書けるようになって、上で辿り着いたメソッドの実行結果を返すだけのコンポーネントでも書けば、サクッと解決できるのだろうか。もう勉強するしかないのか?
コンテキストメニュー拡張で使ってるけど、文字コードを選択するドロップダウンリストは以下のようにすれば作れる。
<menulist id="charset"
label="(choose an charset)"
datasources="rdf:charset-menu"
ref="NC:DecodersRoot">
<template>
<menupopup>
<menuitem uri="..."
label="rdf:http://home.netscape.com/NC-rdf#Name"
value="..."/>
</menupopup>
</template>
</menulist>
ただし、XULにこれを書いただけだと空のリストになってしまう。onloadとかそこらへんでCc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService).notifyObservers(null, 'charsetmenu-selected', 'other');
とすればポップアップの中身が生成される。設定ダイアログで使う時なら、その後でpreference要素のvalue
を見るなどして、前回の選択状態を復元してやる必要がある。
ATOK X3の同音語用例・電子辞典ウィンドウが… - めも (2009-04-07)
この問題についてTwitterで発言したまさに翌日、修正モジュールが公開された。吹いた。
tarの中身は問題の原因になってるライブラリの修正版のバイナリファイルで、ルート直下で展開するとデフォルトのインストール先にあるファイルが上書きされる。他の修正パッチを全て適用した後で別途導入する必要があるようだ。
ので、ぶちまけた。
我慢したり、腹に沈めたりってことがどうにもできない。ストレス耐性、やっぱり低いなあ。「まだやめとこう……もうちょっと待とう」ってつい先日思ったばかりなのに。
まあ後悔はしてないんですけどね。スッキリした感が強い。ある意味「どうにでもなーれ」なのかもだけど。その辺は、前より結構自分でも「変わったなあ」と思える部分だ。
いや、多分本質的には変わってない。ただ、「まあ最悪の状況になってもそんなに酷いことにはならんな」と、そういう風に考えられるようにはなったんだと思う。プッチ神父の言うところの「覚悟」とかそんなん。