Edited at

「以前のバージョンでは使えていた機能が新バージョンでは使えなくなった」時の原因の調べ方

この記事は会社のブログとのクロスポストです

恐らくあまり知られていませんが、Firefoxはインストール先の browser/chrome/icons/default/main-window.ico の位置(Firefoxのインストール先が C:\Program Files\Mozilla Firefox\ であれば、 C:\Program Files\Mozilla Firefox\browser\chrome\icons\default\main-window.ico)にICO形式のアイコン画像を置くと、それがメインウィンドウのアイコンになるという機能がありました1

(実際にアイコンを変えた様子)

この機能について、次のESR版であるESR68でも有効なのかどうかを確かめようとNightly 68で試してみたところ、アイコンが変化しないという結果を得られました。

ということは、Firefox ESR68では機能が削除されたのだな……と決めつけるのは早計です。開発版のNightlyで駄目だったからといって、そのバージョンのFirefoxが正式リリースされた後も駄目だとは限りません2。たまたまNightlyでは機能していないだけなのか、それともこの方法が使えなくなってしまったのか、きちんと裏付けを取らないとはっきりした事は言えません。

この記事では、フリーソフトウェア・OSSで遭遇したこのような挙動の変化の経緯を実装を辿って調べる方法について、Firefoxでの事例を示します。


調査の取っかかりを探す

この事例では「ウィンドウのアイコン」がポイントになります。Windows上で動くFirefoxはWindowsのアプリケーションなので、ウィンドウのタイトルバーのアイコンを変えるには当然Windowsのアプリケーションの流儀に則った方法を使っているはずです。

Windows window icon win32 といったキーワードで検索してみたところ、Win32アプリケーションでウィンドウのアイコンを変える伝統的なやり方に WM_SETICON という定数で定められたメッセージを使う方法 があるという事が分かりました。


機能が動いているバージョンでどう実装されているかを調べる

確認してみたところ、前述の方法でのアイコン変更はFirefox ESR60やFirefox 66では機能していました。そこで、Firefox ESR60のソースコード中で SM_SETICON という定数が使われている箇所を検索してみたところ、クロスプラットフォームな実装ではなくWindows固有の実装の部分で、この定数が使われている箇所が見つかりました

このメソッドの冒頭で呼ばれているResolveIconName()というメソッドの定義を辿り、さらにその中で呼ばれている ResolveIconNameHelper() というメソッドの定義まで辿ってみたところ、「与えられたファイルハンドラからiconsdefault、とディレクトリを辿り、与えられたファイル名のアイコンファイルに対応するアファイルハンドラを得る」という処理が行われている様子がうかがえました。これはまさしく、前述の「特定の位置に置かれたアイコンファイルを参照する」という処理そのものに見えます。

この箇所は nsWindow クラスの SetIcon() メソッドに含まれていますので、今度はこのメソッドを呼んでいる箇所を探しました。すると、XULのwindow要素のid属性の値を参照してアイコンを設定しているらしい箇所が見つかりました。

  // "id" attribute for icon

windowElement->GetAttribute(NS_LITERAL_STRING("id"), attr);
if (attr.IsEmpty()) {
attr.AssignLiteral("default");
}
mWindow->SetIcon(attr);

ということで、先の方法でウィンドウのアイコンを変更するという機能は、この一連の箇所によって実現されている事が分かりました。


機能が動いていないバージョンでどう実装されているかを調べる

機能が動いているバージョンでの実装が分かったので、今度は対応する部分のNightly 68での実装を見てみました。

先ほど見ていった実装のそれぞれについてNightly 68での状況を見ていくと、ほとんどの箇所には変更が見られませんでしたが、nsWindow クラスの SetIcon() メソッドを呼んでいる箇所に違いがありました。こちらでは、XULのwindow要素のicon属性の値を参照して、値があった時にだけアイコンを設定するというコードになっています。

  // "icon" attribute

windowElement->GetAttribute(NS_LITERAL_STRING("icon"), attr);
if (!attr.IsEmpty()) {
mWindow->SetIcon(attr);

NS_ENSURE_TRUE_VOID(mWindow);
}

Firefoxのソースコード検索システムでは、そのまま続けてMercurialのblameの結果を見る事ができます。そこから当該箇所の変更が行われたコミットの情報を見ると、バグトラッカー上での対応するbugの番号が記載されており、Bug 1531836 - Each new xul window does a stat call to look for non-existant window specific iconsに辿り着きました。

bugの内容を読むと、どうやら起動処理の高速化の一環として、「まず存在しないファイルを探しに行く」のではなく「明示的にアイコンが指定されている時だけファイルを探しに行く」という方針に改める変更が行われ、その一環として前述の機能が削除されたという事のようです。


まとめ

以上、フリーソフトウェア・OSSで「以前のバージョンでは使えていた機能が新バージョンでは使えなくなった」という事態に遭遇した時の原因の調べ方の、Firefoxでの事例をご紹介しました。

ユーザーの目に触れやすい機能の変更はリリースノートに記載されることが多いですし、また、開発者向けに影響の大きな変更は技術情報が別途まとめられている事もあります。しかし、この例のように影響度の小さい変更は、そのような変更があったという事自体は特に告知されないままになっている事があります。そういった場合でも、フリーソフトウェア・OSSではソースコードやバージョン管理システムの変更履歴を辿って、原因を特定したり回避方法を見つけたりする事ができます。

皆さんも是非、開発に使用しているフレームワークやライブラリの挙動の変化に気付いた時には、公開の情報から詳細を調べてみて下さい。





  1. 正確には、(id文字列).ico という名前でファイルを置いておくと、ウィンドウの内部的なID(XULのwindow要素のid属性の値)が一致するファイルが自動的に使われるという事になっています。 



  2. その逆に、Nightlyでは使えていた機能が同じバージョンのリリース版Firefoxで使えなくなる場合もあります。例えば xpinstall.signatures.required という設定はビルド時のオプションによって機能するかどうかが切り替わるようになっており、NightlyとDeveloper Editionでは使えますが、ベータ版および正式リリース版のFirefoxでは機能しないようになっています。