Bug 1015894 - Use window.realFrameElement into b2g/components/ContentPermissionPrompt.js to dispatch the permission request to the correct iframe. r=ochameau
☠☠ backed out by 616163ca1aa5 ☠ ☠
authorVivien Nicolas <vnicolas@mozilla.com>
Wed, 04 Jun 2014 20:11:06 +0200
changeset 206970 3220b7b2efc9022dde350eaa21528d065e6c7db9
parent 206969 4e23647ae2470a3022a17a2f2e065d9fdac013d1
child 206971 dbcb9974b640b6846647b44c7995844c612eb0bb
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1015894
milestone32.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 1015894 - Use window.realFrameElement into b2g/components/ContentPermissionPrompt.js to dispatch the permission request to the correct iframe. r=ochameau
b2g/components/ContentPermissionPrompt.js
b2g/components/SystemAppProxy.jsm
b2g/components/test/mochitest/systemapp_helper.js
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -415,17 +415,34 @@ ContentPermissionPrompt.prototype = {
       isApp: isApp,
       remember: remember,
       isGranted: isGranted,
     };
 
     if (isApp) {
       details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
     }
-    SystemAppProxy.dispatchEvent(details);
+
+    // request.element is defined for OOP content, while request.window
+    // is defined for In-Process content.
+    // In both cases the message needs to be dispatched to the top-level
+    // <iframe mozbrowser> container in the system app.
+    // So the above code iterates over window.realFrameElement in order
+    // to crosss mozbrowser iframes boundaries and find the top-level
+    // one in the system app.
+    // window.realFrameElement will be |null| if the code try to cross
+    // content -> chrome boundaries.
+    let targetElement = request.element;
+    let targetWindow = request.window || targetElement.ownerDocument.defaultView;
+    while (targetWindow.realFrameElement) {
+      targetElement = targetWindow.realFrameElement;
+      targetWindow = targetElement.ownerDocument.defaultView;
+    }
+
+    SystemAppProxy.dispatchEvent(details, targetElement);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
 (function() {
--- a/b2g/components/SystemAppProxy.jsm
+++ b/b2g/components/SystemAppProxy.jsm
@@ -53,17 +53,20 @@ let SystemAppProxy = {
    *     event.details == 'bar'
    *   });
    *
    *   @param type      The custom event type.
    *   @param details   The event details.
    *   @param noPending Set to true to emit this event even before the system
    *                    app is ready.
    */
-  _sendCustomEvent: function systemApp_sendCustomEvent(type, details, noPending) {
+  _sendCustomEvent: function systemApp_sendCustomEvent(type,
+                                                       details,
+                                                       noPending,
+                                                       target) {
     let content = this._frame ? this._frame.contentWindow : null;
 
     // If the system app isn't ready yet,
     // queue events until someone calls setIsReady
     if (!content || (!this._isReady && !noPending)) {
       this._pendingEvents.push([type, details]);
       return null;
     }
@@ -75,24 +78,24 @@ let SystemAppProxy = {
     // we consider the caller already wrapped (correctly) the object.
     if ('__exposedProps__' in details) {
       payload = details;
     } else {
       payload = details ? Cu.cloneInto(details, content) : {};
     }
 
     event.initCustomEvent(type, true, false, payload);
-    content.dispatchEvent(event);
+    (target || content).dispatchEvent(event);
 
     return event;
   },
 
   // Now deprecated, use sendCustomEvent with a custom event name
-  dispatchEvent: function systemApp_sendChromeEvent(details) {
-    return this._sendCustomEvent('mozChromeEvent', details);
+  dispatchEvent: function systemApp_sendChromeEvent(details, target) {
+    return this._sendCustomEvent('mozChromeEvent', details, false, target);
   },
 
   // Listen for dom events on the system app
   addEventListener: function systemApp_addEventListener() {
     let content = this._frame ? this._frame.contentWindow : null;
     if (!content) {
       this._pendingListeners.push(arguments);
       return false;
--- a/b2g/components/test/mochitest/systemapp_helper.js
+++ b/b2g/components/test/mochitest/systemapp_helper.js
@@ -3,16 +3,17 @@ const Cu = Components.utils;
 const { Services } = Cu.import("resource://gre/modules/Services.jsm");
 
 // Load a duplicated copy of the jsm to prevent messing with the currently running one
 let scope = {};
 Services.scriptloader.loadSubScript("resource://gre/modules/SystemAppProxy.jsm", scope);
 const { SystemAppProxy } = scope;
 
 let frame;
+let customEventTarget;
 
 let index = -1;
 function next() {
   index++;
   if (index >= steps.length) {
     assert.ok(false, "Shouldn't get here!");
     return;
   }
@@ -42,16 +43,20 @@ function listener(event) {
 
     next(); // call checkEventDispatching
   } else if (n == 3) {
     assert.equal(event.type, "custom");
     assert.equal(event.detail.name, "third");
   } else if (n == 4) {
     assert.equal(event.type, "mozChromeEvent");
     assert.equal(event.detail.name, "fourth");
+  } else if (n == 5) {
+    assert.equal(event.type, "mozChromeEvent");
+    assert.equal(event.detail.name, "fifth");
+    assert.equal(event.target, customEventTarget);
 
     next(); // call checkEventListening();
   } else {
     assert.ok(false, "Unexpected event of type " + event.type);
   }
 }
 
 
@@ -74,16 +79,18 @@ let steps = [
 
   function createFrame() {
     // Create a fake system app frame
     let win = Services.wm.getMostRecentWindow("navigator:browser");
     let doc = win.document;
     frame = doc.createElement("iframe");
     doc.documentElement.appendChild(frame);
 
+    customEventTarget = frame.contentDocument.body;
+
     // Ensure that events are correctly sent to the frame.
     // `listener` is going to call next()
     frame.contentWindow.addEventListener("mozChromeEvent", listener);
     frame.contentWindow.addEventListener("custom", listener);
 
     // Ensure that listener being registered before the system app is ready
     // are correctly removed from the pending list
     function removedListener() {
@@ -113,17 +120,18 @@ let steps = [
     frame.setAttribute("src", "data:text/html,system app");
   },
 
   function checkEventDispatching() {
     // Send events after the iframe is ready,
     // they should be dispatched right away
     SystemAppProxy._sendCustomEvent("custom", { name: "third" });
     SystemAppProxy.dispatchEvent({ name: "fourth" });
-    // Once this 4th event is received, we will run checkEventListening
+    SystemAppProxy._sendCustomEvent("custom", { name: "fifth" }, false, customEventTarget);
+    // Once this 5th event is received, we will run checkEventListening
   },
 
   function checkEventListening() {
     SystemAppProxy.addEventListener("mozContentEvent", function onContentEvent(event) {
       assert.equal(event.detail.name, "first-content", "received a system app event");
       SystemAppProxy.removeEventListener("mozContentEvent", onContentEvent);
 
       next();