Dive Into Firefox: 「スクリプトはスクリプトによって開かれたウィンドウ以外を閉じることができません。」が表示されるまでを追う

Firefox 2.0になってJavascriptからwindow.close()を呼び出す場合の制限が強くなって、Javascriptから開いたのではないウィンドウを閉じようとしても何も起きず、エラーコンソールには上記のような警告が出るようになった*1。あるウィンドウがスクリプトによって開かれたのかそうでないのかをどうやって区別しているのか、またそれはどこで設定されているのかについて、Firefoxソースコードを調べてみた。(以下はVine LinuxFirefox-2.0-0vl4 のソースコードを元にしている。ちなみに、調べるのに使ったのは主にgrep

まず、この警告がどこに定義してあるか調べると、JLP の ja/dom/chrome/dom/dom.properties に

WindowCloseBlockedWarning       = スクリプトはスクリプトによって開かれたウィンドウ以外を閉じることができません。

という行がある。次にソースコード中で WindowCloseBlockedWarning を探すと、mozilla/dom/src/base/nsGlobalWindow.cpp というファイルの nsGlobalWindow::Close() というメソッドで使われている。
その少し上を見ると、以下のようなコードが見つかる。

  // Don't allow scripts from content to close windows
  // that were not opened by script
  nsresult rv = NS_OK;
  if (!mHadOriginalOpener) {
    PRBool allowClose = PR_FALSE;

ビンゴ。今度はこの mHadOriginalOpener を探す。これはメンバー変数なのでこのファイル(とヘッダファイル)の中だけ調べれば OK。すると、nsGlobalWindow::SetOpenerWindow() 内で mHadOriginalOpener = PR_TRUE; してるのが見つかる。そうしたら、あとは関数呼び出しを辿ってこの関数がどこから呼ばれているのかを調べていく。

nsGlobalWindow::SetOpenerWindow() in mozilla/dom/src/base/nsGlobalWindow.cpp
↑
nsWindowWatcher::ReadyOpenedDocShellItem() in mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
↑
nsWindowWatcher::OpenWindowJSInternal()
↑
NS_IMETHODIMP nsWindowWatcher::OpenWindow(), NS_IMETHODIMP nsWindowWatcher::OpenWindowJS()
↑
nsGlobalWindow::OpenInternal()
↑
NS_IMETHODIMP nsGlobalWindow::Open()

NS_IMETHODIMP の意味はわからないけど名前からして何かのインタフェースを実装しているんだろう。ということで、window.open() から nsGlobalWindow::Open() が呼ばれることが容易に想像できる。

あとがき

上では簡単に見つかったように書いたけど、じつはここまで分かるのに1週間近くかかっている。特に、nsGlobalWindow を nsWindowWatcher が呼び出してさらに nsWindowWatcher を nsGlobalWindow が呼び出すという構造に気がつかなくて、無駄にあちこち探し回ってしまった。
今回この件について調べたのは、gBrowser.addTab()で開いたタブが Javascript から close できなかったため。今回の結果をもとに、そちらについても引き続き解決策を考えていきたい。