Bug 992778 - Set docshell.chromeEventHandler in child processes. r=bz
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 09 Apr 2014 07:15:00 +0200
changeset 197037 84f879f9cdc3563e3a600431ed882ea3a5d7789d
parent 197036 3abaf19dcbffc7076bfec2037210b0dbbe76f002
child 197038 6bccf46b48d00ee8c365369bf3cc9f3cb6c03300
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs992778
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 992778 - Set docshell.chromeEventHandler in child processes. r=bz
dom/ipc/TabChild.cpp
dom/ipc/tests/mochitest.ini
dom/ipc/tests/test_child_docshell.html
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -934,16 +934,30 @@ TabChild::Init()
       mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW);
   loadContext->SetRemoteTabs(
       mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
 
   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
   NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
   webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
 
+  // Few lines before, baseWindow->Create() will end up creating a new
+  // window root in nsGlobalWindow::SetDocShell.
+  // Then this chrome event handler, will be inherited to inner windows.
+  // We want to also set it to the docshell so that inner windows
+  // and any code that has access to the docshell
+  // can all listen to the same chrome event handler.
+  // XXX: ideally, we would set a chrome event handler earlier,
+  // and all windows, even the root one, will use the docshell one.
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+  nsCOMPtr<EventTarget> chromeHandler =
+    do_QueryInterface(window->GetChromeEventHandler());
+  docShell->SetChromeEventHandler(chromeHandler);
+
   return NS_OK;
 }
 
 void
 TabChild::NotifyTabContextUpdated()
 {
     nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
     MOZ_ASSERT(docShell);
--- a/dom/ipc/tests/mochitest.ini
+++ b/dom/ipc/tests/mochitest.ini
@@ -1,2 +1,3 @@
 [test_NuwaProcessCreation.html]
 run-if = toolkit == 'gonk'
+[test_child_docshell.html]
new file mode 100644
--- /dev/null
+++ b/dom/ipc/tests/test_child_docshell.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.addPermission("browser", true, document);
+SpecialPowers.pushPrefEnv({'set':[
+  ["dom.mozBrowserFramesEnabled", true],
+  ["dom.ipc.tabs.disabled", false]
+]}, function () {
+
+  var iframe =  document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
+  iframe.setAttribute("remote", "true");
+  SpecialPowers.wrap(iframe).mozbrowser = true;
+  document.documentElement.appendChild(iframe);
+
+  var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+  mm.addMessageListener("chromeEventHandler", function (msg) {
+    msg = SpecialPowers.wrap(msg);
+    var result = msg.json;
+    is(result.processType, SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT,
+       "The frame script is running in a real distinct child process");
+    ok(result.hasCorrectInterface,
+       "docshell.chromeEventHandler has nsIDOMEventTarget interface");
+  });
+
+
+  mm.addMessageListener("DOMWindowCreatedReceived", function (msg) {
+    msg = SpecialPowers.wrap(msg);
+    ok(true, "the chrome event handler looks functional");
+    var result = msg.json;
+    ok(result.stableChromeEventHandler, "docShell.chromeEventHandler is stable");
+    ok(result.iframeHasNewDocShell, "iframe spawns a new docShell");
+    ok(result.iframeHasSameChromeEventHandler, "but iframe has the same chrome event handler");
+    SimpleTest.finish();
+  });
+  // Inject a frame script in the child process:
+  mm.loadFrameScript('data:,new ' + function ContentScriptScope() {
+    var processType = Components.classes["@mozilla.org/xre/runtime;1"]
+                                .getService(Components.interfaces.nsIXULRuntime)
+                                .processType;
+    var chromeEventHandler = docShell.chromeEventHandler;
+    sendAsyncMessage("chromeEventHandler", {
+      processType: Services.appinfo.processType,
+      hasCorrectInterface: chromeEventHandler instanceof Components.interfaces.nsIDOMEventTarget
+    });
+
+    /*
+      Ensure that this chromeEventHandler actually works,
+      by creating a new window and listening for its DOMWindowCreated event
+    */
+    chromeEventHandler.addEventListener("DOMWindowCreated", function listener(evt) {
+      if (evt.target == content.document) {
+        return;
+      }
+      chromeEventHandler.removeEventListener("DOMWindowCreated", listener);
+      let new_win = evt.target.defaultView;
+      let new_docShell = new_win.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIWebNavigation)
+                                .QueryInterface(Ci.nsIDocShell);
+      sendAsyncMessage("DOMWindowCreatedReceived", {
+        stableChromeEventHandler: chromeEventHandler === docShell.chromeEventHandler,
+        iframeHasNewDocShell: new_docShell !== docShell,
+        iframeHasSameChromeEventHandler: new_docShell.chromeEventHandler === chromeEventHandler
+      });
+    });
+
+    let i = content.document.createElement("iframe");
+    i.setAttribute("src", "data:text/html,foo");
+    content.document.documentElement.appendChild(i);
+  }, false);
+});
+
+</script>
+</body>
+</html>