diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js
index 3e7ed5821c..b063f79a80 100644
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -33,6 +33,9 @@ Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Screenshot",
+ "resource://gre/modules/Screenshot.jsm");
+
Cu.import('resource://gre/modules/Webapps.jsm');
DOMApplicationRegistry.allAppsLaunchable = true;
@@ -818,30 +821,9 @@ window.addEventListener('ContentStart', function ss_onContentStart() {
return;
try {
- var canvas = document.createElementNS('http://www.w3.org/1999/xhtml',
- 'canvas');
- var docRect = document.body.getBoundingClientRect();
- var width = docRect.width;
- var height = docRect.height;
-
- // Convert width and height from CSS pixels (potentially fractional)
- // to device pixels (integer).
- var scale = window.devicePixelRatio;
- canvas.setAttribute('width', Math.round(width * scale));
- canvas.setAttribute('height', Math.round(height * scale));
-
- var context = canvas.getContext('2d');
- var flags =
- context.DRAWWINDOW_DRAW_CARET |
- context.DRAWWINDOW_DRAW_VIEW |
- context.DRAWWINDOW_USE_WIDGET_LAYERS;
- context.scale(scale, scale);
- context.drawWindow(window, 0, 0, width, height,
- 'rgb(255,255,255)', flags);
-
shell.sendChromeEvent({
type: 'take-screenshot-success',
- file: canvas.mozGetAsFile('screenshot', 'image/png')
+ file: Screenshot.get()
});
} catch (e) {
dump('exception while creating screenshot: ' + e + '\n');
diff --git a/b2g/components/Frames.jsm b/b2g/components/Frames.jsm
index e84c2f247c..96745bbe25 100644
--- a/b2g/components/Frames.jsm
+++ b/b2g/components/Frames.jsm
@@ -25,7 +25,7 @@ const Observer = {
start: function () {
Services.obs.addObserver(this, 'remote-browser-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
- Services.obs.addObserver(this, 'message-manager-disconnect', false);
+ Services.obs.addObserver(this, 'message-manager-close', false);
SystemAppProxy.getFrames().forEach(frame => {
let mm = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
@@ -40,7 +40,7 @@ const Observer = {
stop: function () {
Services.obs.removeObserver(this, 'remote-browser-shown');
Services.obs.removeObserver(this, 'inprocess-browser-shown');
- Services.obs.removeObserver(this, 'message-manager-disconnect');
+ Services.obs.removeObserver(this, 'message-manager-close');
this._frames.clear();
this._apps.clear();
},
@@ -61,7 +61,7 @@ const Observer = {
break;
// Every time an iframe is destroyed, its message manager also is
- case 'message-manager-disconnect':
+ case 'message-manager-close':
this.onMessageManagerDestroyed(subject);
break;
}
diff --git a/b2g/components/LogCapture.jsm b/b2g/components/LogCapture.jsm
index e8a0cec2f2..fbd87888f3 100644
--- a/b2g/components/LogCapture.jsm
+++ b/b2g/components/LogCapture.jsm
@@ -13,6 +13,7 @@ const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", "resource://gre/modules/Screenshot.jsm");
this.EXPORTED_SYMBOLS = ["LogCapture"];
@@ -185,6 +186,26 @@ let LogCapture = {
deferred.resolve(file);
}, null, false);
+ return deferred.promise;
+ },
+
+ /**
+ * Dumping screenshot, returning a Promise. Will be resolved with the content
+ * as an ArrayBuffer.
+ */
+ getScreenshot: function() {
+ this.ensureLoaded();
+ let deferred = Promise.defer();
+
+ let fr = Cc["@mozilla.org/files/filereader;1"]
+ .createInstance(Ci.nsIDOMFileReader);
+
+ fr.onload = function(evt) {
+ deferred.resolve(new Uint8Array(evt.target.result));
+ };
+
+ fr.readAsArrayBuffer(Screenshot.get());
+
return deferred.promise;
}
};
diff --git a/b2g/components/LogShake.jsm b/b2g/components/LogShake.jsm
index 6b846d87dd..548797a0b5 100644
--- a/b2g/components/LogShake.jsm
+++ b/b2g/components/LogShake.jsm
@@ -240,6 +240,14 @@ let LogShake = {
Cu.reportError("Unable to get about:memory dump: " + ex);
}
+ try {
+ LogCapture.getScreenshot().then(screenshot => {
+ logArrays["logshake-screenshot.png"] = screenshot;
+ });
+ } catch (ex) {
+ Cu.reportError("Unable to get screenshot dump: " + ex);
+ }
+
for (let loc in this.LOGS_WITH_PARSERS) {
let logArray;
try {
diff --git a/b2g/components/Screenshot.jsm b/b2g/components/Screenshot.jsm
new file mode 100644
index 0000000000..adf08ac68c
--- /dev/null
+++ b/b2g/components/Screenshot.jsm
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", "resource://gre/modules/SystemAppProxy.jsm");
+
+this.EXPORTED_SYMBOLS = ['Screenshot'];
+
+let Screenshot = {
+ get: function screenshot_get() {
+ let systemAppFrame = SystemAppProxy.getFrame();
+ let window = systemAppFrame.ownerDocument.defaultView;
+ let document = window.document;
+
+ var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
+ var docRect = document.body.getBoundingClientRect();
+ var width = docRect.width;
+ var height = docRect.height;
+
+ // Convert width and height from CSS pixels (potentially fractional)
+ // to device pixels (integer).
+ var scale = window.devicePixelRatio;
+ canvas.setAttribute('width', Math.round(width * scale));
+ canvas.setAttribute('height', Math.round(height * scale));
+
+ var context = canvas.getContext('2d');
+ var flags =
+ context.DRAWWINDOW_DRAW_CARET |
+ context.DRAWWINDOW_DRAW_VIEW |
+ context.DRAWWINDOW_USE_WIDGET_LAYERS;
+ context.scale(scale, scale);
+ context.drawWindow(window, 0, 0, width, height, 'rgb(255,255,255)', flags);
+
+ return canvas.mozGetAsFile('screenshot', 'image/png');
+ }
+};
+this.Screenshot = Screenshot;
diff --git a/b2g/components/SystemAppProxy.jsm b/b2g/components/SystemAppProxy.jsm
index 240e564131..355433d555 100644
--- a/b2g/components/SystemAppProxy.jsm
+++ b/b2g/components/SystemAppProxy.jsm
@@ -29,6 +29,11 @@ let SystemAppProxy = {
this._pendingListeners = [];
},
+ // Get the system app frame
+ getFrame: function () {
+ return this._frame;
+ },
+
// To call when it is ready to receive events
setIsReady: function () {
if (this._isReady) {
diff --git a/b2g/components/moz.build b/b2g/components/moz.build
index 5cef686632..105b59a037 100644
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -60,6 +60,7 @@ EXTRA_JS_MODULES += [
'LogParser.jsm',
'LogShake.jsm',
'OrientationChangeHandler.jsm',
+ 'Screenshot.jsm',
'SignInToWebsite.jsm',
'SystemAppProxy.jsm',
'TelURIParser.jsm',
diff --git a/b2g/components/test/mochitest/mochitest.ini b/b2g/components/test/mochitest/mochitest.ini
index b7fdd8b0b6..b7ffc7d026 100644
--- a/b2g/components/test/mochitest/mochitest.ini
+++ b/b2g/components/test/mochitest/mochitest.ini
@@ -4,6 +4,7 @@ support-files =
permission_handler_chrome.js
SandboxPromptTest.html
filepicker_path_handler_chrome.js
+ screenshot_helper.js
systemapp_helper.js
presentation_prompt_handler_chrome.js
@@ -12,5 +13,6 @@ support-files =
[test_permission_gum_remember.html]
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
+[test_screenshot.html]
[test_systemapp.html]
[test_presentation_device_prompt.html]
diff --git a/b2g/components/test/mochitest/screenshot_helper.js b/b2g/components/test/mochitest/screenshot_helper.js
new file mode 100644
index 0000000000..d10234f928
--- /dev/null
+++ b/b2g/components/test/mochitest/screenshot_helper.js
@@ -0,0 +1,38 @@
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+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/Screenshot.jsm", scope);
+const { Screenshot } = scope;
+
+let index = -1;
+function next() {
+ index++;
+ if (index >= steps.length) {
+ assert.ok(false, "Shouldn't get here!");
+ return;
+ }
+ try {
+ steps[index]();
+ } catch(ex) {
+ assert.ok(false, "Caught exception: " + ex);
+ }
+}
+
+let steps = [
+ function getScreenshot() {
+ let screenshot = Screenshot.get();
+ assert.ok(screenshot instanceof Ci.nsIDOMFile,
+ "Screenshot.get() returns a File");
+ next();
+ },
+
+ function endOfTest() {
+ sendAsyncMessage("finish");
+ }
+];
+
+next();
diff --git a/b2g/components/test/mochitest/systemapp_helper.js b/b2g/components/test/mochitest/systemapp_helper.js
index 80e30b0096..c5c9ef0610 100644
--- a/b2g/components/test/mochitest/systemapp_helper.js
+++ b/b2g/components/test/mochitest/systemapp_helper.js
@@ -113,6 +113,9 @@ let steps = [
SystemAppProxy.setIsReady();
assert.ok(true, "Frame declared as loaded");
+ let gotFrame = SystemAppProxy.getFrame();
+ assert.equal(gotFrame, frame, "getFrame returns the frame we passed");
+
// Once pending events are received,
// we will run checkEventDispatching from `listener` function
});
diff --git a/b2g/components/test/mochitest/test_screenshot.html b/b2g/components/test/mochitest/test_screenshot.html
new file mode 100644
index 0000000000..d2eeb8d483
--- /dev/null
+++ b/b2g/components/test/mochitest/test_screenshot.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+ Screenshot Test
+
+
+
+
+Screenshot.jsm
+
+
+
+
diff --git a/b2g/components/test/unit/test_logcapture_gonk.js b/b2g/components/test/unit/test_logcapture_gonk.js
index 123ca69865..da64d86a82 100644
--- a/b2g/components/test/unit/test_logcapture_gonk.js
+++ b/b2g/components/test/unit/test_logcapture_gonk.js
@@ -45,7 +45,6 @@ add_test(function test_readAppIni() {
run_next_test();
});
-
add_test(function test_get_about_memory() {
let memLog = LogCapture.readAboutMemory();
diff --git a/browser/base/content/aboutDialog.css b/browser/base/content/aboutDialog.css
index aa79b0795c..4d3e4424ed 100644
--- a/browser/base/content/aboutDialog.css
+++ b/browser/base/content/aboutDialog.css
@@ -32,7 +32,6 @@
#distribution,
#distributionId {
- font-weight: bold;
display: none;
margin-top: 0;
margin-bottom: 0;
diff --git a/config/config.mk b/config/config.mk
index fccd569fcb..deb4edbbb2 100644
--- a/config/config.mk
+++ b/config/config.mk
@@ -387,24 +387,16 @@ endif # CROSS_COMPILE
CFLAGS += $(MOZ_FRAMEPTR_FLAGS)
CXXFLAGS += $(MOZ_FRAMEPTR_FLAGS)
-# Check for FAIL_ON_WARNINGS & FAIL_ON_WARNINGS_DEBUG (Shorthand for Makefiles
-# to request that we use the 'warnings as errors' compile flags)
+# Check for FAIL_ON_WARNINGS (Shorthand for Makefiles to request that we use
+# the 'warnings as errors' compile flags)
# NOTE: First, we clear FAIL_ON_WARNINGS[_DEBUG] if we're doing a Windows PGO
# build, since WARNINGS_AS_ERRORS has been suspected of causing isuses in that
# situation. (See bug 437002.)
ifeq (WINNT_1,$(OS_ARCH)_$(MOZ_PROFILE_GENERATE)$(MOZ_PROFILE_USE))
-FAIL_ON_WARNINGS_DEBUG=
FAIL_ON_WARNINGS=
endif # WINNT && (MOS_PROFILE_GENERATE ^ MOZ_PROFILE_USE)
-# Now, check for debug version of flag; it turns on normal flag in debug builds.
-ifdef FAIL_ON_WARNINGS_DEBUG
-ifdef MOZ_DEBUG
-FAIL_ON_WARNINGS = 1
-endif # MOZ_DEBUG
-endif # FAIL_ON_WARNINGS_DEBUG
-
# Check for normal version of flag, and add WARNINGS_AS_ERRORS if it's set to 1.
ifdef FAIL_ON_WARNINGS
# Never treat warnings as errors in clang-cl, because it warns about many more
diff --git a/configure.in b/configure.in
index 0185fee305..b592e842d3 100644
--- a/configure.in
+++ b/configure.in
@@ -418,6 +418,30 @@ MOZ_TOOL_VARIABLES
MOZ_CHECK_COMPILER_WRAPPER
+dnl ========================================================
+dnl Check for MacOS deployment target version
+dnl ========================================================
+
+MOZ_ARG_ENABLE_STRING(macos-target,
+ [ --enable-macos-target=VER (default=10.6)
+ Set the minimum MacOS version needed at runtime],
+ [_MACOSX_DEPLOYMENT_TARGET=$enableval])
+
+case "$target" in
+*-darwin*)
+ if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then
+ dnl Use the specified value
+ export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET
+ else
+ dnl No value specified on the command line or in the environment,
+ dnl use architecture minimum.
+ export MACOSX_DEPLOYMENT_TARGET=10.6
+ fi
+ ;;
+esac
+
+AC_SUBST(MACOSX_DEPLOYMENT_TARGET)
+
dnl ========================================================
dnl Special win32 checks
dnl ========================================================
@@ -839,30 +863,6 @@ if test -n "$UNIVERSAL_BINARY"; then
fi
AC_SUBST(UNIFY_DIST)
-dnl ========================================================
-dnl Check for MacOS deployment target version
-dnl ========================================================
-
-MOZ_ARG_ENABLE_STRING(macos-target,
- [ --enable-macos-target=VER (default=10.6)
- Set the minimum MacOS version needed at runtime],
- [_MACOSX_DEPLOYMENT_TARGET=$enableval])
-
-case "$target" in
-*-darwin*)
- if test -n "$_MACOSX_DEPLOYMENT_TARGET" ; then
- dnl Use the specified value
- export MACOSX_DEPLOYMENT_TARGET=$_MACOSX_DEPLOYMENT_TARGET
- else
- dnl No value specified on the command line or in the environment,
- dnl use architecture minimum.
- export MACOSX_DEPLOYMENT_TARGET=10.6
- fi
- ;;
-esac
-
-AC_SUBST(MACOSX_DEPLOYMENT_TARGET)
-
dnl ========================================================
dnl = Mac OS X SDK support
dnl ========================================================
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 80ac8c7769..1e161b2e26 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -31,6 +31,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/Base64.h"
+#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/DocumentFragment.h"
@@ -994,19 +995,29 @@ nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
}
bool foundValue = false;
- int32_t value = 0;
- int32_t pValue = 0; // Previous value, used to check integer overflow
+ CheckedInt32 value = 0;
+
+ // Check for leading zeros first.
+ uint64_t leadingZeros = 0;
+ while (iter != end) {
+ if (*iter != char16_t('0')) {
+ break;
+ }
+
+ ++leadingZeros;
+ foundValue = true;
+ ++iter;
+ }
+
while (iter != end) {
if (*iter >= char16_t('0') && *iter <= char16_t('9')) {
value = (value * 10) + (*iter - char16_t('0'));
++iter;
- // Checking for integer overflow.
- if (pValue > value) {
+ if (!value.isValid()) {
result |= eParseHTMLInteger_Error | eParseHTMLInteger_ErrorOverflow;
break;
} else {
foundValue = true;
- pValue = value;
}
} else if (*iter == char16_t('%')) {
++iter;
@@ -1024,17 +1035,21 @@ nsContentUtils::ParseHTMLInteger(const nsAString& aValue,
if (negate) {
value = -value;
// Checking the special case of -0.
- if (!value) {
+ if (value == 0) {
result |= eParseHTMLInteger_NonStandard;
}
}
+ if (leadingZeros > 1 || (leadingZeros == 1 && !(value == 0))) {
+ result |= eParseHTMLInteger_NonStandard;
+ }
+
if (iter != end) {
result |= eParseHTMLInteger_DidNotConsumeAllInput;
}
*aResult = (ParseHTMLIntegerResultFlags)result;
- return value;
+ return value.value();
}
#define SKIP_WHITESPACE(iter, end_iter, end_res) \
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index fd05f73052..f4f21947cb 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -366,6 +366,8 @@ public:
enum ParseHTMLIntegerResultFlags {
eParseHTMLInteger_NoFlags = 0,
eParseHTMLInteger_IsPercent = 1 << 0,
+ // eParseHTMLInteger_NonStandard is set if the string representation of the
+ // integer was not the canonical one (e.g. had extra leading '+' or '0').
eParseHTMLInteger_NonStandard = 1 << 1,
eParseHTMLInteger_DidNotConsumeAllInput = 1 << 2,
// Set if one or more error flags were set.
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index 638ab1135c..06cee13eb4 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -490,7 +490,7 @@ nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX,
}
NS_IMETHODIMP
-nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
+nsDOMWindowUtils::SetResolution(float aResolution)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
@@ -503,15 +503,15 @@ nsDOMWindowUtils::SetResolution(float aXResolution, float aYResolution)
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
if (sf) {
- sf->SetResolution(gfxSize(aXResolution, aYResolution));
- presShell->SetResolution(aXResolution, aYResolution);
+ sf->SetResolution(aResolution);
+ presShell->SetResolution(aResolution);
}
return NS_OK;
}
NS_IMETHODIMP
-nsDOMWindowUtils::SetResolutionAndScaleTo(float aXResolution, float aYResolution)
+nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
@@ -524,15 +524,15 @@ nsDOMWindowUtils::SetResolutionAndScaleTo(float aXResolution, float aYResolution
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
if (sf) {
- sf->SetResolutionAndScaleTo(gfxSize(aXResolution, aYResolution));
- presShell->SetResolutionAndScaleTo(aXResolution, aYResolution);
+ sf->SetResolutionAndScaleTo(aResolution);
+ presShell->SetResolutionAndScaleTo(aResolution);
}
return NS_OK;
}
NS_IMETHODIMP
-nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
+nsDOMWindowUtils::GetResolution(float* aResolution)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
@@ -543,12 +543,9 @@ nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
if (sf) {
- const gfxSize& res = sf->GetResolution();
- *aXResolution = res.width;
- *aYResolution = res.height;
+ *aResolution = sf->GetResolution();
} else {
- *aXResolution = presShell->GetXResolution();
- *aYResolution = presShell->GetYResolution();
+ *aResolution = presShell->GetResolution();
}
return NS_OK;
@@ -2375,6 +2372,18 @@ nsDOMWindowUtils::IsInModalState(bool *retval)
return NS_OK;
}
+NS_IMETHODIMP
+nsDOMWindowUtils::SetDesktopModeViewport(bool aDesktopMode)
+{
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+ nsCOMPtr window = do_QueryReferent(mWindow);
+ NS_ENSURE_STATE(window);
+
+ static_cast(window.get())->SetDesktopModeViewport(aDesktopMode);
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsDOMWindowUtils::GetOuterWindowID(uint64_t *aWindowID)
{
@@ -2928,6 +2937,67 @@ nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResu
return NS_OK;
}
+NS_IMETHODIMP
+nsDOMWindowUtils::IsPartOfOpaqueLayer(nsIDOMElement* aElement, bool* aResult)
+{
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+ if (!aElement) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsresult rv;
+ nsCOMPtr content = do_QueryInterface(aElement, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIFrame* frame = content->GetPrimaryFrame();
+ if (!frame) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Layer* layer = FrameLayerBuilder::GetDebugSingleOldLayerForFrame(frame);
+ if (!layer || !layer->AsPaintedLayer()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *aResult = (layer->GetContentFlags() & Layer::CONTENT_OPAQUE);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::NumberOfAssignedPaintedLayers(nsIDOMElement** aElements,
+ uint32_t aCount,
+ uint32_t* aResult)
+{
+ MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
+
+ if (!aElements) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsTHashtable> layers;
+ nsresult rv;
+ for (uint32_t i = 0; i < aCount; i++) {
+ nsCOMPtr content = do_QueryInterface(aElements[i], &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIFrame* frame = content->GetPrimaryFrame();
+ if (!frame) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Layer* layer = FrameLayerBuilder::GetDebugSingleOldLayerForFrame(frame);
+ if (!layer || !layer->AsPaintedLayer()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ layers.PutEntry(layer->AsPaintedLayer());
+ }
+
+ *aResult = layers.Count();
+ return NS_OK;
+}
+
NS_IMETHODIMP
nsDOMWindowUtils::EnableDialogs()
{
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 038eb26241..4af07dc8ad 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -7311,14 +7311,14 @@ nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader)
}
nsresult
-nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader)
+nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer)
{
mInitializableFrameLoaders.RemoveElement(aLoader);
if (mInDestructor) {
return NS_ERROR_FAILURE;
}
- mFinalizableFrameLoaders.AppendElement(aLoader);
+ mFrameLoaderFinalizers.AppendElement(aFinalizer);
if (!mFrameLoaderRunner) {
mFrameLoaderRunner =
NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders);
@@ -7343,7 +7343,7 @@ nsDocument::MaybeInitializeFinalizeFrameLoaders()
if (!nsContentUtils::IsSafeToRunScript()) {
if (!mInDestructor && !mFrameLoaderRunner &&
(mInitializableFrameLoaders.Length() ||
- mFinalizableFrameLoaders.Length())) {
+ mFrameLoaderFinalizers.Length())) {
mFrameLoaderRunner =
NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders);
nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
@@ -7362,12 +7362,12 @@ nsDocument::MaybeInitializeFinalizeFrameLoaders()
loader->ReallyStartLoading();
}
- uint32_t length = mFinalizableFrameLoaders.Length();
+ uint32_t length = mFrameLoaderFinalizers.Length();
if (length > 0) {
- nsTArray > loaders;
- mFinalizableFrameLoaders.SwapElements(loaders);
+ nsTArray > finalizers;
+ mFrameLoaderFinalizers.SwapElements(finalizers);
for (uint32_t i = 0; i < length; ++i) {
- loaders[i]->Finalize();
+ finalizers[i]->Run();
}
}
}
@@ -7384,20 +7384,6 @@ nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell)
}
}
-bool
-nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell)
-{
- if (aShell) {
- uint32_t length = mFinalizableFrameLoaders.Length();
- for (uint32_t i = 0; i < length; ++i) {
- if (mFinalizableFrameLoaders[i]->GetExistingDocShell() == aShell) {
- return true;
- }
- }
- }
- return false;
-}
-
nsIDocument*
nsDocument::RequestExternalResource(nsIURI* aURI,
nsINode* aRequestingNode,
@@ -7871,6 +7857,15 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
CSSToScreenScale defaultScale = layoutDeviceScale
* LayoutDeviceToScreenScale(1.0);
+ // Get requested Desktopmode
+ nsPIDOMWindow* win = GetWindow();
+ if (win && win->IsDesktopModeViewport())
+ {
+ return nsViewportInfo(aDisplaySize,
+ defaultScale,
+ /*allowZoom*/false,
+ /*allowDoubleTapZoom*/ true);
+ }
if (!Preferences::GetBool("dom.meta-viewport.enabled", false)) {
return nsViewportInfo(aDisplaySize,
diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h
index 5969490e62..cbdfbb91e8 100644
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1034,9 +1034,8 @@ public:
virtual void FlushSkinBindings() override;
virtual nsresult InitializeFrameLoader(nsFrameLoader* aLoader) override;
- virtual nsresult FinalizeFrameLoader(nsFrameLoader* aLoader) override;
+ virtual nsresult FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer) override;
virtual void TryCancelFrameLoaderInitialization(nsIDocShell* aShell) override;
- virtual bool FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell) override;
virtual nsIDocument*
RequestExternalResource(nsIURI* aURI,
nsINode* aRequestingNode,
@@ -1765,7 +1764,7 @@ private:
nsString mLastStyleSheetSet;
nsTArray > mInitializableFrameLoaders;
- nsTArray > mFinalizableFrameLoaders;
+ nsTArray > mFrameLoaderFinalizers;
nsRefPtr > mFrameLoaderRunner;
nsRevocableEventPtr >
diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp
index 2dd2e9f720..0b8c0b988a 100644
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -107,25 +107,6 @@ using namespace mozilla::layers;
using namespace mozilla::layout;
typedef FrameMetrics::ViewID ViewID;
-class nsAsyncDocShellDestroyer : public nsRunnable
-{
-public:
- explicit nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
- : mDocShell(aDocShell)
- {
- }
-
- NS_IMETHOD Run()
- {
- nsCOMPtr base_win(do_QueryInterface(mDocShell));
- if (base_win) {
- base_win->Destroy();
- }
- return NS_OK;
- }
- nsRefPtr mDocShell;
-};
-
// Bug 136580: Limit to the number of nested content frames that can have the
// same URL. This is to stop content that is recursively loading
// itself. Note that "#foo" on the end of URL doesn't affect
@@ -181,7 +162,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
nsFrameLoader::~nsFrameLoader()
{
- mNeedsAsyncDestroy = true;
if (mMessageManager) {
mMessageManager->Disconnect();
}
@@ -523,16 +503,6 @@ nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
return rv;
}
-void
-nsFrameLoader::Finalize()
-{
- nsCOMPtr base_win(do_QueryInterface(mDocShell));
- if (base_win) {
- base_win->Destroy();
- }
- mDocShell = nullptr;
-}
-
static void
FirePageHideEvent(nsIDocShellTreeItem* aItem,
EventTarget* aChromeEventHandler)
@@ -1358,29 +1328,59 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
return NS_OK;
}
-void
-nsFrameLoader::DestroyChild()
-{
- if (mRemoteBrowser) {
- mRemoteBrowser->SetOwnerElement(nullptr);
- mRemoteBrowser->Destroy();
- mRemoteBrowser = nullptr;
- }
-}
-
NS_IMETHODIMP
nsFrameLoader::Destroy()
{
+ StartDestroy();
+ return NS_OK;
+}
+
+class nsFrameLoaderDestroyRunnable : public nsRunnable
+{
+ enum DestroyPhase
+ {
+ // See the implementation of Run for an explanation of these phases.
+ eDestroyDocShell,
+ eWaitForUnloadMessage,
+ eDestroyComplete
+ };
+
+ nsRefPtr mFrameLoader;
+ DestroyPhase mPhase;
+
+public:
+ explicit nsFrameLoaderDestroyRunnable(nsFrameLoader* aFrameLoader)
+ : mFrameLoader(aFrameLoader), mPhase(eDestroyDocShell) {}
+
+ NS_IMETHODIMP Run() override;
+};
+
+void
+nsFrameLoader::StartDestroy()
+{
+ // nsFrameLoader::StartDestroy is called just before the frameloader is
+ // detached from the element. Destruction continues in phases via
+ // the nsFrameLoaderDestroyRunnable.
+
if (mDestroyCalled) {
- return NS_OK;
+ return;
}
mDestroyCalled = true;
+ // After this point, we return an error when trying to send a message using
+ // the message manager on the frame.
if (mMessageManager) {
- mMessageManager->Disconnect();
+ mMessageManager->Close();
}
- if (mChildMessageManager) {
- static_cast(mChildMessageManager.get())->Disconnect();
+
+ // Retain references to the element and the frameloader in case we
+ // receive any messages from the message manager on the frame. These
+ // references are dropped in DestroyComplete.
+ if (mChildMessageManager || mRemoteBrowser) {
+ mOwnerContentStrong = mOwnerContent;
+ if (mRemoteBrowser) {
+ mRemoteBrowser->CacheFrameLoader(this);
+ }
}
nsCOMPtr doc;
@@ -1392,7 +1392,6 @@ nsFrameLoader::Destroy()
SetOwnerContent(nullptr);
}
- DestroyChild();
// Seems like this is a dynamic frame removal.
if (dynamicSubframeRemoval) {
@@ -1412,7 +1411,7 @@ nsFrameLoader::Destroy()
}
}
}
-
+
// Let our window know that we are gone
if (mDocShell) {
nsCOMPtr win_private(mDocShell->GetWindow());
@@ -1421,23 +1420,122 @@ nsFrameLoader::Destroy()
}
}
- if ((mNeedsAsyncDestroy || !doc ||
- NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
- nsCOMPtr event = new nsAsyncDocShellDestroyer(mDocShell);
- NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
- NS_DispatchToCurrentThread(event);
+ nsCOMPtr destroyRunnable = new nsFrameLoaderDestroyRunnable(this);
+ if (mNeedsAsyncDestroy || !doc ||
+ NS_FAILED(doc->FinalizeFrameLoader(this, destroyRunnable))) {
+ NS_DispatchToCurrentThread(destroyRunnable);
+ }
+}
- // Let go of our docshell now that the async destroyer holds on to
- // the docshell.
+nsresult
+nsFrameLoaderDestroyRunnable::Run()
+{
+ switch (mPhase) {
+ case eDestroyDocShell:
+ mFrameLoader->DestroyDocShell();
- mDocShell = nullptr;
+ // In the out-of-process case, TabParent will eventually call
+ // DestroyComplete once it receives a __delete__ message from the child. In
+ // the in-process case, we dispatch a series of runnables to ensure that
+ // DestroyComplete gets called at the right time. The frame loader is kept
+ // alive by mFrameLoader during this time.
+ if (mFrameLoader->mChildMessageManager) {
+ // When the docshell is destroyed, NotifyWindowIDDestroyed is called to
+ // asynchronously notify {outer,inner}-window-destroyed via a runnable. We
+ // don't want DestroyComplete to run until after those runnables have
+ // run. Since we're enqueueing ourselves after the window-destroyed
+ // runnables are enqueued, we're guaranteed to run after.
+ mPhase = eWaitForUnloadMessage;
+ NS_DispatchToCurrentThread(this);
+ }
+ break;
+
+ case eWaitForUnloadMessage:
+ // The *-window-destroyed observers have finished running at this
+ // point. However, it's possible that a *-window-destroyed observer might
+ // have sent a message using the message manager. These messages might not
+ // have been processed yet. So we enqueue ourselves again to ensure that
+ // DestroyComplete runs after all messages sent by *-window-destroyed
+ // observers have been processed.
+ mPhase = eDestroyComplete;
+ NS_DispatchToCurrentThread(this);
+ break;
+
+ case eDestroyComplete:
+ // Now that all messages sent by unload listeners and window destroyed
+ // observers have been processed, we disconnect the message manager and
+ // finish destruction.
+ mFrameLoader->DestroyComplete();
+ break;
}
- // NOTE: 'this' may very well be gone by now.
-
return NS_OK;
}
+void
+nsFrameLoader::DestroyDocShell()
+{
+ // This code runs after the frameloader has been detached from the
+ // element. We postpone this work because we may not be allowed to run
+ // script at that time.
+
+ // Ask the TabChild to fire the frame script "unload" event, destroy its
+ // docshell, and finally destroy the PBrowser actor. This eventually leads to
+ // nsFrameLoader::DestroyComplete being called.
+ if (mRemoteBrowser) {
+ mRemoteBrowser->Destroy();
+ }
+
+ // Fire the "unload" event if we're in-process.
+ if (mChildMessageManager) {
+ static_cast(mChildMessageManager.get())->FireUnloadEvent();
+ }
+
+ // Destroy the docshell.
+ nsCOMPtr base_win(do_QueryInterface(mDocShell));
+ if (base_win) {
+ base_win->Destroy();
+ }
+ mDocShell = nullptr;
+
+ if (mChildMessageManager) {
+ // Stop handling events in the in-process frame script.
+ static_cast(mChildMessageManager.get())->DisconnectEventListeners();
+ }
+}
+
+void
+nsFrameLoader::DestroyComplete()
+{
+ // We get here, as part of StartDestroy, after the docshell has been destroyed
+ // and all message manager messages sent during docshell destruction have been
+ // dispatched. We also get here if the child process crashes. In the latter
+ // case, StartDestroy might not have been called.
+
+ // Drop the strong references created in StartDestroy.
+ if (mChildMessageManager || mRemoteBrowser) {
+ mOwnerContentStrong = nullptr;
+ if (mRemoteBrowser) {
+ mRemoteBrowser->CacheFrameLoader(nullptr);
+ }
+ }
+
+ // Call TabParent::Destroy if we haven't already (in case of a crash).
+ if (mRemoteBrowser) {
+ mRemoteBrowser->SetOwnerElement(nullptr);
+ mRemoteBrowser->Destroy();
+ mRemoteBrowser = nullptr;
+ }
+
+ if (mMessageManager) {
+ mMessageManager->Disconnect();
+ }
+
+ if (mChildMessageManager) {
+ static_cast(mChildMessageManager.get())->Disconnect();
+ }
+}
+
NS_IMETHODIMP
nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
{
diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h
index 60e306e7f9..89c29fc287 100644
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -79,7 +79,9 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
nsresult CheckForRecursiveLoad(nsIURI* aURI);
nsresult ReallyStartLoading();
- void Finalize();
+ void StartDestroy();
+ void DestroyDocShell();
+ void DestroyComplete();
nsIDocShell* GetExistingDocShell() { return mDocShell; }
mozilla::dom::EventTarget* GetTabChildGlobalAsEventTarget();
nsresult CreateStaticClone(nsIFrameLoader* aDest);
@@ -320,6 +322,11 @@ private:
nsCOMPtr mURIToLoad;
mozilla::dom::Element* mOwnerContent; // WEAK
+ // After the frameloader has been removed from the DOM but before all of the
+ // messages from the frame have been received, we keep a strong reference to
+ // our element.
+ nsRefPtr mOwnerContentStrong;
+
// Note: this variable must be modified only by ResetPermissionManagerStatus()
uint32_t mAppIdSentToPermissionManager;
diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp
index 29a777c5f6..a6e0d6ee12 100644
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -301,7 +301,8 @@ SameProcessCpowHolder::ToObject(JSContext* aCx,
NS_IMETHODIMP
nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
- nsIMessageListener* aListener)
+ nsIMessageListener* aListener,
+ bool aListenWhenClosed)
{
nsAutoTObserverArray* listeners =
mListeners.Get(aMessage);
@@ -320,6 +321,7 @@ nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
nsMessageListenerInfo* entry = listeners->AppendElement();
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->mStrongListener = aListener;
+ entry->mListenWhenClosed = aListenWhenClosed;
return NS_OK;
}
@@ -407,6 +409,7 @@ nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
nsMessageListenerInfo* entry = listeners->AppendElement();
entry->mWeakListener = weak;
+ entry->mListenWhenClosed = false;
return NS_OK;
}
@@ -983,6 +986,20 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
mozilla::jsipc::CpowHolder* aCpows,
nsIPrincipal* aPrincipal,
InfallibleTArray* aJSONRetVal)
+{
+ return ReceiveMessage(aTarget, mClosed, aMessage, aIsSync,
+ aCloneData, aCpows, aPrincipal, aJSONRetVal);
+}
+
+nsresult
+nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
+ bool aTargetClosed,
+ const nsAString& aMessage,
+ bool aIsSync,
+ const StructuredCloneData* aCloneData,
+ mozilla::jsipc::CpowHolder* aCpows,
+ nsIPrincipal* aPrincipal,
+ InfallibleTArray* aJSONRetVal)
{
nsAutoTObserverArray* listeners =
mListeners.Get(aMessage);
@@ -1004,6 +1021,10 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
}
+ if (!listener.mListenWhenClosed && aTargetClosed) {
+ continue;
+ }
+
nsCOMPtr wrappedJS;
if (weakListener) {
wrappedJS = do_QueryInterface(weakListener);
@@ -1154,7 +1175,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
}
nsRefPtr kungfuDeathGrip = mParentManager;
- return mParentManager ? mParentManager->ReceiveMessage(aTarget, aMessage,
+ return mParentManager ? mParentManager->ReceiveMessage(aTarget, aTargetClosed, aMessage,
aIsSync, aCloneData,
aCpows, aPrincipal,
aJSONRetVal) : NS_OK;
@@ -1234,9 +1255,27 @@ nsFrameMessageManager::RemoveFromParent()
mOwnedCallback = nullptr;
}
+void
+nsFrameMessageManager::Close()
+{
+ if (!mClosed) {
+ nsCOMPtr obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this),
+ "message-manager-close", nullptr);
+ }
+ }
+ mClosed = true;
+ mCallback = nullptr;
+ mOwnedCallback = nullptr;
+}
+
void
nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
{
+ // Notify message-manager-close if we haven't already.
+ Close();
+
if (!mDisconnected) {
nsCOMPtr obs = mozilla::services::GetObserverService();
if (obs) {
@@ -1249,8 +1288,6 @@ nsFrameMessageManager::Disconnect(bool aRemoveFromParent)
}
mDisconnected = true;
mParentManager = nullptr;
- mCallback = nullptr;
- mOwnedCallback = nullptr;
if (!mHandlingMessage) {
mListeners.Clear();
}
diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h
index 73468cbc97..b3d8c7094c 100644
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -133,6 +133,7 @@ struct nsMessageListenerInfo
// Exactly one of mStrongListener and mWeakListener must be non-null.
nsCOMPtr mStrongListener;
nsWeakPtr mWeakListener;
+ bool mListenWhenClosed;
};
@@ -169,6 +170,7 @@ public:
mIsBroadcaster(!!(aFlags & mozilla::dom::ipc::MM_BROADCASTER)),
mOwnsCallback(!!(aFlags & mozilla::dom::ipc::MM_OWNSCALLBACK)),
mHandlingMessage(false),
+ mClosed(false),
mDisconnected(false),
mCallback(aCallback),
mParentManager(aParentManager)
@@ -238,6 +240,7 @@ public:
mChildManagers.RemoveObject(aManager);
}
void Disconnect(bool aRemoveFromParent = true);
+ void Close();
void InitWithCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
void SetCallback(mozilla::dom::ipc::MessageManagerCallback* aCallback);
@@ -290,6 +293,11 @@ private:
JS::MutableHandle aRetval,
bool aIsSync);
+ nsresult ReceiveMessage(nsISupports* aTarget, bool aTargetClosed, const nsAString& aMessage,
+ bool aIsSync, const StructuredCloneData* aCloneData,
+ mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
+ InfallibleTArray* aJSONRetVal);
+
NS_IMETHOD LoadScript(const nsAString& aURL,
bool aAllowDelayedLoad,
bool aRunInGlobalScope);
@@ -309,6 +317,7 @@ protected:
bool mIsBroadcaster; // true if the message manager is a broadcaster
bool mOwnsCallback;
bool mHandlingMessage;
+ bool mClosed; // true if we can no longer send messages
bool mDisconnected;
mozilla::dom::ipc::MessageManagerCallback* mCallback;
nsAutoPtr mOwnedCallback;
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 1a9863ce08..be50e51a7a 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -582,7 +582,8 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
mIsModalContentWindow(false),
mIsActive(false), mIsBackground(false),
mAudioMuted(false), mAudioVolume(1.0),
- mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
+ mDesktopModeViewport(false), mInnerWindow(nullptr),
+ mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0
mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
mMarkedCCGeneration(0)
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index 3cecd2875d..092a0c1d8e 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -65,6 +65,7 @@ class nsIObserver;
class nsIPresShell;
class nsIPrincipal;
class nsIRequest;
+class nsIRunnable;
class nsIStreamListener;
class nsIStructuredCloneContainer;
class nsIStyleRule;
@@ -1707,11 +1708,9 @@ public:
virtual nsresult InitializeFrameLoader(nsFrameLoader* aLoader) = 0;
// In case of failure, the caller must handle the error, for example by
// finalizing frame loader asynchronously.
- virtual nsresult FinalizeFrameLoader(nsFrameLoader* aLoader) = 0;
+ virtual nsresult FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer) = 0;
// Removes the frame loader of aShell from the initialization list.
virtual void TryCancelFrameLoaderInitialization(nsIDocShell* aShell) = 0;
- // Returns true if the frame loader of aShell is in the finalization list.
- virtual bool FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell) = 0;
/**
* Check whether this document is a root document that is not an
diff --git a/dom/base/nsIMessageManager.idl b/dom/base/nsIMessageManager.idl
index b220c625f4..fdb926485e 100644
--- a/dom/base/nsIMessageManager.idl
+++ b/dom/base/nsIMessageManager.idl
@@ -201,7 +201,7 @@ interface nsIMessageListener : nsISupports
void receiveMessage();
};
-[scriptable, builtinclass, uuid(aae827bd-acf1-45fe-a556-ea545d4c0804)]
+[scriptable, builtinclass, uuid(b949bfec-bb7d-47bc-b387-ac6a9b655072)]
interface nsIMessageListenerManager : nsISupports
{
/**
@@ -213,9 +213,16 @@ interface nsIMessageListenerManager : nsISupports
*
* If the same listener registers twice for the same message, the
* second registration is ignored.
+ *
+ * Pass true for listenWhenClosed if you want to receive messages
+ * during the short period after a frame has been removed from the
+ * DOM and before its frame script has finished unloading. This
+ * parameter only has an effect for frame message managers in
+ * the main process. Default is false.
*/
void addMessageListener(in AString messageName,
- in nsIMessageListener listener);
+ in nsIMessageListener listener,
+ [optional] in boolean listenWhenClosed);
/**
* Undo an |addMessageListener| call -- that is, calling this causes us to no
@@ -252,7 +259,7 @@ interface nsIMessageListenerManager : nsISupports
* messages that are only delivered to its one parent-process message
* manager.
*/
-[scriptable, builtinclass, uuid(d6b0d851-43e6-426d-9f13-054bc0198175)]
+[scriptable, builtinclass, uuid(bb5d79e4-e73c-45e7-9651-4d718f4b994c)]
interface nsIMessageSender : nsIMessageListenerManager
{
/**
@@ -284,7 +291,7 @@ interface nsIMessageSender : nsIMessageListenerManager
* manager will broadcast the message to all frame message managers
* within its window.
*/
-[scriptable, builtinclass, uuid(d36346b9-5d3b-497d-9c28-ffbc3e4f6d0d)]
+[scriptable, builtinclass, uuid(4d7d62ad-4725-4f39-86cf-8fb22bf9c1d8)]
interface nsIMessageBroadcaster : nsIMessageListenerManager
{
/**
@@ -311,7 +318,7 @@ interface nsIMessageBroadcaster : nsIMessageListenerManager
nsIMessageListenerManager getChildAt(in unsigned long aIndex);
};
-[scriptable, builtinclass, uuid(7fda0941-9dcc-448b-bd39-16373c5b4003)]
+[scriptable, builtinclass, uuid(0e602c9e-1977-422a-a8e4-fe0d4a4f78d0)]
interface nsISyncMessageSender : nsIMessageSender
{
/**
@@ -341,7 +348,7 @@ interface nsISyncMessageSender : nsIMessageSender
[optional] in nsIPrincipal principal);
};
-[scriptable, builtinclass, uuid(e04a7ade-c61a-46ec-9f13-efeabedd9d3d)]
+[scriptable, builtinclass, uuid(13f3555f-769e-44ea-b607-5239230c3162)]
interface nsIMessageManagerGlobal : nsISyncMessageSender
{
/**
@@ -376,13 +383,13 @@ interface nsIContentFrameMessageManager : nsIMessageManagerGlobal
readonly attribute nsIDocShell docShell;
};
-[uuid(a2325927-9c0c-437d-9215-749c79235031)]
+[uuid(a9e07e89-7125-48e3-bf73-2cbae7fc5b1c)]
interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
{
[notxpcom] nsIContent getOwnerContent();
};
-[scriptable, builtinclass, uuid(9ca95410-b253-11e4-ab27-0800200c9a66)]
+[scriptable, builtinclass, uuid(d0c799a2-d5ff-4a75-acbb-b8c8347944a6)]
interface nsIContentProcessMessageManager : nsIMessageManagerGlobal
{
};
diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp
index 9a30413797..a94d87299c 100644
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -101,6 +101,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
nsIContent* aOwner,
nsFrameMessageManager* aChrome)
: mDocShell(aShell), mInitialized(false), mLoadingScript(false),
+ mPreventEventsEscaping(false),
mOwner(aOwner), mChromeMessageManager(aChrome)
{
SetIsNotDOMBinding();
@@ -206,25 +207,24 @@ nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
}
void
-nsInProcessTabChildGlobal::Disconnect()
+nsInProcessTabChildGlobal::FireUnloadEvent()
{
- // Let the frame scripts know the child is being closed. We do any other
- // cleanup after the event has been fired. See DelayedDisconnect
- nsContentUtils::AddScriptRunner(
- NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect)
- );
+ // We're called from nsDocument::MaybeInitializeFinalizeFrameLoaders, so it
+ // should be safe to run script.
+ MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
+
+ // Don't let the unload event propagate to chrome event handlers.
+ mPreventEventsEscaping = true;
+ DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
+
+ // Allow events fired during docshell destruction (pagehide, unload) to
+ // propagate to the element since chrome code depends on this.
+ mPreventEventsEscaping = false;
}
void
-nsInProcessTabChildGlobal::DelayedDisconnect()
+nsInProcessTabChildGlobal::DisconnectEventListeners()
{
- // Don't let the event escape
- mOwner = nullptr;
-
- // Fire the "unload" event
- DOMEventTargetHelper::DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
-
- // Continue with the Disconnect cleanup
if (mDocShell) {
nsCOMPtr win = mDocShell->GetWindow();
if (win) {
@@ -232,15 +232,22 @@ nsInProcessTabChildGlobal::DelayedDisconnect()
win->SetChromeEventHandler(win->GetChromeEventHandler());
}
}
+ if (mListenerManager) {
+ mListenerManager->Disconnect();
+ }
+
mDocShell = nullptr;
+}
+
+void
+nsInProcessTabChildGlobal::Disconnect()
+{
mChromeMessageManager = nullptr;
+ mOwner = nullptr;
if (mMessageManager) {
static_cast(mMessageManager.get())->Disconnect();
mMessageManager = nullptr;
}
- if (mListenerManager) {
- mListenerManager->Disconnect();
- }
}
NS_IMETHODIMP_(nsIContent *)
@@ -254,18 +261,6 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
{
aVisitor.mCanHandle = true;
- if (mIsBrowserOrAppFrame &&
- (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
- if (mOwner) {
- nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
- if (innerWindow) {
- aVisitor.mParentTarget = innerWindow->GetParentTarget();
- }
- }
- } else {
- aVisitor.mParentTarget = mOwner;
- }
-
#ifdef DEBUG
if (mOwner) {
nsCOMPtr owner = do_QueryInterface(mOwner);
@@ -279,6 +274,23 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
#endif
+ if (mPreventEventsEscaping) {
+ aVisitor.mParentTarget = nullptr;
+ return NS_OK;
+ }
+
+ if (mIsBrowserOrAppFrame &&
+ (!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
+ if (mOwner) {
+ nsPIDOMWindow* innerWindow = mOwner->OwnerDoc()->GetInnerWindow();
+ if (innerWindow) {
+ aVisitor.mParentTarget = innerWindow->GetParentTarget();
+ }
+ }
+ } else {
+ aVisitor.mParentTarget = mOwner;
+ }
+
return NS_OK;
}
diff --git a/dom/base/nsInProcessTabChildGlobal.h b/dom/base/nsInProcessTabChildGlobal.h
index e2667eae95..650e84dca4 100644
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -118,6 +118,8 @@ public:
virtual JSContext* GetJSContextForEventHandlers() override { return nsContentUtils::GetSafeJSContext(); }
virtual nsIPrincipal* GetPrincipal() override { return mPrincipal; }
void LoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope);
+ void FireUnloadEvent();
+ void DisconnectEventListeners();
void Disconnect();
void SendMessageToParent(const nsString& aMessage, bool aSync,
const nsString& aJSON,
@@ -137,8 +139,6 @@ public:
mChromeMessageManager = aParent;
}
- void DelayedDisconnect();
-
virtual JSObject* GetGlobalJSObject() override {
if (!mGlobal) {
return nullptr;
@@ -164,6 +164,7 @@ protected:
//