Loading testing/marionette/marionette-actors.js +168 −41 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ * Gecko-specific actors. */ const FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js"; let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] Loading Loading @@ -94,8 +96,8 @@ MarionetteRootActor.prototype = { getMarionetteID: function MRA_getMarionette() { return { "from": "root", "id": this._marionetteActor.actorID } ; }, } }; // register the calls MarionetteRootActor.prototype.requestTypes = { Loading @@ -103,6 +105,19 @@ MarionetteRootActor.prototype.requestTypes = { "sayHello": MarionetteRootActor.prototype.sayHello }; /** * An object representing a frame that Marionette has loaded a * frame script in. */ function MarionetteRemoteFrame(windowId, frameId) { this.windowId = windowId; this.frameId = frameId; this.targetFrameId = null; this.messageManager = null; } // persistent list of remote frames that Marionette has loaded a frame script in let remoteFrames = []; /** * This actor is responsible for all marionette API calls. It gets created * for each connection and manages all chrome and browser based calls. It Loading @@ -114,8 +129,9 @@ function MarionetteDriverActor(aConnection) .getService(Ci.nsIUUIDGenerator); this.conn = aConnection; this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); this.messageManager = this.globalMessageManager; this.browsers = {}; //holds list of BrowserObjs this.curBrowser = null; // points to current browser this.context = "content"; Loading @@ -127,16 +143,10 @@ function MarionetteDriverActor(aConnection) this.mainFrame = null; //topmost chrome frame this.curFrame = null; //subframe that currently has focus this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']); this.currentRemoteFrame = null; // a member of remoteFrames //register all message listeners this.messageManager.addMessageListener("Marionette:ok", this); this.messageManager.addMessageListener("Marionette:done", this); this.messageManager.addMessageListener("Marionette:error", this); this.messageManager.addMessageListener("Marionette:log", this); this.messageManager.addMessageListener("Marionette:shareData", this); this.messageManager.addMessageListener("Marionette:register", this); this.messageManager.addMessageListener("Marionette:goUrl", this); this.messageManager.addMessageListener("Marionette:runEmulatorCmd", this); this.addMessageManagerListeners(this.messageManager); } MarionetteDriverActor.prototype = { Loading @@ -144,6 +154,26 @@ MarionetteDriverActor.prototype = { //name of the actor actorPrefix: "marionette", /** * Helper methods: */ /** * Switches to the global ChromeMessageBroadcaster, potentially replacing a frame-specific * ChromeMessageSender. Has no effect if the global ChromeMessageBroadcaster is already * in use. If this replaces a frame-specific ChromeMessageSender, it removes the message * listeners from that sender, and then puts the corresponding frame script "to sleep", * which removes most of the message listeners from it as well. */ switchToGlobalMessageManager: function MDA_switchToGlobalMM() { if (this.currentRemoteFrame !== null) { this.removeMessageManagerListeners(this.messageManager); this.sendAsync("sleepSession"); } this.messageManager = this.globalMessageManager; this.currentRemoteFrame = null; }, /** * Helper method to send async messages to the content listener * Loading @@ -153,12 +183,51 @@ MarionetteDriverActor.prototype = { * Object to send to the listener */ sendAsync: function MDA_sendAsync(name, values) { this.messageManager.broadcastAsyncMessage("Marionette:" + name + this.curBrowser.curFrameId, values); if (this.currentRemoteFrame !== null) { this.messageManager.sendAsyncMessage( "Marionette:" + name + this.currentRemoteFrame.targetFrameId, values); } else { this.messageManager.broadcastAsyncMessage( "Marionette:" + name + this.curBrowser.curFrameId, values); } }, /** * Helper methods: */ * Adds listeners for messages from content frame scripts. * * @param object messageManager * The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender) * to which the listeners should be added. */ addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) { messageManager.addMessageListener("Marionette:ok", this); messageManager.addMessageListener("Marionette:done", this); messageManager.addMessageListener("Marionette:error", this); messageManager.addMessageListener("Marionette:log", this); messageManager.addMessageListener("Marionette:shareData", this); messageManager.addMessageListener("Marionette:register", this); messageManager.addMessageListener("Marionette:runEmulatorCmd", this); messageManager.addMessageListener("Marionette:switchToFrame", this); }, /** * Removes listeners for messages from content frame scripts. * * @param object messageManager * The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender) * from which the listeners should be removed. */ removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) { messageManager.removeMessageListener("Marionette:ok", this); messageManager.removeMessageListener("Marionette:done", this); messageManager.removeMessageListener("Marionette:error", this); messageManager.removeMessageListener("Marionette:log", this); messageManager.removeMessageListener("Marionette:shareData", this); messageManager.removeMessageListener("Marionette:register", this); messageManager.removeMessageListener("Marionette:runEmulatorCmd", this); messageManager.removeMessageListener("Marionette:switchToFrame", this); }, /** * Generic method to pass a response to the client Loading Loading @@ -316,7 +385,7 @@ MarionetteDriverActor.prototype = { whenBrowserStarted: function MDA_whenBrowserStarted(win, newSession) { try { if (!Services.prefs.getBoolPref("marionette.contentListener") || !newSession) { this.curBrowser.loadFrameScript("chrome://marionette/content/marionette-listener.js", win); this.curBrowser.loadFrameScript(FRAME_SCRIPT, win); } } catch (e) { Loading Loading @@ -377,6 +446,8 @@ MarionetteDriverActor.prototype = { } } this.switchToGlobalMessageManager(); if (!Services.prefs.getBoolPref("marionette.contentListener")) { waitForWindow.call(this); } Loading Loading @@ -968,6 +1039,14 @@ MarionetteDriverActor.prototype = { } } else { if ((aRequest.value == null) && (aRequest.element == null) && (this.currentRemoteFrame !== null)) { // We're currently using a ChromeMessageSender for a remote frame, so this // request indicates we need to switch back to the top-level (parent) frame. // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so // we send the message to the right listener. this.switchToGlobalMessageManager(); } this.sendAsync("switchToFrame", aRequest); } }, Loading Loading @@ -1302,7 +1381,7 @@ MarionetteDriverActor.prototype = { } try{ this.messageManager.removeDelayedFrameScript("chrome://marionette/content/marionette-listener.js"); this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT); this.getCurrentWindow().close(); this.sendOk(); } Loading @@ -1324,7 +1403,7 @@ MarionetteDriverActor.prototype = { deleteSession: function MDA_deleteSession() { if (this.curBrowser != null) { if (appName == "B2G") { this.messageManager.broadcastAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {}); this.globalMessageManager.broadcastAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {}); this.curBrowser.knownFrames.splice(this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1); } else { Loading @@ -1335,23 +1414,17 @@ MarionetteDriverActor.prototype = { //delete session in each frame in each browser for (let win in this.browsers) { for (let i in this.browsers[win].knownFrames) { this.messageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {}); this.globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {}); } } let winEnum = this.getWinEnumerator(); while (winEnum.hasMoreElements()) { winEnum.getNext().messageManager.removeDelayedFrameScript("chrome://marionette/content/marionette-listener.js"); winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT); } } this.sendOk(); this.messageManager.removeMessageListener("Marionette:ok", this); this.messageManager.removeMessageListener("Marionette:done", this); this.messageManager.removeMessageListener("Marionette:error", this); this.messageManager.removeMessageListener("Marionette:log", this); this.messageManager.removeMessageListener("Marionette:shareData", this); this.messageManager.removeMessageListener("Marionette:register", this); this.messageManager.removeMessageListener("Marionette:goUrl", this); this.messageManager.removeMessageListener("Marionette:runEmulatorCmd", this); this.removeMessageManagerListeners(this.globalMessageManager); this.switchToGlobalMessageManager(); this.curBrowser = null; try { this.importedScripts.remove(false); Loading Loading @@ -1415,6 +1488,15 @@ MarionetteDriverActor.prototype = { } }, /** * Helper function to convert an outerWindowID into a UID that Marionette * tracks. */ generateFrameId: function MDA_generateFrameId(id) { let uid = id + (appName == "B2G" ? "-b2g" : ""); return uid; }, /** * Receives all messages from content messageManager */ Loading Loading @@ -1449,12 +1531,58 @@ MarionetteDriverActor.prototype = { case "Marionette:runEmulatorCmd": this.sendToClient(message.json); break; case "Marionette:switchToFrame": // Switch to a remote frame. for (let i = 0; i < remoteFrames.length; i++) { let frame = remoteFrames[i]; if ((frame.windowId == message.json.win) && (frame.frameId == message.json.frame)) { // The frame script has already been loaded in this frame, so just wake it up. this.currentRemoteFrame = frame; this.messageManager = frame.messageManager; this.addMessageManagerListeners(this.messageManager); this.messageManager.sendAsyncMessage("Marionette:restart", {}); return; } } // Load the frame script in this frame, and set the frame's ChromeMessageSender // as the active message manager. let thisWin = this.getCurrentWindow(); let frameWindow = thisWin.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils) .getOuterWindowWithId(message.json.win); let thisFrame = frameWindow.document.getElementsByTagName("iframe")[message.json.frame]; let mm = thisFrame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager this.addMessageManagerListeners(mm); mm.loadFrameScript(FRAME_SCRIPT, true); this.messageManager = mm; let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame); aFrame.messageManager = this.messageManager; remoteFrames.push(aFrame); this.currentRemoteFrame = aFrame; break; case "Marionette:register": // This code processes the content listener's registration information // and either accepts the listener, or ignores it let nullPrevious = (this.curBrowser.curFrameId == null); let curWin = this.getCurrentWindow(); let frameObject = curWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).getOuterWindowWithId(message.json.value); let listenerWindow = curWin.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils) .getOuterWindowWithId(message.json.value); if (listenerWindow.location.href != message.json.href) { // If there is a mismatch between the calculated href and the one // sent from the frame script, it means that the frame script is // running in a separate process. Currently this only happens // in B2G for OOP frames registered in Marionette:switchToFrame, so // we'll acknowledge the switchToFrame message here. // XXX: Should have a better way of determining that this message // is from a remote frame. this.sendOk(); this.currentRemoteFrame.targetFrameId = this.generateFrameId(message.json.value); } let browserType; try { browserType = message.target.getAttribute("type"); Loading @@ -1463,9 +1591,10 @@ MarionetteDriverActor.prototype = { } let reg; if (!browserType || browserType != "content") { reg = this.curBrowser.register(message.json.value, message.json.href); reg = this.curBrowser.register(this.generateFrameId(message.json.value), message.json.href); } this.curBrowser.elementManager.seenItems[reg] = frameObject; //add to seenItems this.curBrowser.elementManager.seenItems[reg] = listenerWindow; //add to seenItems if (nullPrevious && (this.curBrowser.curFrameId != null)) { this.sendAsync("newSession", {B2G: (appName == "B2G")}); if (this.curBrowser.newSession) { Loading Loading @@ -1545,8 +1674,6 @@ function BrowserObj(win) { this.curFrameId = null; this.startPage = "about:blank"; this.mainContentId = null; // used in B2G to identify the homescreen content page this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); this.newSession = true; //used to set curFrameId upon new session this.elementManager = new ElementManager([SELECTOR, NAME, LINK_TEXT, PARTIAL_LINK_TEXT]); this.setBrowser(win); Loading Loading @@ -1642,15 +1769,15 @@ BrowserObj.prototype = { * if it is not already assigned, and if a) we already have a session * or b) we're starting a new session and it is the right start frame. * * @param string id * frame id * @param string uid * frame uid * @param string href * frame's href */ register: function BO_register(id, href) { let uid = id + ((appName == "B2G") ? '-b2g' : ''); register: function BO_register(uid, href) { if (this.curFrameId == null) { if ((!this.newSession) || (this.newSession && ((appName != "Firefox") || href.indexOf(this.startPage) > -1))) { if ((!this.newSession) || (this.newSession && ((appName != "Firefox") || href.indexOf(this.startPage) > -1))) { this.curFrameId = uid; this.mainContentId = uid; } Loading testing/marionette/marionette-listener.js +22 −10 Original line number Diff line number Diff line Loading @@ -747,28 +747,31 @@ function switchToFrame(msg) { } } } let frames = curWindow.document.getElementsByTagName("iframe"); switch(typeof(msg.json.value)) { case "string" : let foundById = null; let numFrames = curWindow.frames.length; for (let i = 0; i < numFrames; i++) { for (let i = 0; i < frames.length; i++) { //give precedence to name let frame = curWindow.frames[i]; let frameElement = frame.frameElement; if (frameElement.name == msg.json.value) { let frame = frames[i]; let name = utils.getElementAttribute(frame, 'name'); let id = utils.getElementAttribute(frame, 'id'); if (name == msg.json.value) { foundFrame = i; break; } else if ((foundById == null) && (frameElement.id == msg.json.value)) { } else if ((foundById == null) && (id == msg.json.value)) { foundById = i; } } if ((foundFrame == null) && (foundById != null)) { foundFrame = foundById; curWindow = frames[foundFrame]; } break; case "number": if (curWindow.frames[msg.json.value] != undefined) { if (frames[msg.json.value] != undefined) { foundFrame = msg.json.value; curWindow = frames[foundFrame]; } break; } Loading @@ -776,11 +779,20 @@ function switchToFrame(msg) { sendError("Unable to locate frame: " + msg.json.value, 8, null); return; } curWindow = curWindow.frames[foundFrame]; curWindow.focus(); sendOk(); sandbox = null; if (curWindow.contentWindow == null) { // The frame we want to switch to is a remote frame; notify our parent to handle // the switch. curWindow = content; sendToServer('Marionette:switchToFrame', {win: winUtil.outerWindowID, frame: foundFrame}); } else { curWindow = curWindow.contentWindow; curWindow.focus(); sendOk(); } } // emulator callbacks Loading Loading
testing/marionette/marionette-actors.js +168 −41 Original line number Diff line number Diff line Loading @@ -8,6 +8,8 @@ * Gecko-specific actors. */ const FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js"; let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] Loading Loading @@ -94,8 +96,8 @@ MarionetteRootActor.prototype = { getMarionetteID: function MRA_getMarionette() { return { "from": "root", "id": this._marionetteActor.actorID } ; }, } }; // register the calls MarionetteRootActor.prototype.requestTypes = { Loading @@ -103,6 +105,19 @@ MarionetteRootActor.prototype.requestTypes = { "sayHello": MarionetteRootActor.prototype.sayHello }; /** * An object representing a frame that Marionette has loaded a * frame script in. */ function MarionetteRemoteFrame(windowId, frameId) { this.windowId = windowId; this.frameId = frameId; this.targetFrameId = null; this.messageManager = null; } // persistent list of remote frames that Marionette has loaded a frame script in let remoteFrames = []; /** * This actor is responsible for all marionette API calls. It gets created * for each connection and manages all chrome and browser based calls. It Loading @@ -114,8 +129,9 @@ function MarionetteDriverActor(aConnection) .getService(Ci.nsIUUIDGenerator); this.conn = aConnection; this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] this.globalMessageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); this.messageManager = this.globalMessageManager; this.browsers = {}; //holds list of BrowserObjs this.curBrowser = null; // points to current browser this.context = "content"; Loading @@ -127,16 +143,10 @@ function MarionetteDriverActor(aConnection) this.mainFrame = null; //topmost chrome frame this.curFrame = null; //subframe that currently has focus this.importedScripts = FileUtils.getFile('TmpD', ['marionettescriptchrome']); this.currentRemoteFrame = null; // a member of remoteFrames //register all message listeners this.messageManager.addMessageListener("Marionette:ok", this); this.messageManager.addMessageListener("Marionette:done", this); this.messageManager.addMessageListener("Marionette:error", this); this.messageManager.addMessageListener("Marionette:log", this); this.messageManager.addMessageListener("Marionette:shareData", this); this.messageManager.addMessageListener("Marionette:register", this); this.messageManager.addMessageListener("Marionette:goUrl", this); this.messageManager.addMessageListener("Marionette:runEmulatorCmd", this); this.addMessageManagerListeners(this.messageManager); } MarionetteDriverActor.prototype = { Loading @@ -144,6 +154,26 @@ MarionetteDriverActor.prototype = { //name of the actor actorPrefix: "marionette", /** * Helper methods: */ /** * Switches to the global ChromeMessageBroadcaster, potentially replacing a frame-specific * ChromeMessageSender. Has no effect if the global ChromeMessageBroadcaster is already * in use. If this replaces a frame-specific ChromeMessageSender, it removes the message * listeners from that sender, and then puts the corresponding frame script "to sleep", * which removes most of the message listeners from it as well. */ switchToGlobalMessageManager: function MDA_switchToGlobalMM() { if (this.currentRemoteFrame !== null) { this.removeMessageManagerListeners(this.messageManager); this.sendAsync("sleepSession"); } this.messageManager = this.globalMessageManager; this.currentRemoteFrame = null; }, /** * Helper method to send async messages to the content listener * Loading @@ -153,12 +183,51 @@ MarionetteDriverActor.prototype = { * Object to send to the listener */ sendAsync: function MDA_sendAsync(name, values) { this.messageManager.broadcastAsyncMessage("Marionette:" + name + this.curBrowser.curFrameId, values); if (this.currentRemoteFrame !== null) { this.messageManager.sendAsyncMessage( "Marionette:" + name + this.currentRemoteFrame.targetFrameId, values); } else { this.messageManager.broadcastAsyncMessage( "Marionette:" + name + this.curBrowser.curFrameId, values); } }, /** * Helper methods: */ * Adds listeners for messages from content frame scripts. * * @param object messageManager * The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender) * to which the listeners should be added. */ addMessageManagerListeners: function MDA_addMessageManagerListeners(messageManager) { messageManager.addMessageListener("Marionette:ok", this); messageManager.addMessageListener("Marionette:done", this); messageManager.addMessageListener("Marionette:error", this); messageManager.addMessageListener("Marionette:log", this); messageManager.addMessageListener("Marionette:shareData", this); messageManager.addMessageListener("Marionette:register", this); messageManager.addMessageListener("Marionette:runEmulatorCmd", this); messageManager.addMessageListener("Marionette:switchToFrame", this); }, /** * Removes listeners for messages from content frame scripts. * * @param object messageManager * The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender) * from which the listeners should be removed. */ removeMessageManagerListeners: function MDA_removeMessageManagerListeners(messageManager) { messageManager.removeMessageListener("Marionette:ok", this); messageManager.removeMessageListener("Marionette:done", this); messageManager.removeMessageListener("Marionette:error", this); messageManager.removeMessageListener("Marionette:log", this); messageManager.removeMessageListener("Marionette:shareData", this); messageManager.removeMessageListener("Marionette:register", this); messageManager.removeMessageListener("Marionette:runEmulatorCmd", this); messageManager.removeMessageListener("Marionette:switchToFrame", this); }, /** * Generic method to pass a response to the client Loading Loading @@ -316,7 +385,7 @@ MarionetteDriverActor.prototype = { whenBrowserStarted: function MDA_whenBrowserStarted(win, newSession) { try { if (!Services.prefs.getBoolPref("marionette.contentListener") || !newSession) { this.curBrowser.loadFrameScript("chrome://marionette/content/marionette-listener.js", win); this.curBrowser.loadFrameScript(FRAME_SCRIPT, win); } } catch (e) { Loading Loading @@ -377,6 +446,8 @@ MarionetteDriverActor.prototype = { } } this.switchToGlobalMessageManager(); if (!Services.prefs.getBoolPref("marionette.contentListener")) { waitForWindow.call(this); } Loading Loading @@ -968,6 +1039,14 @@ MarionetteDriverActor.prototype = { } } else { if ((aRequest.value == null) && (aRequest.element == null) && (this.currentRemoteFrame !== null)) { // We're currently using a ChromeMessageSender for a remote frame, so this // request indicates we need to switch back to the top-level (parent) frame. // We'll first switch to the parent's (global) ChromeMessageBroadcaster, so // we send the message to the right listener. this.switchToGlobalMessageManager(); } this.sendAsync("switchToFrame", aRequest); } }, Loading Loading @@ -1302,7 +1381,7 @@ MarionetteDriverActor.prototype = { } try{ this.messageManager.removeDelayedFrameScript("chrome://marionette/content/marionette-listener.js"); this.messageManager.removeDelayedFrameScript(FRAME_SCRIPT); this.getCurrentWindow().close(); this.sendOk(); } Loading @@ -1324,7 +1403,7 @@ MarionetteDriverActor.prototype = { deleteSession: function MDA_deleteSession() { if (this.curBrowser != null) { if (appName == "B2G") { this.messageManager.broadcastAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {}); this.globalMessageManager.broadcastAsyncMessage("Marionette:sleepSession" + this.curBrowser.mainContentId, {}); this.curBrowser.knownFrames.splice(this.curBrowser.knownFrames.indexOf(this.curBrowser.mainContentId), 1); } else { Loading @@ -1335,23 +1414,17 @@ MarionetteDriverActor.prototype = { //delete session in each frame in each browser for (let win in this.browsers) { for (let i in this.browsers[win].knownFrames) { this.messageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {}); this.globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {}); } } let winEnum = this.getWinEnumerator(); while (winEnum.hasMoreElements()) { winEnum.getNext().messageManager.removeDelayedFrameScript("chrome://marionette/content/marionette-listener.js"); winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT); } } this.sendOk(); this.messageManager.removeMessageListener("Marionette:ok", this); this.messageManager.removeMessageListener("Marionette:done", this); this.messageManager.removeMessageListener("Marionette:error", this); this.messageManager.removeMessageListener("Marionette:log", this); this.messageManager.removeMessageListener("Marionette:shareData", this); this.messageManager.removeMessageListener("Marionette:register", this); this.messageManager.removeMessageListener("Marionette:goUrl", this); this.messageManager.removeMessageListener("Marionette:runEmulatorCmd", this); this.removeMessageManagerListeners(this.globalMessageManager); this.switchToGlobalMessageManager(); this.curBrowser = null; try { this.importedScripts.remove(false); Loading Loading @@ -1415,6 +1488,15 @@ MarionetteDriverActor.prototype = { } }, /** * Helper function to convert an outerWindowID into a UID that Marionette * tracks. */ generateFrameId: function MDA_generateFrameId(id) { let uid = id + (appName == "B2G" ? "-b2g" : ""); return uid; }, /** * Receives all messages from content messageManager */ Loading Loading @@ -1449,12 +1531,58 @@ MarionetteDriverActor.prototype = { case "Marionette:runEmulatorCmd": this.sendToClient(message.json); break; case "Marionette:switchToFrame": // Switch to a remote frame. for (let i = 0; i < remoteFrames.length; i++) { let frame = remoteFrames[i]; if ((frame.windowId == message.json.win) && (frame.frameId == message.json.frame)) { // The frame script has already been loaded in this frame, so just wake it up. this.currentRemoteFrame = frame; this.messageManager = frame.messageManager; this.addMessageManagerListeners(this.messageManager); this.messageManager.sendAsyncMessage("Marionette:restart", {}); return; } } // Load the frame script in this frame, and set the frame's ChromeMessageSender // as the active message manager. let thisWin = this.getCurrentWindow(); let frameWindow = thisWin.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils) .getOuterWindowWithId(message.json.win); let thisFrame = frameWindow.document.getElementsByTagName("iframe")[message.json.frame]; let mm = thisFrame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager this.addMessageManagerListeners(mm); mm.loadFrameScript(FRAME_SCRIPT, true); this.messageManager = mm; let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame); aFrame.messageManager = this.messageManager; remoteFrames.push(aFrame); this.currentRemoteFrame = aFrame; break; case "Marionette:register": // This code processes the content listener's registration information // and either accepts the listener, or ignores it let nullPrevious = (this.curBrowser.curFrameId == null); let curWin = this.getCurrentWindow(); let frameObject = curWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).getOuterWindowWithId(message.json.value); let listenerWindow = curWin.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils) .getOuterWindowWithId(message.json.value); if (listenerWindow.location.href != message.json.href) { // If there is a mismatch between the calculated href and the one // sent from the frame script, it means that the frame script is // running in a separate process. Currently this only happens // in B2G for OOP frames registered in Marionette:switchToFrame, so // we'll acknowledge the switchToFrame message here. // XXX: Should have a better way of determining that this message // is from a remote frame. this.sendOk(); this.currentRemoteFrame.targetFrameId = this.generateFrameId(message.json.value); } let browserType; try { browserType = message.target.getAttribute("type"); Loading @@ -1463,9 +1591,10 @@ MarionetteDriverActor.prototype = { } let reg; if (!browserType || browserType != "content") { reg = this.curBrowser.register(message.json.value, message.json.href); reg = this.curBrowser.register(this.generateFrameId(message.json.value), message.json.href); } this.curBrowser.elementManager.seenItems[reg] = frameObject; //add to seenItems this.curBrowser.elementManager.seenItems[reg] = listenerWindow; //add to seenItems if (nullPrevious && (this.curBrowser.curFrameId != null)) { this.sendAsync("newSession", {B2G: (appName == "B2G")}); if (this.curBrowser.newSession) { Loading Loading @@ -1545,8 +1674,6 @@ function BrowserObj(win) { this.curFrameId = null; this.startPage = "about:blank"; this.mainContentId = null; // used in B2G to identify the homescreen content page this.messageManager = Cc["@mozilla.org/globalmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); this.newSession = true; //used to set curFrameId upon new session this.elementManager = new ElementManager([SELECTOR, NAME, LINK_TEXT, PARTIAL_LINK_TEXT]); this.setBrowser(win); Loading Loading @@ -1642,15 +1769,15 @@ BrowserObj.prototype = { * if it is not already assigned, and if a) we already have a session * or b) we're starting a new session and it is the right start frame. * * @param string id * frame id * @param string uid * frame uid * @param string href * frame's href */ register: function BO_register(id, href) { let uid = id + ((appName == "B2G") ? '-b2g' : ''); register: function BO_register(uid, href) { if (this.curFrameId == null) { if ((!this.newSession) || (this.newSession && ((appName != "Firefox") || href.indexOf(this.startPage) > -1))) { if ((!this.newSession) || (this.newSession && ((appName != "Firefox") || href.indexOf(this.startPage) > -1))) { this.curFrameId = uid; this.mainContentId = uid; } Loading
testing/marionette/marionette-listener.js +22 −10 Original line number Diff line number Diff line Loading @@ -747,28 +747,31 @@ function switchToFrame(msg) { } } } let frames = curWindow.document.getElementsByTagName("iframe"); switch(typeof(msg.json.value)) { case "string" : let foundById = null; let numFrames = curWindow.frames.length; for (let i = 0; i < numFrames; i++) { for (let i = 0; i < frames.length; i++) { //give precedence to name let frame = curWindow.frames[i]; let frameElement = frame.frameElement; if (frameElement.name == msg.json.value) { let frame = frames[i]; let name = utils.getElementAttribute(frame, 'name'); let id = utils.getElementAttribute(frame, 'id'); if (name == msg.json.value) { foundFrame = i; break; } else if ((foundById == null) && (frameElement.id == msg.json.value)) { } else if ((foundById == null) && (id == msg.json.value)) { foundById = i; } } if ((foundFrame == null) && (foundById != null)) { foundFrame = foundById; curWindow = frames[foundFrame]; } break; case "number": if (curWindow.frames[msg.json.value] != undefined) { if (frames[msg.json.value] != undefined) { foundFrame = msg.json.value; curWindow = frames[foundFrame]; } break; } Loading @@ -776,11 +779,20 @@ function switchToFrame(msg) { sendError("Unable to locate frame: " + msg.json.value, 8, null); return; } curWindow = curWindow.frames[foundFrame]; curWindow.focus(); sendOk(); sandbox = null; if (curWindow.contentWindow == null) { // The frame we want to switch to is a remote frame; notify our parent to handle // the switch. curWindow = content; sendToServer('Marionette:switchToFrame', {win: winUtil.outerWindowID, frame: foundFrame}); } else { curWindow = curWindow.contentWindow; curWindow.focus(); sendOk(); } } // emulator callbacks Loading