chromiumのgreasemonkey実装とスクリプトを再読み込みさせる方法

COLLECTION & COPY経由ChromiumのGreasemonkeyを軽く試した。でchromeにofficialなgreasemonkeyが搭載されたというのを知って、コードをチェック!

src/chrome/renderer/greasemonkey_slave.ccが実装。極めてシンプル。Firefox版と関数名が同じInjectScriptsになっていてうけました。

bool GreasemonkeySlave::InjectScripts(WebFrame* frame) {
  // TODO(aa): Check script patterns here

  for (std::vector<GreasemonkeyScript>::iterator script = scripts_.begin();
       script != scripts_.end(); ++script) {
    frame->ExecuteJavaScript(script->GetBody().as_string(),
                             script->GetURL().as_string());
  }

  return true;
}

src/chrome/renderer/render_view.cc

void RenderView::DidFinishDocumentLoadForFrame(WebView* webview,
                                               WebFrame* frame) {
  // Check whether we have new encoding name.
  UpdateEncoding(frame, webview->GetMainFrameEncodingName());

  // Inject any Greasemonkey scripts. Do not inject into chrome UI pages, but
  // do inject into any other document.
  if (greasemonkey_enabled_) {
    const GURL &gurl = frame->GetURL();
    if (gurl.SchemeIs("file") ||
        gurl.SchemeIs("http") ||
        gurl.SchemeIs("https")) {
      RenderThread::current()->greasemonkey_slave()->InjectScripts(frame);
    }
  }
}

で実行される。

これはWebKitのWebCoreを継承している

void WebFrameLoaderClient::dispatchDidFinishDocumentLoad()

の中からドキュメントがロードされたタイミング(HTMLがロードされて文字コードが再設定されるタイミング、ってかいてありました。DOM構築タイミングとの関係は調べてないです)だそうです。

ちなみにGreasemetalでは、WebKit内部の微妙なタイミングは外側からは取得する方法がないので500ms間隔でポーリングしてchromeの持っているタブの数をチェックして、新しく現れたタブにscriptを流し込む、という方法がとられています。

実装としてはGreaseKitGreasemetalと全く同じで単純にDOMが完成したタイミングでjavascriptのコードが実行されているだけでした。FirefoxのXPCNativeWrapperのような安全策を講じるのはJSエンジンに大きな細工が必要だし、パフォーマンスを落とすのでchromeでは今後も導入されない(つまり今後もGM_*系関数が使えるようになることはない)んじゃないかと思います。JSONPという裏技が編み出された今となっては昔に比べればクロスドメインXMLHttpRequestの必要性も減って、なくても困らなくなってるし(実際自分の使っているスクリプトで構造上GM_*が必須なものはないです)。

スクリプトの再読み込み

ついでにTwitter / Shogo Ohta: いちいち再起動するの面倒過ぎるのはなんとかならないのか調べてみたらRenderProcessHost::Init()というのが呼ばれた時にスクリプトを再読み込みしているので、一度同じレンダリングプロセス(chromiumのプロセスモデル参照。単純に言えば同じドメインのもの)に属するタブを全部閉じてからもう一度開くとスクリプトが再読み込みされるので、再起動しなくてもよくなります。
タブを閉じないでページの再読み込みをするとレンダリングプロセスが再利用されるけど、タブを閉じたらちゃんと消滅して再度開いた時にプロセスがまた生成されるのでスクリプトが再読み込みされて更新が反映されます。

一度タブを閉じてもう一度開いたら再読み込みされているのをGoogle Chrome にいよいよ GreaseMonkey がやってくる ::: creazy photographを参照してインストールしたchromium3804上で確認しました。


About this entry