Bug 757182 - Handle window.close in <iframe mozbrowser>. r=smaug
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6356,17 +6356,22 @@ nsGlobalWindow::CanClose()
return true;
}
NS_IMETHODIMP
nsGlobalWindow::Close()
{
FORWARD_TO_OUTER(Close, (), NS_ERROR_NOT_INITIALIZED);
- if (IsFrame() || !mDocShell || IsInModalState()) {
+ bool isMozBrowser = false;
+ if (mDocShell) {
+ mDocShell->GetIsBrowserFrame(&isMozBrowser);
+ }
+
+ if ((!isMozBrowser && IsFrame()) || !mDocShell || IsInModalState()) {
// window.close() is called on a frame in a frameset, on a window
// that's already closed, or on a window for which there's
// currently a modal dialog open. Ignore such calls.
return NS_OK;
}
if (mHavePendingClose) {
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -3,16 +3,17 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let Cu = Components.utils;
let Ci = Components.interfaces;
let Cc = Components.classes;
let Cr = Components.results;
+
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
// Event whitelisted for bubbling.
let whitelistedEvents = [
Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE, // Back button.
Ci.nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU,
@@ -42,20 +43,20 @@ function sendSyncMsg(msg, data) {
*
* Our job here is to listen for events within this frame and bubble them up to
* the parent process.
*/
var global = this;
function BrowserElementChild() {
- this._init();
-
// Maps outer window id --> weak ref to window. Used by modal dialog code.
this._windowIDDict = {};
+
+ this._init();
};
BrowserElementChild.prototype = {
_init: function() {
debug("Starting up.");
sendAsyncMsg("hello");
BrowserElementPromptService.mapWindowToBrowserElementChild(content, this);
@@ -113,16 +114,19 @@ BrowserElementChild.prototype = {
this._keyEventHandler.bind(this),
/* useCapture = */ true);
els.addSystemEventListener(global, 'keypress',
this._keyEventHandler.bind(this),
/* useCapture = */ true);
els.addSystemEventListener(global, 'keyup',
this._keyEventHandler.bind(this),
/* useCapture = */ true);
+ els.addSystemEventListener(global, 'DOMWindowClose',
+ this._closeHandler.bind(this),
+ /* useCapture = */ false);
},
_tryGetInnerWindowID: function(win) {
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
try {
return utils.currentInnerWindowID;
}
@@ -278,16 +282,29 @@ BrowserElementChild.prototype = {
sendAsyncMsg('iconchange', e.target.href);
}
else {
debug("Not top level!");
}
}
},
+ _closeHandler: function(e) {
+ let win = e.target;
+ if (win != content || e.defaultPrevented) {
+ return;
+ }
+
+ debug("Closing window " + win);
+ sendAsyncMsg('close');
+
+ // Inform the window implementation that we handled this close ourselves.
+ e.preventDefault();
+ },
+
_recvGetScreenshot: function(data) {
debug("Received getScreenshot message: (" + data.json.id + ")");
var canvas = content.document
.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
var ctx = canvas.getContext("2d");
canvas.mozOpaque = true;
canvas.height = content.innerHeight;
canvas.width = content.innerWidth;
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -107,16 +107,17 @@ BrowserElementParent.prototype = {
}
addMessageListener("hello", this._recvHello);
addMessageListener("locationchange", this._fireEventFromMsg);
addMessageListener("loadstart", this._fireEventFromMsg);
addMessageListener("loadend", this._fireEventFromMsg);
addMessageListener("titlechange", this._fireEventFromMsg);
addMessageListener("iconchange", this._fireEventFromMsg);
+ addMessageListener("close", this._fireEventFromMsg);
addMessageListener("get-mozapp-manifest-url", this._sendMozAppManifestURL);
addMessageListener("keyevent", this._fireKeyEvent);
addMessageListener("showmodalprompt", this._handleShowModalPrompt);
mm.addMessageListener('browser-element-api:got-screenshot',
this._recvGotScreenshot.bind(this));
XPCNativeWrapper.unwrap(frameElement).getScreenshot =
this._getScreenshot.bind(this, mm, frameElement);
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -25,12 +25,13 @@ include $(topsrcdir)/config/rules.mk
test_browserFrame7.html \
test_browserFrame8.html \
test_browserFrame9.html \
test_browserFrame10.html \
test_browserFrame_keyEvents.html \
test_browserFrameAlert.html \
test_browserFramePromptCheck.html \
test_browserFramePromptConfirm.html \
+ test_browserFrameClose.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserFrameClose.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=757182
+-->
+<head>
+ <title>Test for Bug 757182</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="browserFrameHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=757182">Mozilla Bug 757182</a>
+
+<!--
+ Test that window.close() works.
+-->
+
+<script type="application/javascript;version=1.7">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ browserFrameHelpers.setEnabledPref(true);
+ browserFrameHelpers.addToWhitelist();
+
+ var iframe = document.createElement('iframe');
+ iframe.mozbrowser = true;
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener("mozbrowserclose", function(e) {
+ ok(true, "got mozbrowserclose event.");
+ SimpleTest.finish();
+ });
+
+ iframe.src = "data:text/html,<html><body><script>window.close()</scr"+"ipt></body></html>";
+}
+
+runTest();
+</script>
+</body>
+</html>