Bug 1015894 - Use window.realFrameElement into b2g/components/ContentPermissionPrompt.js to dispatch the permission request to the correct iframe. r=ochameau
authorVivien Nicolas <vnicolas@mozilla.com>
Wed, 04 Jun 2014 20:11:06 +0200
changeset 207124 0c8f92915f71e12b53c3d317dd2319f40d574527
parent 207123 2d9589c8da11707ed878b857367ddd33fff21969
child 207125 e0da2d69cfdb3511f97a2a7021aaf84468c9d3f3
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, "custom");
+    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();