import change from rmottola/Arctic-Fox:

- Bug 1139453 - Send network UP/DOWN events on desktop Linux. (7466c1298)
- Bug 1141488 - On non-APZ platforms, combine any async transform with the OMTA transform rather than clobbering it the OMTA transform. (fe48d6774)
- Bug 1080752 - Hold wakelock when attempting to connect to push server. (b1e74295f)
- Bug 1126089 - Allow messages to be sent after frame script unload event. (167ebbd9a)
- Bug 1126089 - Add test for pageload event on browser element when tab closed (f2011e6e4)
- Bug 1090921 - Logging to see which tasks remain alive too long (ebfc3c9bd)
- Bug 1142544 - delete now-unnecessary |extern "C++"| block from nsISupportsUtils.h; r=mccr8 (07e6572f8)
- Bug 1142503 - don't use QueryInterface when the compiler can do the cast for us; r=ehsan (b13219054)
- Bug 1140161 - Sensibly handle patterns with absolute paths in TEST_HARNESS_FILES. (173e369a7)
- Bug 1082510 - When we detect a chrome popup at the current event coordinates and remote content has the mouse captured, release capture. r=Enn (da9fe26a7)
- Bug 1137722 - Ensure that system message cache is refreshed before openapp. r=fabrice (97dc41f50)
- Bug 1139904 - Add initial test runtime files for mochitest browser-chrome and devtools (9837c79b1)
- Bug 1061604 part.1 nsTextStore::GetTextExt() should rReturn previous character rect instead of TS_E_NOLAYOUT when Google Japanese Input retrieves first character of selected clause at composing r=emk (54779d30e)
- Bug 1061604 part.2 nsTextStore::GetTextExt() should rReturn previous character rect of modified range instead of TS_E_NOLAYOUT when Google Japanese Input retrieves caret rect during composition r=emk (ba7f93879)
- Bug 1136051 - component_insert_pair statrs checks only while we are still checking or haven't started pairing; (ae1ae1d4f)
- Bug 1137007 - Detect namespace and SECCOMP_FILTER_FLAG_TSYNC support in SandboxInfo. r=kang, r=Unfocused (6d9e32a8f)
- Bug 1142263 - Specify all syscall parameters when doing CLONE_NEWUSER detection; f=bwc r=kang (8bcba1831)
-  Bug 1142567 - Remove FAIL_ON_WARNINGS_DEBUG; It is not used. (bf22f1ccf)
- No bug - Add an explanatory message to the multiple-inheritance assertion in DOM bindings; # (ffd94ef07)
- Bug 1141252. Don't mark the TablePainter display item as having background-attachment:fixed content if the background-attachment:fixed image will be painted by a dedicated nsDisplayTableCellBackground. r=mats (98287b37c)
- Bug 1140084 - delete list of script counts in tail-recursive fashion. (90a2b7c45)
- Bug 1048741 - [WebGL2] texParameter: Fix silly bug in TEXTURE_COMPARE_FUNC handling. (ccc90dae3)
- Bug 1142478. Fix integer attribute parsing to not lose track of leading zeroes. (d596a1ce1)
- Bug 1139388 - Remove superfluous locking in the OS X profiler implementation to fix deadlock. (r=mstange) (a13088958)
- Bug 1128603: Remove findReferences and the tests that use it. (bccc64734)
- Bug 1140683: Fix async plugin init using null plugin funcs on MacOSX (47b591d54)
- Bug 1142494 - Fix OSX packaging mistake. (15555f4ee)
- Bug 1136784 - Add screenshot to LogShake produced data. (7ff264243)
- Bug 1142550 - Fix screenshot. (d684b6469)
- Bug 1142006 - Set MACOSX_DEPLOYMENT_TARGET earlier. r=mshal (c333b954e)
- Bug 1100966 - Remember all ranges for all selections when joining nodes in the editor transactions; r=roc (bf34bd0c8)
- Bug 1136507 - L8, LA8, and A8 should not be renderable. (96e807795)
- Bug 1128019 - Init SCISSOR_BOX with initial width and height. (7258cc44c)
- Bug 1142211 - Add layerization testing mechanisms to reftest. r=roc (4c6aa11f8)
- Bug 1106905 - Modify mobile desktop mode implementation to use a desktop viewport. (644ede0e7)
- Bug 1139675 - Simplify the APIs for getting and setting the pres shell resolution. r=mstange,mattwoodrow (c520a8c98)
- Bug 1141563 - Don't update Shapes in parallel after compacting GC (098af79c9)
This commit is contained in:
2019-07-13 08:35:45 +08:00
parent 0a2ee1ef29
commit 2a3dd7f84c
177 changed files with 2586 additions and 1668 deletions
+4 -22
View File
@@ -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');
+3 -3
View File
@@ -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;
}
+21
View File
@@ -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;
}
};
+8
View File
@@ -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 {
+43
View File
@@ -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;
+5
View File
@@ -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) {
+1
View File
@@ -60,6 +60,7 @@ EXTRA_JS_MODULES += [
'LogParser.jsm',
'LogShake.jsm',
'OrientationChangeHandler.jsm',
'Screenshot.jsm',
'SignInToWebsite.jsm',
'SystemAppProxy.jsm',
'TelURIParser.jsm',
@@ -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]
@@ -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();
@@ -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
});
@@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1136784
-->
<head>
<meta charset="utf-8">
<title>Screenshot Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1136784">Screenshot.jsm</a>
<script type="application/javascript">
"use strict";
var gUrl = SimpleTest.getTestFileURL("screenshot_helper.js");
var gScript = SpecialPowers.loadChromeScript(gUrl);
SimpleTest.waitForExplicitFinish();
gScript.addMessageListener("finish", function () {
SimpleTest.ok(true, "chrome test script finished");
gScript.destroy();
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>
@@ -45,7 +45,6 @@ add_test(function test_readAppIni() {
run_next_test();
});
add_test(function test_get_about_memory() {
let memLog = LogCapture.readAboutMemory();
-1
View File
@@ -32,7 +32,6 @@
#distribution,
#distributionId {
font-weight: bold;
display: none;
margin-top: 0;
margin-bottom: 0;
+2 -10
View File
@@ -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
+24 -24
View File
@@ -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 ========================================================
+22 -7
View File
@@ -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) \
+2
View File
@@ -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.
+82 -12
View File
@@ -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<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
static_cast<nsGlobalWindow*>(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<nsIContent> 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<nsPtrHashKey<PaintedLayer>> layers;
nsresult rv;
for (uint32_t i = 0; i < aCount; i++) {
nsCOMPtr<nsIContent> 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()
{
+16 -21
View File
@@ -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<nsRefPtr<nsFrameLoader> > loaders;
mFinalizableFrameLoaders.SwapElements(loaders);
nsTArray<nsCOMPtr<nsIRunnable> > 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,
+2 -3
View File
@@ -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<nsRefPtr<nsFrameLoader> > mInitializableFrameLoaders;
nsTArray<nsRefPtr<nsFrameLoader> > mFinalizableFrameLoaders;
nsTArray<nsCOMPtr<nsIRunnable> > mFrameLoaderFinalizers;
nsRefPtr<nsRunnableMethod<nsDocument> > mFrameLoaderRunner;
nsRevocableEventPtr<nsRunnableMethod<nsDocument, void, false> >
+154 -56
View File
@@ -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<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
if (base_win) {
base_win->Destroy();
}
return NS_OK;
}
nsRefPtr<nsIDocShell> 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<nsIBaseWindow> 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<nsFrameLoader> 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 <browser> 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<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
// Retain references to the <browser> 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<nsIDocument> 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<nsPIDOMWindow> win_private(mDocShell->GetWindow());
@@ -1421,23 +1420,122 @@ nsFrameLoader::Destroy()
}
}
if ((mNeedsAsyncDestroy || !doc ||
NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
nsCOMPtr<nsIRunnable> event = new nsAsyncDocShellDestroyer(mDocShell);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
NS_DispatchToCurrentThread(event);
nsCOMPtr<nsIRunnable> 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 <browser>
// 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<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->FireUnloadEvent();
}
// Destroy the docshell.
nsCOMPtr<nsIBaseWindow> 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<nsInProcessTabChildGlobal*>(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<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
}
}
NS_IMETHODIMP
nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
{
+8 -1
View File
@@ -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<nsIURI> 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 <browser> element.
nsRefPtr<mozilla::dom::Element> mOwnerContentStrong;
// Note: this variable must be modified only by ResetPermissionManagerStatus()
uint32_t mAppIdSentToPermissionManager;
+41 -4
View File
@@ -301,7 +301,8 @@ SameProcessCpowHolder::ToObject(JSContext* aCx,
NS_IMETHODIMP
nsFrameMessageManager::AddMessageListener(const nsAString& aMessage,
nsIMessageListener* aListener)
nsIMessageListener* aListener,
bool aListenWhenClosed)
{
nsAutoTObserverArray<nsMessageListenerInfo, 1>* 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<nsString>* 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<nsString>* aJSONRetVal)
{
nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
mListeners.Get(aMessage);
@@ -1004,6 +1021,10 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
}
if (!listener.mListenWhenClosed && aTargetClosed) {
continue;
}
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS;
if (weakListener) {
wrappedJS = do_QueryInterface(weakListener);
@@ -1154,7 +1175,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
}
nsRefPtr<nsFrameMessageManager> 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<nsIObserverService> 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<nsIObserverService> 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();
}
+9
View File
@@ -133,6 +133,7 @@ struct nsMessageListenerInfo
// Exactly one of mStrongListener and mWeakListener must be non-null.
nsCOMPtr<nsIMessageListener> 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<JS::Value> aRetval,
bool aIsSync);
nsresult ReceiveMessage(nsISupports* aTarget, bool aTargetClosed, const nsAString& aMessage,
bool aIsSync, const StructuredCloneData* aCloneData,
mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* 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<mozilla::dom::ipc::MessageManagerCallback> mOwnedCallback;
+2 -1
View File
@@ -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)
+2 -3
View File
@@ -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
+15 -8
View File
@@ -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
{
};
+41 -29
View File
@@ -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 <browser> 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<nsPIDOMWindow> 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<nsFrameMessageManager*>(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<nsIFrameLoaderOwner> 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;
}
+4 -3
View File
@@ -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:
// <iframe mozapp>? This affects where events get sent, so it affects
// PreHandleEvent.
bool mIsBrowserOrAppFrame;
bool mPreventEventsEscaping;
public:
nsIContent* mOwner;
nsFrameMessageManager* mChromeMessageManager;
+14
View File
@@ -114,6 +114,17 @@ public:
}
// Outer windows only.
void SetDesktopModeViewport(bool aDesktopModeViewport)
{
MOZ_ASSERT(IsOuterWindow());
mDesktopModeViewport = aDesktopModeViewport;
}
bool IsDesktopModeViewport() const
{
MOZ_ASSERT(IsOuterWindow());
return mDesktopModeViewport;
}
virtual void SetIsBackground(bool aIsBackground)
{
MOZ_ASSERT(IsOuterWindow());
@@ -814,6 +825,9 @@ protected:
bool mAudioMuted;
float mAudioVolume;
// current desktop mode flag.
bool mDesktopModeViewport;
// And these are the references between inner and outer windows.
nsPIDOMWindow* MOZ_NON_OWNING_REF mInnerWindow;
nsCOMPtr<nsPIDOMWindow> mOuterWindow;
+5
View File
@@ -1,10 +1,15 @@
[DEFAULT]
support-files =
file_messagemanager_unload.html
[browser_bug593387.js]
skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.iframe.addEventListener)
[browser_bug902350.js]
skip-if = e10s # Bug ?????? - test e10s utils don't support load events from iframe etc, which this test relies on.
[browser_messagemanager_loadprocessscript.js]
[browser_pagehide_on_tab_close.js]
skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
[browser_messagemanager_unload.js]
[browser_state_notifications.js]
# skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
@@ -0,0 +1,196 @@
function frameScript()
{
Components.utils.import("resource://gre/modules/Services.jsm");
function eventHandler(e) {
if (!docShell) {
sendAsyncMessage("Test:Fail", "docShell is null");
}
sendAsyncMessage("Test:Event", [e.type, e.target === content.document, e.eventPhase]);
}
let outerID = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils).outerWindowID;
function onOuterWindowDestroyed(subject, topic, data) {
if (docShell) {
sendAsyncMessage("Test:Fail", "docShell is non-null");
}
let id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
sendAsyncMessage("Test:Event", ["outer-window-destroyed", id == outerID]);
if (id == outerID) {
Services.obs.removeObserver(onOuterWindowDestroyed, "outer-window-destroyed");
}
}
let url = "https://example.com/browser/dom/base/test/file_messagemanager_unload.html";
content.location = url;
addEventListener("load", (e) => {
if (e.target.location != url) {
return;
}
addEventListener("unload", eventHandler, false);
addEventListener("unload", eventHandler, true);
addEventListener("pagehide", eventHandler, false);
addEventListener("pagehide", eventHandler, true);
Services.obs.addObserver(onOuterWindowDestroyed, "outer-window-destroyed", false);
sendAsyncMessage("Test:Ready");
}, true);
}
const EXPECTED = [
// Unload events on the TabChildGlobal. These come first so that the
// docshell is available.
["unload", false, 2],
["unload", false, 2],
// pagehide and unload events for the top-level page.
["pagehide", true, 1],
["pagehide", true, 3],
["unload", true, 1],
// pagehide and unload events for the iframe.
["pagehide", false, 1],
["pagehide", false, 3],
["unload", false, 1],
// outer-window-destroyed for both pages.
["outer-window-destroyed", false],
["outer-window-destroyed", true],
];
function test() {
waitForExplicitFinish();
var newTab = gBrowser.addTab("about:blank");
gBrowser.selectedTab = newTab;
let browser = newTab.linkedBrowser;
browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false);
browser.messageManager.addMessageListener("Test:Fail", (msg) => {
ok(false, msg.data);
}, true);
let index = 0;
browser.messageManager.addMessageListener("Test:Event", (msg) => {
ok(msg.target === browser, "<browser> is correct");
info(JSON.stringify(msg.data));
is(JSON.stringify(msg.data), JSON.stringify(EXPECTED[index]), "results match");
index++;
if (index == EXPECTED.length) {
finish();
}
}, true);
browser.messageManager.addMessageListener("Test:Ready", () => {
info("Got ready message");
gBrowser.removeCurrentTab();
});
}
function frameScript()
{
Components.utils.import("resource://gre/modules/Services.jsm");
function eventHandler(e) {
if (!docShell) {
sendAsyncMessage("Test:Fail", "docShell is null");
}
sendAsyncMessage("Test:Event", [e.type, e.target === content.document, e.eventPhase]);
}
let outerID = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils).outerWindowID;
function onOuterWindowDestroyed(subject, topic, data) {
if (docShell) {
sendAsyncMessage("Test:Fail", "docShell is non-null");
}
let id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
sendAsyncMessage("Test:Event", ["outer-window-destroyed", id == outerID]);
if (id == outerID) {
Services.obs.removeObserver(onOuterWindowDestroyed, "outer-window-destroyed");
}
}
let url = "https://example.com/browser/dom/base/test/file_messagemanager_unload.html";
content.location = url;
addEventListener("load", (e) => {
if (e.target.location != url) {
return;
}
addEventListener("unload", eventHandler, false);
addEventListener("unload", eventHandler, true);
addEventListener("pagehide", eventHandler, false);
addEventListener("pagehide", eventHandler, true);
Services.obs.addObserver(onOuterWindowDestroyed, "outer-window-destroyed", false);
sendAsyncMessage("Test:Ready");
}, true);
}
const EXPECTED = [
// Unload events on the TabChildGlobal. These come first so that the
// docshell is available.
["unload", false, 2],
["unload", false, 2],
// pagehide and unload events for the top-level page.
["pagehide", true, 1],
["pagehide", true, 3],
["unload", true, 1],
// pagehide and unload events for the iframe.
["pagehide", false, 1],
["pagehide", false, 3],
["unload", false, 1],
// outer-window-destroyed for both pages.
["outer-window-destroyed", false],
["outer-window-destroyed", true],
];
function test() {
waitForExplicitFinish();
var newTab = gBrowser.addTab("about:blank");
gBrowser.selectedTab = newTab;
let browser = newTab.linkedBrowser;
browser.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false);
browser.messageManager.addMessageListener("Test:Fail", (msg) => {
ok(false, msg.data);
}, true);
let index = 0;
browser.messageManager.addMessageListener("Test:Event", (msg) => {
ok(msg.target === browser, "<browser> is correct");
info(JSON.stringify(msg.data));
is(JSON.stringify(msg.data), JSON.stringify(EXPECTED[index]), "results match");
index++;
if (index == EXPECTED.length) {
finish();
}
}, true);
browser.messageManager.addMessageListener("Test:Ready", () => {
info("Got ready message");
gBrowser.removeCurrentTab();
});
}
@@ -0,0 +1,17 @@
function test() {
waitForExplicitFinish();
var tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
tab.linkedBrowser.addEventListener("load", function onload() {
tab.linkedBrowser.removeEventListener("load", onload);
tab.linkedBrowser.addEventListener("pagehide", function() {
ok(true, "got page hide event");
finish();
});
executeSoon(() => { gBrowser.removeTab(tab); });
}, true);
}
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<body>
<iframe id="frame" src="about:robots"></iframe>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<iframe id="frame" src="about:robots"></iframe>
</body>
</html>
+1
View File
@@ -773,6 +773,7 @@ skip-if = true # bug 1107443 - code for newly-added test was disabled
skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_bug1118689.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g'
[test_integer_attr_with_leading_zero.html]
[test_getAttribute_after_createAttribute.html]
[test_script_loader_crossorigin_data_url.html]
[test_unknown_url_origin.html]
@@ -0,0 +1,64 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for parsing of integer attributes with leading zero</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
var td = document.createElement("td");
var li = document.createElement("li");
// Array of tests: "values" are the values to set, "tdreflection" is the
// corresponding td.rowspan value, "lireflection" is the corresponding li.value
// value.
var testData = [
{
values: [
"2",
"02",
"002",
"00002",
],
tdreflection: 2,
lireflection: 2,
},
{
values: [
"-2",
"-02",
"-002",
"-00002",
],
tdreflection: 1,
lireflection: -2,
},
{
values: [
"-0",
"-00",
"0",
"00",
],
tdreflection: 0,
lireflection: 0,
},
];
for (var data of testData) {
for (var value of data.values) {
td.setAttribute("rowspan", value);
li.setAttribute("value", value);
test(function() {
assert_equals(td.rowSpan, data.tdreflection);
}, `<td> reflection for ${value}`);
test(function() {
assert_equals(td.getAttribute("rowspan"), value);
}, `<td> setAttribute roundtripping for ${value}`);
test(function() {
assert_equals(li.value, data.lireflection);
}, `<li> reflection for ${value}`);
test(function() {
assert_equals(li.getAttribute("value"), value);
}, `<li> setAttribute roundtripping for ${value}`);
}
}
</script>
+3 -2
View File
@@ -3203,8 +3203,9 @@ def AssertInheritanceChain(descriptor):
desc = descriptor.getDescriptor(iface.identifier.name)
asserts += (
"MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
" reinterpret_cast<%s*>(aObject));\n" %
(desc.nativeType, desc.nativeType))
" reinterpret_cast<%s*>(aObject),\n"
" \"Multiple inheritance for %s is broken.\");\n" %
(desc.nativeType, desc.nativeType, desc.nativeType))
iface = iface.parent
asserts += "MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n"
return asserts
+2
View File
@@ -911,6 +911,8 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
mViewportWidth = mWidth;
mViewportHeight = mHeight;
gl->fScissor(0, 0, mWidth, mHeight);
// Make sure that we clear this out, otherwise
// we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+2 -2
View File
@@ -1502,10 +1502,10 @@ void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname,
case LOCAL_GL_NOTEQUAL:
case LOCAL_GL_ALWAYS:
case LOCAL_GL_NEVER:
paramValueInvalid = false;
break;
default:
paramValueInvalid = true;
pnameAndParamAreIncompatible = true;
}
break;
-3
View File
@@ -263,9 +263,6 @@ bool
WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const
{
switch (sizedFormat) {
case LOCAL_GL_ALPHA8:
case LOCAL_GL_LUMINANCE8:
case LOCAL_GL_LUMINANCE8_ALPHA8:
case LOCAL_GL_RGB8:
case LOCAL_GL_RGBA8:
case LOCAL_GL_RGB565:
+2 -2
View File
@@ -390,7 +390,7 @@ HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
// quirks mode does not honor the special html 4 value of 0
if (val > MAX_COLSPAN || val < 0 ||
(0 == val && InNavQuirksMode(OwnerDoc()))) {
aResult.SetTo(1);
aResult.SetTo(1, &aValue);
}
}
return res;
@@ -401,7 +401,7 @@ HTMLTableCellElement::ParseAttribute(int32_t aNamespaceID,
int32_t val = aResult.GetIntegerValue();
// quirks mode does not honor the special html 4 value of 0
if (val < 0 || (0 == val && InNavQuirksMode(OwnerDoc()))) {
aResult.SetTo(1);
aResult.SetTo(1, &aValue);
}
}
return res;
+28 -7
View File
@@ -50,7 +50,7 @@ interface nsITranslationNodeList;
interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
[scriptable, uuid(6eaf87a1-b252-4c4e-a2fc-318120680335)]
[scriptable, uuid(dde97573-f4cf-45ce-bbb0-5af4e5f77440)]
interface nsIDOMWindowUtils : nsISupports {
/**
@@ -205,15 +205,14 @@ interface nsIDOMWindowUtils : nsISupports {
*
* The effect of this API is for gfx code to allocate more or fewer
* pixels for rescalable content by a factor of |resolution| in
* either or both dimensions. The scale at which the content is
* displayed does not change; if that is desired, use
* setResolutionAndScaleTo() instead.
* both dimensions. The scale at which the content is displayed does
* not change; if that is desired, use setResolutionAndScaleTo() instead.
*
* The caller of this method must have chrome privileges.
*/
void setResolution(in float aXResolution, in float aYResolution);
void setResolution(in float aResolution);
void getResolution(out float aXResolution, out float aYResolution);
void getResolution(out float aResolution);
/**
* Similar to setResolution(), but also scales the content by the
@@ -226,7 +225,7 @@ interface nsIDOMWindowUtils : nsISupports {
*
* The caller of this method must have chrome privileges.
*/
void setResolutionAndScaleTo(in float aXResolution, in float aYResolution);
void setResolutionAndScaleTo(in float aResolution);
/**
* Whether the resolution has been set by the user.
@@ -1275,6 +1274,11 @@ interface nsIDOMWindowUtils : nsISupports {
*/
[noscript] boolean isInModalState();
/**
* Request set internal desktopMode flag change.
*/
void setDesktopModeViewport(in boolean aDesktopModeViewport);
/**
* Suspend/resume timeouts on this window and its descendant windows.
*/
@@ -1442,6 +1446,23 @@ interface nsIDOMWindowUtils : nsISupports {
*/
boolean checkAndClearPaintedState(in nsIDOMElement aElement);
/**
* Check whether all display items of the primary frame of aElement have been
* assigned to the same single PaintedLayer in the last paint. If that is the
* case, returns whether that PaintedLayer is opaque; if it's not the case, an
* exception is thrown.
*/
boolean isPartOfOpaqueLayer(in nsIDOMElement aElement);
/**
* Count the number of different PaintedLayers that the supplied elements have
* been assigned to in the last paint. Throws an exception if any of the
* elements doesn't have a primary frame, or if that frame's display items are
* assigned to any other layers than just a single PaintedLayer per element.
*/
unsigned long numberOfAssignedPaintedLayers([array, size_is(count)] in nsIDOMElement aElements,
in uint32_t count);
/**
* Get internal id of the stored blob, file or file handle.
*/
+7 -34
View File
@@ -387,7 +387,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
metrics.SetPresShellResolution(metrics.GetCumulativeResolution().ToScaleFactor().scale);
utils->SetResolutionAndScaleTo(metrics.GetPresShellResolution(), metrics.GetPresShellResolution());
utils->SetResolutionAndScaleTo(metrics.GetPresShellResolution());
CSSSize scrollPort = metrics.CalculateCompositedSizeInCssPixels();
utils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);
@@ -910,8 +910,7 @@ TabChild::Observe(nsISupports *aSubject,
// until we we get an inner size.
if (HasValidInnerSize()) {
InitializeRootMetrics();
utils->SetResolutionAndScaleTo(mLastRootMetrics.GetPresShellResolution(),
mLastRootMetrics.GetPresShellResolution());
utils->SetResolutionAndScaleTo(mLastRootMetrics.GetPresShellResolution());
HandlePossibleViewportChange(mInnerSize);
}
}
@@ -2331,7 +2330,7 @@ TabChild::GetPresShellResolution() const
if (!shell) {
return 1.0f;
}
return shell->GetXResolution();
return shell->GetResolution();
}
bool
@@ -2637,32 +2636,6 @@ TabChild::RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline)
return true;
}
class UnloadScriptEvent : public nsRunnable
{
public:
UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
: mTabChild(aTabChild), mTabChildGlobal(aTabChildGlobal)
{ }
NS_IMETHOD Run()
{
nsCOMPtr<nsIDOMEvent> event;
NS_NewDOMEvent(getter_AddRefs(event), mTabChildGlobal, nullptr, nullptr);
if (event) {
event->InitEvent(NS_LITERAL_STRING("unload"), false, false);
event->SetTrusted(true);
bool dummy;
mTabChildGlobal->DispatchEvent(event, &dummy);
}
return NS_OK;
}
nsRefPtr<TabChild> mTabChild;
TabChildGlobal* mTabChildGlobal;
};
bool
TabChild::RecvDestroy()
{
@@ -2670,10 +2643,10 @@ TabChild::RecvDestroy()
mDestroyed = true;
if (mTabChildGlobal) {
// Let the frame scripts know the child is being closed
nsContentUtils::AddScriptRunner(
new UnloadScriptEvent(this, mTabChildGlobal)
);
// Message handlers are called from the event loop, so it better be safe to
// run script.
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
mTabChildGlobal->DispatchTrustedEvent(NS_LITERAL_STRING("unload"));
}
nsCOMPtr<nsIObserverService> observerService =
+20 -9
View File
@@ -315,6 +315,12 @@ TabParent::RemoveTabParentFromTable(uint64_t aLayersId)
}
}
void
TabParent::CacheFrameLoader(nsFrameLoader* aFrameLoader)
{
mFrameLoader = aFrameLoader;
}
void
TabParent::SetOwnerElement(Element* aElement)
{
@@ -401,15 +407,13 @@ TabParent::ActorDestroy(ActorDestroyReason why)
if (mIMETabParent == this) {
mIMETabParent = nullptr;
}
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
nsRefPtr<nsFrameMessageManager> fmm;
if (frameLoader) {
fmm = frameLoader->GetFrameMessageManager();
nsCOMPtr<Element> frameElement(mFrameElement);
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr,
nullptr);
frameLoader->DestroyChild();
frameLoader->DestroyComplete();
if (why == AbnormalShutdown && os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
@@ -418,14 +422,13 @@ TabParent::ActorDestroy(ActorDestroyReason why)
NS_LITERAL_STRING("oop-browser-crashed"),
true, true);
}
mFrameLoader = nullptr;
}
if (os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this), "ipc:browser-destroyed", nullptr);
}
if (fmm) {
fmm->Disconnect();
}
}
bool
@@ -2230,7 +2233,7 @@ TabParent::ReceiveMessage(const nsString& aMessage,
nsIPrincipal* aPrincipal,
InfallibleTArray<nsString>* aJSONRetVal)
{
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
if (frameLoader && frameLoader->GetFrameMessageManager()) {
nsRefPtr<nsFrameMessageManager> manager =
frameLoader->GetFrameMessageManager();
@@ -2348,8 +2351,16 @@ TabParent::AllowContentIME()
}
already_AddRefed<nsFrameLoader>
TabParent::GetFrameLoader() const
TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
{
if (mIsDestroyed && !aUseCachedFrameLoaderAfterDestroy) {
return nullptr;
}
if (mFrameLoader) {
nsRefPtr<nsFrameLoader> fl = mFrameLoader;
return fl.forget();
}
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(mFrameElement);
return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr;
}
+8 -1
View File
@@ -81,6 +81,8 @@ public:
Element* GetOwnerElement() const { return mFrameElement; }
void SetOwnerElement(Element* aElement);
void CacheFrameLoader(nsFrameLoader* aFrameLoader);
/**
* Get the mozapptype attribute from this TabParent's owner DOM element.
*/
@@ -426,7 +428,7 @@ protected:
bool mUpdatedDimensions;
private:
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
layout::RenderFrameParent* GetRenderFrame();
nsRefPtr<nsIContentParent> mManager;
void TryCacheDPIAndScale();
@@ -468,6 +470,11 @@ private:
nsCOMPtr<nsILoadContext> mLoadContext;
// We keep a strong reference to the frameloader after we've sent the
// Destroy message and before we've received __delete__. This allows us to
// dispatch message manager messages during this time.
nsRefPtr<nsFrameLoader> mFrameLoader;
TabId mTabId;
// Helper class for RecvCreateWindow.
-1
View File
@@ -25,7 +25,6 @@ function SystemMessageCache() {
this._pagesCache = [];
dump("SystemMessageCache: init");
Services.obs.addObserver(this, "xpcom-shutdown", false);
kMessages.forEach(function(aMessage) {
cpmm.addMessageListener(aMessage, this);
+22 -27
View File
@@ -250,8 +250,6 @@ SystemMessageInternal.prototype = {
aExtra);
debug("Returned status of sending message: " + result);
// Don't need to open the pages and queue the system message
// which was not allowed to be sent.
if (result === MSG_SENT_FAILURE_PERM_DENIED) {
return;
}
@@ -259,14 +257,6 @@ SystemMessageInternal.prototype = {
// For each page we must receive a confirm.
++pendingPromise.counter;
let page = this._findPage(aType, aPageURL, manifestURL);
if (page) {
// Queue this message in the corresponding pages.
this._queueMessage(page, aMessage, messageID);
this._openAppPage(page, aMessage, aExtra, result);
}
}, this);
if (pendingPromise.counter) {
@@ -308,18 +298,6 @@ SystemMessageInternal.prototype = {
aPage.manifestURL,
aExtra);
debug("Returned status of sending message: " + result);
// Don't need to open the pages and queue the system message
// which was not allowed to be sent.
if (result === MSG_SENT_FAILURE_PERM_DENIED) {
return;
}
// Queue this message in the corresponding pages.
this._queueMessage(aPage, aMessage, messageID);
this._openAppPage(aPage, aMessage, aExtra, result);
};
if ('function' !== typeof shouldDispatchFunc) {
@@ -738,15 +716,32 @@ SystemMessageInternal.prototype = {
return MSG_SENT_FAILURE_PERM_DENIED;
}
// Queue this message in the corresponding pages.
let page = this._findPage(aType, aPageURL, aManifestURL);
if (!page) {
debug("Message " + aType + " is not registered for " +
aPageURL + " @ " + aManifestURL);
// FIXME bug 1140275 should only send message to page registered in manifest
// return MSG_SENT_FAILURE_PERM_DENIED;
}
if (page)
this._queueMessage(page, aMessage, aMessageID);
let appPageIsRunning = false;
let pageKey = this._createKeyForPage({ type: aType,
manifestURL: aManifestURL,
pageURL: aPageURL });
let cache = this._findCacheForApp(aManifestURL);
let targets = this._listeners[aManifestURL];
if (targets) {
for (let index = 0; index < targets.length; ++index) {
let target = targets[index];
let manager = target.target;
// Ensure hasPendingMessage cache is refreshed before we open app
manager.sendAsyncMessage("SystemMessageCache:RefreshCache", cache);
// We only need to send the system message to the targets (processes)
// which contain the window page that matches the manifest/page URL of
// the destination of system message.
@@ -765,7 +760,6 @@ SystemMessageInternal.prototype = {
// Multiple windows can share the same target (process), the content
// window needs to check if the manifest/page URL is matched. Only
// *one* window should handle the system message.
let manager = target.target;
manager.sendAsyncMessage("SystemMessageManager:Message",
{ type: aType,
msg: aMessage,
@@ -775,6 +769,7 @@ SystemMessageInternal.prototype = {
}
}
let result = MSG_SENT_SUCCESS;
if (!appPageIsRunning) {
// The app page isn't running and relies on the 'open-app' chrome event to
// wake it up. We still need to acquire a CPU wake lock for that page and
@@ -782,12 +777,12 @@ SystemMessageInternal.prototype = {
// or a "SystemMessageManager:HandleMessageDone" message when the page
// finishes handling the system message with other pending messages. At
// that point, we'll release the lock we acquired.
result = MSG_SENT_FAILURE_APP_NOT_RUNNING;
this._acquireCpuWakeLock(pageKey);
return MSG_SENT_FAILURE_APP_NOT_RUNNING;
} else {
return MSG_SENT_SUCCESS;
}
if (page)
this._openAppPage(page, aMessage, aExtra, result);
return result;
},
_resolvePendingPromises: function(aMessageID) {
+2 -2
View File
@@ -231,8 +231,8 @@ nsPluginInstanceOwner::GetImageContainer()
// NotifySize() causes Flash to do a bunch of stuff like ask for surfaces to render
// into, set y-flip flags, etc, so we do this at the beginning.
gfxSize resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
ScreenSize screenSize = (r * LayoutDeviceToScreenScale2D(resolution.width, resolution.height)).Size();
float resolution = mPluginFrame->PresContext()->PresShell()->GetCumulativeResolution();
ScreenSize screenSize = (r * LayoutDeviceToScreenScale(resolution)).Size();
mInstance->NotifySize(nsIntSize(screenSize.width, screenSize.height));
container = LayerManager::CreateImageContainer();
+13 -2
View File
@@ -1049,6 +1049,8 @@ PluginModuleParent::DeallocPPluginInstanceParent(PPluginInstanceParent* aActor)
void
PluginModuleParent::SetPluginFuncs(NPPluginFuncs* aFuncs)
{
MOZ_ASSERT(aFuncs);
aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
aFuncs->javaClass = nullptr;
@@ -1684,7 +1686,7 @@ PluginModuleParent::RecvNP_InitializeResult(const NPError& aError)
return true;
}
if (mIsStartingAsync) {
if (mIsStartingAsync && mNPPIface) {
SetPluginFuncs(mNPPIface);
InitAsyncSurrogates();
}
@@ -1803,8 +1805,17 @@ PluginModuleParent::NP_GetEntryPoints(NPPluginFuncs* pFuncs, NPError* error)
*error = NPERR_NO_ERROR;
if (mIsStartingAsync && !IsChrome()) {
PluginAsyncSurrogate::NP_GetEntryPoints(pFuncs);
mNPPIface = pFuncs;
#if defined(XP_MACOSX)
if (mNPInitialized) {
SetPluginFuncs(pFuncs);
InitAsyncSurrogates();
} else {
PluginAsyncSurrogate::NP_GetEntryPoints(pFuncs);
}
#else
PluginAsyncSurrogate::NP_GetEntryPoints(pFuncs);
#endif
} else {
SetPluginFuncs(pFuncs);
}
+51 -2
View File
@@ -33,6 +33,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
"resource://gre/modules/AlarmService.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gPowerManagerService",
"@mozilla.org/power/powermanagerservice;1",
"nsIPowerManagerService");
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
this.EXPORTED_SYMBOLS = ["PushService"];
@@ -873,8 +877,18 @@ this.PushService = {
debug("serverURL: " + uri.spec);
this._wsListener = new PushWebSocketListener(this);
this._ws.protocol = "push-notification";
this._ws.asyncOpen(uri, serverURL, this._wsListener, null);
this._currentState = STATE_WAITING_FOR_WS_START;
try {
// Grab a wakelock before we open the socket to ensure we don't go to sleep
// before connection the is opened.
this._ws.asyncOpen(uri, serverURL, this._wsListener, null);
this._acquireWakeLock();
this._currentState = STATE_WAITING_FOR_WS_START;
} catch(e) {
debug("Error opening websocket. asyncOpen failed!");
this._shutdownWS();
this._reconnectAfterBackoff();
}
},
_startListeningIfChannelsPresent: function() {
@@ -997,6 +1011,38 @@ this.PushService = {
}
},
_acquireWakeLock: function() {
if (!this._socketWakeLock) {
debug("Acquiring Socket Wakelock");
this._socketWakeLock = gPowerManagerService.newWakeLock("cpu");
}
if (!this._socketWakeLockTimer) {
debug("Creating Socket WakeLock Timer");
this._socketWakeLockTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
debug("Setting Socket WakeLock Timer");
this._socketWakeLockTimer
.initWithCallback(this._releaseWakeLock.bind(this),
// Allow the same time for socket setup as we do for
// requests after the setup. Fudge it a bit since
// timers can be a little off and we don't want to go
// to sleep just as the socket connected.
this._requestTimeout + 1000,
Ci.nsITimer.ONE_SHOT);
},
_releaseWakeLock: function() {
debug("Releasing Socket WakeLock");
if (this._socketWakeLockTimer) {
this._socketWakeLockTimer.cancel();
}
if (this._socketWakeLock) {
this._socketWakeLock.unlock();
this._socketWakeLock = null;
}
},
/**
* Protocol handler invoked by server message.
*/
@@ -1512,6 +1558,8 @@ this.PushService = {
// begin Push protocol handshake
_wsOnStart: function(context) {
debug("wsOnStart()");
this._releaseWakeLock();
if (this._currentState != STATE_WAITING_FOR_WS_START) {
debug("NOT in STATE_WAITING_FOR_WS_START. Current state " +
this._currentState + ". Skipping");
@@ -1568,6 +1616,7 @@ this.PushService = {
*/
_wsOnStop: function(context, statusCode) {
debug("wsOnStop()");
this._releaseWakeLock();
if (statusCode != Cr.NS_OK &&
!(statusCode == Cr.NS_BASE_STREAM_CLOSED && this._willBeWokenUpByUDP)) {
@@ -385,9 +385,7 @@ nsComposerCommandsUpdater::Notify(nsITimer *timer)
nsresult
NS_NewComposerCommandsUpdater(nsISelectionListener** aInstancePtrResult)
{
nsComposerCommandsUpdater* newThang = new nsComposerCommandsUpdater;
NS_ENSURE_TRUE(newThang, NS_ERROR_OUT_OF_MEMORY);
return newThang->QueryInterface(NS_GET_IID(nsISelectionListener),
(void **)aInstancePtrResult);
nsRefPtr<nsComposerCommandsUpdater> newThang = new nsComposerCommandsUpdater;
newThang.forget(aInstancePtrResult);
return NS_OK;
}
+115 -73
View File
@@ -625,23 +625,28 @@ nsEditor::DeleteSelection(EDirection aAction, EStripWrappers aStripWrappers)
}
NS_IMETHODIMP
nsEditor::GetSelection(nsISelection **aSelection)
nsEditor::GetSelection(nsISelection** aSelection)
{
return GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection);
}
nsresult
nsEditor::GetSelection(int16_t aSelectionType, nsISelection** aSelection)
{
NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
*aSelection = nullptr;
nsCOMPtr<nsISelectionController> selcon;
GetSelectionController(getter_AddRefs(selcon));
NS_ENSURE_TRUE(selcon, NS_ERROR_NOT_INITIALIZED);
return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); // does an addref
return selcon->GetSelection(aSelectionType, aSelection); // does an addref
}
Selection*
nsEditor::GetSelection()
nsEditor::GetSelection(int16_t aSelectionType)
{
nsCOMPtr<nsISelection> sel;
nsresult res = GetSelection(getter_AddRefs(sel));
nsresult res = GetSelection(aSelectionType, getter_AddRefs(sel));
NS_ENSURE_SUCCESS(res, nullptr);
return static_cast<Selection*>(sel.get());
@@ -2689,6 +2694,14 @@ nsEditor::SplitNodeImpl(nsIContent& aExistingRightNode,
return NS_OK;
}
struct SavedRange {
nsRefPtr<Selection> mSelection;
nsCOMPtr<nsINode> mStartNode;
nsCOMPtr<nsINode> mEndNode;
int32_t mStartOffset;
int32_t mEndOffset;
};
nsresult
nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
nsINode* aNodeToJoin,
@@ -2698,25 +2711,6 @@ nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
MOZ_ASSERT(aNodeToJoin);
MOZ_ASSERT(aParent);
nsRefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
// remember some selection points
nsCOMPtr<nsINode> selStartNode;
int32_t selStartOffset;
nsresult result = GetStartNodeAndOffset(selection, getter_AddRefs(selStartNode), &selStartOffset);
if (NS_FAILED(result)) {
selStartNode = nullptr;
}
nsCOMPtr<nsINode> selEndNode;
int32_t selEndOffset;
result = GetEndNodeAndOffset(selection, getter_AddRefs(selEndNode), &selEndOffset);
// Joe or Kin should comment here on why the following line is not a copy/paste error
if (NS_FAILED(result)) {
selStartNode = nullptr;
}
uint32_t firstNodeLength = aNodeToJoin->Length();
int32_t joinOffset;
@@ -2724,24 +2718,53 @@ nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
int32_t keepOffset;
nsINode* parent = GetNodeLocation(aNodeToKeep, &keepOffset);
// if selection endpoint is between the nodes, remember it as being
// in the one that is going away instead. This simplifies later selection
// adjustment logic at end of this method.
if (selStartNode) {
if (selStartNode == parent &&
joinOffset < selStartOffset && selStartOffset <= keepOffset) {
selStartNode = aNodeToJoin;
selStartOffset = firstNodeLength;
// Remember all selection points.
nsAutoTArray<SavedRange, 10> savedRanges;
for (size_t i = 0; i < nsISelectionController::NUM_SELECTIONTYPES - 1; ++i) {
SelectionType type(1 << i);
SavedRange range;
range.mSelection = GetSelection(type);
if (type == nsISelectionController::SELECTION_NORMAL) {
NS_ENSURE_TRUE(range.mSelection, NS_ERROR_NULL_POINTER);
} else if (!range.mSelection) {
// For non-normal selections, skip over the non-existing ones.
continue;
}
if (selEndNode == parent &&
joinOffset < selEndOffset && selEndOffset <= keepOffset) {
selEndNode = aNodeToJoin;
selEndOffset = firstNodeLength;
for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) {
nsRefPtr<nsRange> r = range.mSelection->GetRangeAt(j);
if (!r->IsPositioned()) {
continue;
}
range.mStartNode = r->GetStartParent();
range.mStartOffset = r->StartOffset();
range.mEndNode = r->GetEndParent();
range.mEndOffset = r->EndOffset();
// If selection endpoint is between the nodes, remember it as being
// in the one that is going away instead. This simplifies later selection
// adjustment logic at end of this method.
if (range.mStartNode) {
if (range.mStartNode == parent &&
joinOffset < range.mStartOffset &&
range.mStartOffset <= keepOffset) {
range.mStartNode = aNodeToJoin;
range.mStartOffset = firstNodeLength;
}
if (range.mEndNode == parent &&
joinOffset < range.mEndOffset &&
range.mEndOffset <= keepOffset) {
range.mEndNode = aNodeToJoin;
range.mEndOffset = firstNodeLength;
}
}
savedRanges.AppendElement(range);
}
}
// ok, ready to do join now.
// if it's a text node, just shuffle around some text
// OK, ready to do join now.
// If it's a text node, just shuffle around some text.
nsCOMPtr<nsIDOMCharacterData> keepNodeAsText( do_QueryInterface(aNodeToKeep) );
nsCOMPtr<nsIDOMCharacterData> joinNodeAsText( do_QueryInterface(aNodeToJoin) );
if (keepNodeAsText && joinNodeAsText) {
@@ -2752,15 +2775,15 @@ nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
leftText += rightText;
keepNodeAsText->SetData(leftText);
} else {
// otherwise it's an interior node, so shuffle around the children
// Otherwise it's an interior node, so shuffle around the children.
nsCOMPtr<nsINodeList> childNodes = aNodeToJoin->ChildNodes();
MOZ_ASSERT(childNodes);
// remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
// GetFirstChild returns nullptr firstNode if aNodeToKeep has no children, that's ok.
// Remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
// GetFirstChild returns nullptr firstNode if aNodeToKeep has no children, that's OK.
nsCOMPtr<nsIContent> firstNode = aNodeToKeep->GetFirstChild();
// have to go through the list backwards to keep deletes from interfering with iteration
// Have to go through the list backwards to keep deletes from interfering with iteration.
for (uint32_t i = childNodes->Length(); i > 0; --i) {
nsCOMPtr<nsIContent> childNode = childNodes->Item(i - 1);
if (childNode) {
@@ -2773,41 +2796,60 @@ nsEditor::JoinNodesImpl(nsINode* aNodeToKeep,
}
}
// delete the extra node
// Delete the extra node.
ErrorResult err;
aParent->RemoveChild(*aNodeToJoin, err);
if (GetShouldTxnSetSelection()) {
// editor wants us to set selection at join point
bool shouldSetSelection = GetShouldTxnSetSelection();
nsRefPtr<Selection> previousSelection;
for (size_t i = 0; i < savedRanges.Length(); ++i) {
// And adjust the selection if needed.
SavedRange& range = savedRanges[i];
// If we have not seen the selection yet, clear all of its ranges.
if (range.mSelection != previousSelection) {
nsresult rv = range.mSelection->RemoveAllRanges();
NS_ENSURE_SUCCESS(rv, rv);
previousSelection = range.mSelection;
}
if (shouldSetSelection &&
range.mSelection->Type() ==
nsISelectionController::SELECTION_NORMAL) {
// If the editor should adjust the selection, don't bother restoring
// the ranges for the normal selection here.
continue;
}
// Check to see if we joined nodes where selection starts.
if (range.mStartNode == aNodeToJoin) {
range.mStartNode = aNodeToKeep;
} else if (range.mStartNode == aNodeToKeep) {
range.mStartOffset += firstNodeLength;
}
// Check to see if we joined nodes where selection ends.
if (range.mEndNode == aNodeToJoin) {
range.mEndNode = aNodeToKeep;
} else if (range.mEndNode == aNodeToKeep) {
range.mEndOffset += firstNodeLength;
}
nsRefPtr<nsRange> newRange;
nsresult rv = nsRange::CreateRange(range.mStartNode, range.mStartOffset,
range.mEndNode, range.mEndOffset,
getter_AddRefs(newRange));
NS_ENSURE_SUCCESS(rv, rv);
rv = range.mSelection->AddRange(newRange);
NS_ENSURE_SUCCESS(rv, rv);
}
if (shouldSetSelection) {
// Editor wants us to set selection at join point.
nsRefPtr<Selection> selection = GetSelection();
NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
selection->Collapse(aNodeToKeep, AssertedCast<int32_t>(firstNodeLength));
} else if (selStartNode) {
// and adjust the selection if needed
// HACK: this is overly simplified - multi-range selections need more work than this
bool bNeedToAdjust = false;
// check to see if we joined nodes where selection starts
if (selStartNode == aNodeToJoin) {
bNeedToAdjust = true;
selStartNode = aNodeToKeep;
} else if (selStartNode == aNodeToKeep) {
bNeedToAdjust = true;
selStartOffset += firstNodeLength;
}
// check to see if we joined nodes where selection ends
if (selEndNode == aNodeToJoin) {
bNeedToAdjust = true;
selEndNode = aNodeToKeep;
} else if (selEndNode == aNodeToKeep) {
bNeedToAdjust = true;
selEndOffset += firstNodeLength;
}
// adjust selection if needed
if (bNeedToAdjust) {
selection->Collapse(selStartNode, selStartOffset);
selection->Extend(selEndNode, selEndOffset);
}
}
return err.ErrorCode();
+5 -1
View File
@@ -18,6 +18,7 @@
#include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc
#include "nsIPhonetic.h" // for NS_DECL_NSIPHONETIC, etc
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
#include "nsISelectionController.h" // for nsISelectionController constants
#include "nsISupportsImpl.h" // for nsEditor::Release, etc
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
#include "nsLiteralString.h" // for NS_LITERAL_STRING
@@ -421,6 +422,8 @@ protected:
*/
void EnsureComposition(mozilla::WidgetGUIEvent* aEvent);
nsresult GetSelection(int16_t aSelectionType, nsISelection** aSelection);
public:
/** All editor operations which alter the doc should be prefaced
@@ -618,7 +621,8 @@ public:
#if DEBUG_JOE
static void DumpNode(nsIDOMNode *aNode, int32_t indent=0);
#endif
mozilla::dom::Selection* GetSelection();
mozilla::dom::Selection* GetSelection(int16_t aSelectionType =
nsISelectionController::SELECTION_NORMAL);
// Helpers to add a node to the selection.
// Used by table cell selection methods
+2 -2
View File
@@ -254,7 +254,7 @@ nsresult NS_NewHTMLURIRefObject(nsIURIRefObject** aResult, nsIDOMNode* aNode)
*aResult = 0;
return rv;
}
return refObject->QueryInterface(NS_GET_IID(nsIURIRefObject),
(void**)aResult);
refObject.forget(aResult);
return NS_OK;
}
+1
View File
@@ -19,6 +19,7 @@ skip-if = buildapp == 'mulet'
[test_bug780908.xul]
[test_bug830600.html]
[test_bug1053048.html]
[test_bug1100966.html]
[test_bug1102906.html]
[test_bug1101392.html]
[test_bug1140617.xul]
@@ -0,0 +1,64 @@
<!DOCTYPE>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1100966
-->
<head>
<title>Test for Bug 1100966</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
</head>
<body>
<div id="display">
</div>
<div id="content" contenteditable>
=====<br>
correct<br>
fivee sixx<br>
====
</div>
<pre id="test">
</pre>
<script class="testbody" type="application/javascript">
/** Test for Bug 1100966 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
var div = document.getElementById("content");
div.focus();
synthesizeMouseAtCenter(div, {});
synthesizeKey(" ", {});
setTimeout(function() {
synthesizeKey("a", {});
setTimeout(function() {
synthesizeKey("VK_BACK_SPACE", {});
var sel = getSpellCheckSelection();
is(sel.rangeCount, 2, "We should have two misspelled words");
is(sel.getRangeAt(0), "fivee", "Correct misspelled word");
is(sel.getRangeAt(1), "sixx", "Correct misspelled word");
SimpleTest.finish();
},0);
},0);
});
function getSpellCheckSelection() {
var Ci = Components.interfaces;
var editingSession = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEditingSession);
var editor = editingSession.getEditorForWindow(window);
var selcon = editor.selectionController;
return selcon.getSelection(selcon.SELECTION_SPELLCHECK);
}
</script>
</body>
</html>
+2 -2
View File
@@ -2000,7 +2000,7 @@ nsTextServicesDocument::GetDocumentContentRootNode(nsIDOMNode **aNode)
NS_ENSURE_TRUE(bodyElement, NS_ERROR_FAILURE);
result = bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
bodyElement.forget(aNode);
}
else
{
@@ -2014,7 +2014,7 @@ nsTextServicesDocument::GetDocumentContentRootNode(nsIDOMNode **aNode)
NS_ENSURE_TRUE(docElement, NS_ERROR_FAILURE);
result = docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
docElement.forget(aNode);
}
return result;
@@ -288,10 +288,10 @@ nsControllerCommandGroup::IsCommandInGroup(const char *aCommand, const char *aGr
NS_IMETHODIMP
nsControllerCommandGroup::GetGroupsEnumerator(nsISimpleEnumerator **_retval)
{
nsGroupsEnumerator *groupsEnum = new nsGroupsEnumerator(mGroupsHash);
if (!groupsEnum) return NS_ERROR_OUT_OF_MEMORY;
nsRefPtr<nsGroupsEnumerator> groupsEnum = new nsGroupsEnumerator(mGroupsHash);
return groupsEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)_retval);
groupsEnum.forget(_retval);
return NS_OK;
}
/* nsISimpleEnumerator getEnumeratorForGroup (in DOMString aGroup); */
@@ -301,10 +301,10 @@ nsControllerCommandGroup::GetEnumeratorForGroup(const char *aGroup, nsISimpleEnu
nsDependentCString groupKey(aGroup);
nsTArray<nsCString> *commandList = mGroupsHash.Get(groupKey); // may be null
nsNamedGroupEnumerator *theGroupEnum = new nsNamedGroupEnumerator(commandList);
if (!theGroupEnum) return NS_ERROR_OUT_OF_MEMORY;
nsRefPtr<nsNamedGroupEnumerator> theGroupEnum = new nsNamedGroupEnumerator(commandList);
return theGroupEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator), (void **)_retval);
theGroupEnum.forget(_retval);
return NS_OK;
}
#if 0
@@ -409,8 +409,8 @@ nsresult nsWebBrowserFind::GetRootNode(nsIDOMDocument* aDomDoc,
rv = htmlDoc->GetBody(getter_AddRefs(bodyElement));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG_POINTER(bodyElement);
return bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode),
(void **)aNode);
bodyElement.forget(aNode);
return NS_OK;
}
// For non-HTML documents, the content root node will be the doc element.
@@ -418,7 +418,8 @@ nsresult nsWebBrowserFind::GetRootNode(nsIDOMDocument* aDomDoc,
rv = aDomDoc->GetDocumentElement(getter_AddRefs(docElement));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_ARG_POINTER(docElement);
return docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
docElement.forget(aNode);
return NS_OK;
}
nsresult nsWebBrowserFind::SetRangeAroundDocument(nsIDOMRange* aSearchRange,
+1 -1
View File
@@ -208,7 +208,7 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
// last paint.
float presShellResolution = aMetrics.GetPresShellResolution()
* aMetrics.GetAsyncZoom().scale;
aUtils->SetResolutionAndScaleTo(presShellResolution, presShellResolution);
aUtils->SetResolutionAndScaleTo(presShellResolution);
SetDisplayPortMargins(aUtils, content, aMetrics);
}
@@ -979,9 +979,11 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
ParentLayerPoint translation = userScroll - goannaScroll;
Matrix4x4 treeTransform = ViewTransform(asyncZoom, -translation);
SetShadowTransform(aLayer, oldTransform * treeTransform);
NS_ASSERTION(!aLayer->AsLayerComposite()->GetShadowTransformSetByAnimation(),
"overwriting animated transform!");
// Apply the tree transform on top of GetLocalTransform() here (rather than
// GetTransform()) in case the OMTA code in SampleAnimations already set a
// shadow transform; in that case we want to apply ours on top of that one
// rather than clobber it.
SetShadowTransform(aLayer, aLayer->GetLocalTransform() * treeTransform);
// Make sure that overscroll and under-zoom are represented in the old
// transform so that fixed position content moves and scales accordingly.
+2 -3
View File
@@ -651,9 +651,8 @@ nsStringBundleService::CreateExtensibleBundle(const char* aCategory,
return res;
}
res = bundle->QueryInterface(NS_GET_IID(nsIStringBundle), (void**) aResult);
return res;
bundle.forget(aResult);
return NS_OK;
}
#define GLOBAL_PROPERTIES "chrome://global/locale/global-strres.properties"
+9
View File
@@ -407,6 +407,15 @@ void MessageLoop::ReloadWorkQueue() {
}
bool MessageLoop::DeletePendingTasks() {
#ifdef DEBUG
if (!work_queue_.empty()) {
Task* task = work_queue_.front().task;
tracked_objects::Location loc = task->GetBirthPlace();
printf("Unexpected task! %s:%s:%d\n",
loc.function_name(), loc.file_name(), loc.line_number());
}
#endif
MOZ_ASSERT(work_queue_.empty());
bool did_work = !deferred_non_nestable_work_queue_.empty();
while (!deferred_non_nestable_work_queue_.empty()) {
+7
View File
@@ -81,6 +81,13 @@ void Tracked::SetBirthPlace(const Location& from_here) {
tracked_births_->RecordBirth();
}
Location Tracked::GetBirthPlace() const {
if (tracked_births_) {
return tracked_births_->location();
}
return Location();
}
void Tracked::ResetBirthTime() {
tracked_birth_time_ = Time::Now();
}
+1
View File
@@ -99,6 +99,7 @@ class Tracked {
// Used to record the FROM_HERE location of a caller.
void SetBirthPlace(const Location& from_here);
Location GetBirthPlace() const;
// When a task sits around a long time, such as in a timer, or object watcher,
// this method should be called when the task becomes active, and its
-30
View File
@@ -1,30 +0,0 @@
/* 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/. */
function referencesVia(from, edge, to) {
if (typeof findReferences !== 'function')
return true;
edge = "edge: " + edge;
var edges = findReferences(to);
if (edge in edges && edges[edge].indexOf(from) != -1)
return true;
// Be nice: make it easy to fix if the edge name has just changed.
var alternatives = [];
for (var e in edges) {
if (edges[e].indexOf(from) != -1)
alternatives.push(e);
}
if (alternatives.length == 0) {
print("referent not referred to by referrer after all");
} else {
print("referent is not referenced via: " + uneval(edge));
print("but it is referenced via: " + uneval(alternatives));
}
print("all incoming edges, from any object:");
for (var e in edges)
print(e);
return false;
}
@@ -1,9 +0,0 @@
// Binary: cache/js-dbg-64-06445f55f009-linux
// Flags:
//
var handler = { "\u0039" : function() {} };
var g = newGlobal();
if (typeof findReferences == 'function') {
findReferences(g);
}
@@ -1,11 +0,0 @@
// Binary: cache/js-dbg-64-ff51ddfdf5d1-linux
// Flags:
//
function makeGenerator() {
yield function generatorClosure() {};
}
var generator = makeGenerator();
if (typeof findReferences == 'function') {
findReferences(generator);
}
@@ -1,14 +0,0 @@
// Clearing a Map removes any strong references to its keys and values.
load(libdir + "referencesVia.js");
var m = new Map();
var k = {}, v = {};
m.set(k, v);
assertEq(referencesVia(m, "key", k), true);
assertEq(referencesVia(m, "value", v), true);
m.clear();
if (typeof findReferences == 'function') {
assertEq(referencesVia(m, "key", k), false);
assertEq(referencesVia(m, "value", v), false);
}
@@ -1,16 +0,0 @@
// Check marking through the keys of a Map.
load(libdir + "referencesVia.js");
var m = new Map;
for (var i = 0; i < 20; i++) {
var n = new Map;
n.set(m, i);
assertEq(referencesVia(n, 'key', m), true);
m = n;
}
gc();
gc();
// TODO: walk the chain using for-of to make sure everything is still there
@@ -1,14 +0,0 @@
// Check marking through the values of a Map.
load(libdir + "referencesVia.js");
var m = new Map;
for (var i = 0; i < 20; i++) {
var n = new Map;
n.set(i, m);
assertEq(referencesVia(n, 'value', m), true);
m = n;
}
gc();
gc();
@@ -1,12 +0,0 @@
// Maps do not keep deleted keys or values alive.
load(libdir + "referencesVia.js");
var m = new Map;
var k = {}, v = {};
m.set(k, v);
m.delete(k);
if (typeof findReferences == 'function') {
assertEq(referencesVia(m, 'key', k), false);
assertEq(referencesVia(m, 'value', v), false);
}
@@ -1,11 +0,0 @@
// Clearing a Set removes any strong references to its elements.
load(libdir + "referencesVia.js");
var s = new Set();
var obj = {};
s.add(obj);
assertEq(referencesVia(s, "key", obj), true);
s.clear();
if (typeof findReferences == 'function')
assertEq(referencesVia(s, "key", obj), false);
@@ -1,16 +0,0 @@
// Check marking through the elements of a Set.
load(libdir + "referencesVia.js");
var s = new Set;
for (var i = 0; i < 20; i++) {
var t = new Set;
t.add(s);
assertEq(referencesVia(t, 'key', s), true);
s = t;
}
gc();
gc();
// TODO: walk the chain and make sure it's still intact
@@ -1,10 +0,0 @@
// A Set iterator keeps the data alive.
load(libdir + "referencesVia.js");
load(libdir + "iteration.js");
var key = {};
var set = new Set([key]);
var iter = set[Symbol.iterator]();
referencesVia(iter, "**UNKNOWN SLOT 0**", set);
referencesVia(set, "key", key);
@@ -1,16 +0,0 @@
// An iterator keeps its data alive.
load(libdir + "iteration.js");
load(libdir + "referencesVia.js");
var key = {};
function test(obj, edgeName) {
var iter = obj[Symbol.iterator]();
referencesVia(iter, "**UNKNOWN SLOT 0**", obj);
referencesVia(obj, edgeName, key);
}
test([key], "element[0]");
test(new Map([[key, 'value']]), "key");
test(new Set([key]), "key");
@@ -1,13 +0,0 @@
// Array iterators keep the underlying array, arraylike object, or string alive.
load(libdir + "referencesVia.js");
load(libdir + "iteration.js");
function test(obj) {
var it = Array.prototype[Symbol.iterator].call(obj);
assertEq(referencesVia(it, "**UNKNOWN SLOT 0**", obj), true);
}
test([]);
test([1, 2, 3, 4]);
test({});
-3
View File
@@ -1,3 +0,0 @@
if (typeof findReferences == 'function') {
findReferences([schedulegc(1)])
}
+9 -1
View File
@@ -691,7 +691,15 @@ struct IonScriptCounts
for (size_t i = 0; i < numBlocks_; i++)
blocks_[i].destroy();
js_free(blocks_);
js_delete(previous_);
// The list can be long in some corner cases (bug 1140084), so
// unroll the recursion.
IonScriptCounts *victims = previous_;
while (victims) {
IonScriptCounts *victim = victims;
victims = victim->previous_;
victim->previous_ = nullptr;
js_delete(victim);
}
}
bool init(size_t numBlocks) {
+13 -2
View File
@@ -2398,6 +2398,8 @@ struct ArenasToUpdate
bool ArenasToUpdate::shouldProcessKind(AllocKind kind)
{
MOZ_ASSERT(kind < AllocKind::LIMIT);
// GC things that do not contain JSObject pointers don't need updating.
if (kind == AllocKind::FAT_INLINE_STRING ||
kind == AllocKind::STRING ||
kind == AllocKind::EXTERNAL_STRING ||
@@ -2406,10 +2408,19 @@ bool ArenasToUpdate::shouldProcessKind(AllocKind kind)
return false;
}
if (js::gc::IsBackgroundFinalized(kind))
// We try to update as many GC things in parallel as we can, but there are
// kinds for which this might not be safe:
// - we assume JSObjects that are foreground finalized are not safe to
// update in parallel
// - updating a shape touches child shapes in fixupShapeTreeAfterMovingGC()
if (js::gc::IsBackgroundFinalized(kind) &&
kind != AllocKind::SHAPE &&
kind != AllocKind::ACCESSOR_SHAPE)
{
return (kinds & BACKGROUND) != 0;
else
} else {
return (kinds & FOREGROUND) != 0;
}
}
ArenasToUpdate::ArenasToUpdate(JSRuntime *rt, KindsToUpdate kinds)
-26
View File
@@ -68,7 +68,6 @@
#include "js/StructuredClone.h"
#include "js/TrackedOptimizationInfo.h"
#include "perf/jsperf.h"
#include "shell/jsheaptools.h"
#include "shell/jsoptparse.h"
#include "shell/OSObject.h"
#include "vm/ArgumentsObject.h"
@@ -4618,31 +4617,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
" Tries to print a lot of information about the current stack. \n"
" Similar to the DumpJSStack() function in the browser."),
JS_FN_HELP("findReferences", FindReferences, 1, 0,
"findReferences(target)",
" Walk the entire heap, looking for references to |target|, and return a\n"
" \"references object\" describing what we found.\n"
"\n"
" Each property of the references object describes one kind of reference. The\n"
" property's name is the label supplied to MarkObject, JS_CALL_TRACER, or what\n"
" have you, prefixed with \"edge: \" to avoid collisions with system properties\n"
" (like \"toString\" and \"__proto__\"). The property's value is an array of things\n"
" that refer to |thing| via that kind of reference. Ordinary references from\n"
" one object to another are named after the property name (with the \"edge: \"\n"
" prefix).\n"
"\n"
" Garbage collection roots appear as references from 'null'. We use the name\n"
" given to the root (with the \"edge: \" prefix) as the name of the reference.\n"
"\n"
" Note that the references object does record references from objects that are\n"
" only reachable via |thing| itself, not just the references reachable\n"
" themselves from roots that keep |thing| from being collected. (We could make\n"
" this distinction if it is useful.)\n"
"\n"
" If there are any references on the native stack, the references\n"
" object will have properties named like \"edge: exact-value \"; the referrers\n"
" will be 'null', because they are roots."),
#endif
JS_FN_HELP("build", BuildDate, 0, 0,
"build()",
-577
View File
@@ -1,577 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#include "shell/jsheaptools.h"
#include "mozilla/Move.h"
#include <string.h>
#include "jsalloc.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsobj.h"
#include "jsprf.h"
#include "jsobjinlines.h"
using namespace js;
using mozilla::Move;
#ifdef DEBUG
/*** class HeapReverser **************************************************************************/
/*
* A class for constructing a map of the JavaScript heap, with all
* reference edges reversed.
*
* Unfortunately, it's not possible to build the results for findReferences
* while visiting things solely in the order that js::TraceRuntime and
* JS_TraceChildren reaches them. For example, as you work outward from the
* roots, suppose an edge from thing T reaches a "gray" thing G --- G being gray
* because you're still in the midst of traversing its descendants. At this
* point, you don't know yet whether G will be a referrer or not, and so you
* can't tell whether T should be a referrer either. And you won't visit T
* again.
*
* So we take a brute-force approach. We reverse the entire graph, and then walk
* outward from |target| to the representable objects that refer to it, stopping
* at such objects.
*/
/*
* A JSTracer that produces a map of the heap with edges reversed.
*
* HeapReversers must be allocated in a stack frame. (They are derived from
* CustomAutoRooter, and those must be allocated and destroyed in a stack-like
* order.)
*
* HeapReversers keep all the roots they find in their traversal alive until
* they are destroyed. So you don't need to worry about nodes going away while
* you're using them.
*/
class HeapReverser : public JSTracer, public JS::CustomAutoRooter
{
public:
struct Edge;
/* Metadata for a given Cell we have visited. */
class Node {
public:
Node() { }
explicit Node(JSGCTraceKind kind)
: kind(kind), incoming(), marked(false) { }
/*
* Move constructor and move assignment. These allow us to store our
* incoming edge Vector in the hash table: Vectors support moves, but
* not assignments or copy construction.
*/
Node(Node&& rhs)
: kind(rhs.kind), incoming(Move(rhs.incoming)), marked(rhs.marked) { }
Node& operator=(Node&& rhs) {
MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
this->~Node();
new(this) Node(Move(rhs));
return *this;
}
void trace(JSTracer* trc) {
for (Edge* e = incoming.begin(); e != incoming.end(); e++)
e->trace(trc);
}
/* What kind of Cell this is. */
JSGCTraceKind kind;
/*
* A vector of this Cell's incoming edges.
* This must use SystemAllocPolicy because HashMap requires its elements to
* be constructible with no arguments.
*/
Vector<Edge, 0, SystemAllocPolicy> incoming;
/* A mark bit, for other traversals. */
bool marked;
private:
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
};
/* Metadata for a heap edge we have traversed. */
struct Edge {
public:
Edge(char* name, void* origin) : name(name), origin(origin) { }
~Edge() { js_free(name); }
/*
* Move constructor and move assignment. These allow us to live in
* Vectors without needing to copy our name string when the vector is
* resized.
*/
Edge(Edge&& rhs) : name(rhs.name), origin(rhs.origin) {
rhs.name = nullptr;
}
Edge& operator=(Edge&& rhs) {
MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
this->~Edge();
new(this) Edge(Move(rhs));
return *this;
}
void trace(JSTracer* trc) {
if (origin)
gc::MarkGCThingRoot(trc, &origin, "HeapReverser::Edge");
}
/* The name of this heap edge. Owned by this Edge. */
char* name;
/*
* The Cell from which this edge originates. nullptr means a root. This
* is a cell address instead of a Node * because Nodes live in HashMap
* table entries; if the HashMap reallocates its table, all pointers to
* the Nodes it contains would become invalid. You should look up the
* address here in |map| to find its Node.
*/
void* origin;
};
/*
* The result of a reversal is a map from Cells' addresses to Node
* structures describing their incoming edges.
*/
typedef HashMap<void*, Node, DefaultHasher<void*>, SystemAllocPolicy> Map;
Map map;
/* Construct a HeapReverser for |context|'s heap. */
explicit HeapReverser(JSContext* cx)
: JSTracer(cx->runtime(), traverseEdgeWithThis),
JS::CustomAutoRooter(cx),
noggc(JS_GetRuntime(cx)),
nocgc(JS_GetRuntime(cx)),
runtime(JS_GetRuntime(cx)),
parent(nullptr)
{
}
bool init() { return map.init(); }
/* Build a reversed map of the heap in |map|. */
bool reverseHeap();
private:
JS::AutoDisableGenerationalGC noggc;
js::AutoDisableCompactingGC nocgc;
/* A runtime pointer for use by the destructor. */
JSRuntime* runtime;
/*
* Return the name of the most recent edge this JSTracer has traversed. The
* result is allocated with malloc; if we run out of memory, raise an error
* in this HeapReverser's context and return nullptr.
*
* This may not be called after that edge's call to traverseEdge has
* returned.
*/
char* getEdgeDescription();
/* Class for setting new parent, and then restoring the original. */
class AutoParent {
public:
AutoParent(HeapReverser* reverser, void* newParent) : reverser(reverser) {
savedParent = reverser->parent;
reverser->parent = newParent;
}
~AutoParent() {
reverser->parent = savedParent;
}
private:
HeapReverser* reverser;
void* savedParent;
};
/* A work item in the stack of nodes whose children we need to traverse. */
struct Child {
Child(void* cell, JSGCTraceKind kind) : cell(cell), kind(kind) { }
void* cell;
JSGCTraceKind kind;
};
/*
* A stack of work items. We represent the stack explicitly to avoid
* overflowing the C++ stack when traversing long chains of objects.
*/
Vector<Child, 0, SystemAllocPolicy> work;
/* When traverseEdge is called, the Cell and kind at which the edge originated. */
void* parent;
/* Traverse an edge. */
bool traverseEdge(void* cell, JSGCTraceKind kind);
/*
* js::TraceRuntime and JS_TraceChildren don't propagate error returns,
* and out-of-memory errors, by design, don't establish an exception in
* |context|, so traverseEdgeWithThis uses this to communicate the
* result of the traversal to reverseHeap.
*/
bool traversalStatus;
/* Static member function wrapping 'traverseEdge'. */
static void traverseEdgeWithThis(JSTracer* tracer, void** thingp, JSGCTraceKind kind) {
HeapReverser* reverser = static_cast<HeapReverser*>(tracer);
if (!reverser->traverseEdge(*thingp, kind))
reverser->traversalStatus = false;
}
/* Return a jsval representing a node, if possible; otherwise, return JSVAL_VOID. */
jsval nodeToValue(void* cell, int kind) {
if (kind != JSTRACE_OBJECT)
return JSVAL_VOID;
JSObject* object = static_cast<JSObject*>(cell);
return OBJECT_TO_JSVAL(object);
}
/* Keep all tracked objects live across GC. */
virtual void trace(JSTracer* trc) override {
if (!map.initialized())
return;
for (Map::Enum e(map); !e.empty(); e.popFront()) {
gc::MarkGCThingRoot(trc, const_cast<void**>(&e.front().key()), "HeapReverser::map::key");
e.front().value().trace(trc);
}
for (Child* c = work.begin(); c != work.end(); ++c)
gc::MarkGCThingRoot(trc, &c->cell, "HeapReverser::Child");
}
};
bool
HeapReverser::traverseEdge(void* cell, JSGCTraceKind kind)
{
/* Capture this edge before the JSTracer members get overwritten. */
char* edgeDescription = getEdgeDescription();
if (!edgeDescription)
return false;
Edge e(edgeDescription, parent);
Map::AddPtr a = map.lookupForAdd(cell);
if (!a) {
/*
* We've never visited this cell before. Add it to the map (thus
* marking it as visited), and put it on the work stack, to be
* visited from the main loop.
*/
Node n(kind);
Generation generation = map.generation();
if (!map.add(a, cell, Move(n)) ||
!work.append(Child(cell, kind)))
return false;
/* If the map has been resized, re-check the pointer. */
if (map.generation() != generation)
a = map.lookupForAdd(cell);
}
/* Add this edge to the reversed map. */
return a->value().incoming.append(Move(e));
}
bool
HeapReverser::reverseHeap()
{
traversalStatus = true;
/* Prime the work stack with the roots of collection. */
js::TraceRuntime(this);
if (!traversalStatus)
return false;
/* Traverse children until the stack is empty. */
while (!work.empty()) {
const Child child = work.popCopy();
AutoParent autoParent(this, child.cell);
JS_TraceChildren(this, child.cell, child.kind);
if (!traversalStatus)
return false;
}
return true;
}
char*
HeapReverser::getEdgeDescription()
{
if (!debugPrinter() && debugPrintIndex() == (size_t) -1) {
const char* arg = static_cast<const char*>(debugPrintArg());
char* name = js_pod_malloc<char>(strlen(arg) + 1);
if (!name)
return nullptr;
strcpy(name, arg);
return name;
}
/* Lovely; but a fixed size is required by JSTraceNamePrinter. */
static const int nameSize = 200;
char* name = js_pod_malloc<char>(nameSize);
if (!name)
return nullptr;
if (debugPrinter())
debugPrinter()(this, name, nameSize);
else
JS_snprintf(name, nameSize, "%s[%lu]",
static_cast<const char*>(debugPrintArg()), debugPrintIndex());
/* Shrink storage to fit. */
return static_cast<char*>(js_realloc(name, strlen(name) + 1));
}
/*** class ReferenceFinder ***********************************************************************/
/* A class for finding an object's referrers, given a reversed heap map. */
class ReferenceFinder {
public:
ReferenceFinder(JSContext* cx, const HeapReverser& reverser)
: context(cx), reverser(reverser), result(cx) { }
/* Produce an object describing all references to |target|. */
JSObject* findReferences(HandleObject target);
private:
/* The context in which to do allocation and error-handling. */
JSContext* context;
/* A reversed map of the current heap. */
const HeapReverser& reverser;
/* The results object we're currently building. */
RootedObject result;
/* A list of edges we've traversed to get to a certain point. */
class Path {
public:
Path(const HeapReverser::Edge& edge, Path* next) : edge(edge), next(next) { }
/*
* Compute the full path represented by this Path. The result is
* owned by the caller.
*/
char* computeName(JSContext* cx);
private:
const HeapReverser::Edge& edge;
Path* next;
};
struct AutoNodeMarker {
explicit AutoNodeMarker(HeapReverser::Node* node) : node(node) { node->marked = true; }
~AutoNodeMarker() { node->marked = false; }
private:
HeapReverser::Node* node;
};
/*
* Given that we've reached |cell| via |path|, with all Nodes along that
* path marked, add paths from all reportable objects reachable from cell
* to |result|.
*/
bool visit(void* cell, Path* path);
/*
* If |cell|, of |kind|, is representable as a JavaScript value, return that
* value; otherwise, return JSVAL_VOID.
*/
jsval representable(void* cell, int kind) {
if (kind == JSTRACE_OBJECT) {
JSObject* object = static_cast<JSObject*>(cell);
/* Certain classes of object are for internal use only. */
if (object->is<BlockObject>() ||
object->is<CallObject>() ||
object->is<StaticWithObject>() ||
object->is<DynamicWithObject>() ||
object->is<DeclEnvObject>()) {
return JSVAL_VOID;
}
/* Internal function objects should also not be revealed. */
if (JS_ObjectIsFunction(context, object) && IsInternalFunctionObject(object))
return JSVAL_VOID;
return OBJECT_TO_JSVAL(object);
}
return JSVAL_VOID;
}
/* Add |referrer| as something that refers to |target| via |path|. */
bool addReferrer(jsval referrer, Path* path);
};
bool
ReferenceFinder::visit(void* cell, Path* path)
{
/* In ReferenceFinder, paths will almost certainly fit on the C++ stack. */
JS_CHECK_RECURSION(context, return false);
/* Have we reached a root? Always report that. */
if (!cell)
return addReferrer(JSVAL_NULL, path);
HeapReverser::Map::Ptr p = reverser.map.lookup(cell);
MOZ_ASSERT(p);
HeapReverser::Node* node = &p->value();
/* Is |cell| a representable cell, reached via a non-empty path? */
if (path != nullptr) {
jsval representation = representable(cell, node->kind);
if (!representation.isUndefined())
return addReferrer(representation, path);
}
/*
* If we've made a cycle, don't traverse further. We *do* want to include
* paths from the target to itself, so we don't want to do this check until
* after we've possibly reported this cell as a referrer.
*/
if (node->marked)
return true;
AutoNodeMarker marker(node);
/* Visit the origins of all |cell|'s incoming edges. */
for (size_t i = 0; i < node->incoming.length(); i++) {
const HeapReverser::Edge& edge = node->incoming[i];
Path extendedPath(edge, path);
if (!visit(edge.origin, &extendedPath))
return false;
}
return true;
}
char*
ReferenceFinder::Path::computeName(JSContext* cx)
{
/* Walk the edge list and compute the total size of the path. */
size_t size = 6;
for (Path* l = this; l; l = l->next)
size += strlen(l->edge.name) + (l->next ? 2 : 0);
size += 1;
char* path = cx->pod_malloc<char>(size);
if (!path)
return nullptr;
/*
* Walk the edge list again, and copy the edge names into place, with
* appropriate separators. Note that we constructed the edge list from
* target to referrer, which means that the list links point *towards* the
* target, so we can walk the list and build the path from left to right.
*/
strcpy(path, "edge: ");
char* next = path + 6;
for (Path* l = this; l; l = l->next) {
strcpy(next, l->edge.name);
next += strlen(next);
if (l->next) {
strcpy(next, "; ");
next += 2;
}
}
MOZ_ASSERT(next + 1 == path + size);
return path;
}
bool
ReferenceFinder::addReferrer(jsval referrerArg, Path* path)
{
RootedValue referrer(context, referrerArg);
if (!context->compartment()->wrap(context, &referrer))
return false;
ScopedJSFreePtr<char> pathName(path->computeName(context));
if (!pathName)
return false;
/* Find the property of the results object named |pathName|. */
RootedValue v(context);
if (!JS_GetProperty(context, result, pathName, &v))
return false;
if (v.isUndefined()) {
/* Create an array to accumulate referents under this path. */
JSObject* array = JS_NewArrayObject(context, HandleValueArray(referrer));
if (!array)
return false;
v.setObject(*array);
return !!JS_SetProperty(context, result, pathName, v);
}
/* The property's value had better be an array. */
RootedObject array(context, &v.toObject());
MOZ_ASSERT(JS_IsArrayObject(context, array));
/* Append our referrer to this array. */
uint32_t length;
return JS_GetArrayLength(context, array, &length) &&
JS_SetElement(context, array, length, referrer);
}
JSObject*
ReferenceFinder::findReferences(HandleObject target)
{
result = JS_NewPlainObject(context);
if (!result)
return nullptr;
if (!visit(target, nullptr))
return nullptr;
return result;
}
/* See help(findReferences). */
bool
FindReferences(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"findReferences", "0", "s");
return false;
}
RootedValue target(cx, args[0]);
if (!target.isObject()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE,
"argument", "not an object");
return false;
}
/* Walk the JSRuntime, producing a reversed map of the heap. */
HeapReverser reverser(cx);
if (!reverser.init() || !reverser.reverseHeap())
return false;
/* Given the reversed map, find the referents of target. */
ReferenceFinder finder(cx, reverser);
Rooted<JSObject*> targetObj(cx, &target.toObject());
JSObject* references = finder.findReferences(targetObj);
if (!references)
return false;
args.rval().setObject(*references);
return true;
}
#endif /* DEBUG */
-18
View File
@@ -1,18 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
#ifndef shell_jsheaptools_h
#define shell_jsheaptools_h
#ifdef DEBUG
#include "js/TypeDecls.h"
bool FindReferences(JSContext* cx, unsigned argc, JS::Value* vp);
#endif /* DEBUG */
#endif /* shell_jsheaptools_h */
-1
View File
@@ -12,7 +12,6 @@ if CONFIG['JS_SHELL_NAME']:
UNIFIED_SOURCES += [
'js.cpp',
'jsheaptools.cpp',
'jsoptparse.cpp',
'OSObject.cpp'
]
@@ -1,64 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 422269;
var summary = 'Compile-time let block should not capture runtime references';
var actual = 'referenced only by stack and closure';
var expect = 'referenced only by stack and closure';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
function f()
{
let m = {sin: Math.sin};
(function holder() { m.sin(1); })();
return m;
}
if (typeof findReferences == 'undefined')
{
expect = actual = 'Test skipped';
print('Test skipped. Requires findReferences function.');
}
else
{
var x = f();
var refs = findReferences(x);
// At this point, x should only be referenced from the stack --- the
// variable 'x' itself, and any random things the conservative scanner
// finds --- and possibly from the 'holder' closure, which could itself
// be held alive for random reasons. Remove those from the refs list, and
// then complain if anything is left.
for (var edge in refs) {
// Remove references from roots, like the stack.
if (refs[edge].every(function (r) r === null))
delete refs[edge];
// Remove references from the closure, which could be held alive for
// random reasons.
else if (refs[edge].length === 1 &&
typeof refs[edge][0] === "function" &&
refs[edge][0].name === "holder")
delete refs[edge];
}
if (Object.keys(refs).length != 0)
actual = "unexpected references to the result of f: " + Object.keys(refs).join(", ");
}
reportCompare(expect, actual, summary);
exitFunc ('test');
}
@@ -1,54 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Contributor: Jim Blandy
if (typeof findReferences == "function") {
function C() {}
var o = new C;
o.x = {}; // via ordinary property
o[42] = {}; // via numeric property
o[123456789] = {}; // via ridiculous numeric property
o.myself = o; // self-references should be reported
o.alsoMyself = o; // multiple self-references should all be reported
assertEq(referencesVia(o, 'group; group_proto', C.prototype), true);
assertEq(referencesVia(o, 'shape; base; parent', this), true);
assertEq(referencesVia(o, 'x', o.x), true);
assertEq(referencesVia(o, 'objectElements[42]', o[42]), true);
assertEq(referencesVia(o, '123456789', o[123456789]), true);
assertEq(referencesVia(o, 'myself', o), true);
assertEq(referencesVia(o, 'alsoMyself', o), true);
function g() { return 42; }
function s(v) { }
var p = Object.defineProperty({}, 'a', { get:g, set:s });
assertEq(referencesVia(p, 'shape; getter', g), true);
assertEq(referencesVia(p, 'shape; setter', s), true);
// If there are multiple objects with the same shape referring to a getter
// or setter, findReferences should get all of them, even though the shape
// gets 'marked' the first time we visit it.
var q = Object.defineProperty({}, 'a', { get:g, set:s });
assertEq(referencesVia(p, 'shape; getter', g), true);
assertEq(referencesVia(q, 'shape; getter', g), true);
// If we extend each object's shape chain, both should still be able to
// reach the getter, even though the two shapes are each traversed twice.
p.b = 9;
q.b = 9;
assertEq(referencesVia(p, 'shape; parent; getter', g), true);
assertEq(referencesVia(q, 'shape; parent; getter', g), true);
// These are really just ordinary own property references.
assertEq(referencesVia(C, 'prototype', Object.getPrototypeOf(o)), true);
assertEq(referencesVia(Object.getPrototypeOf(o), 'constructor', C), true);
// Dense arrays should work, too.
a = [];
a[1] = o;
assertEq(referencesVia(a, 'objectElements[1]', o), true);
reportCompare(true, true);
} else {
reportCompare(true, true, "test skipped: findReferences is not a function");
}
@@ -1,25 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Contributor: Jim Blandy
if (typeof findReferences == "function") {
(function f() {
assertEq(referencesVia(arguments, 'callee', f), true);
})();
var o = ({});
function returnHeavy(y) { eval(''); Math.sin(); return function heavy() { return y; }; }
assertEq(referencesVia(returnHeavy(o), 'fun_environment; y', o), true);
assertEq(referencesVia(returnHeavy(o), 'fun_environment; enclosing_environment', this), true);
function returnBlock(z) { eval(''); let(w = z) { return function block() { return w; }; }; }
assertEq(referencesVia(returnBlock(o), 'fun_environment; w', o), true);
function returnWithObj(v) { with(v) return function withObj() { return u; }; }
assertEq(referencesVia(returnWithObj(o), 'fun_environment; with_object', o), true);
reportCompare(true, true);
} else {
reportCompare(true, true, "test skipped: findReferences is not a function");
}
@@ -1,45 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Contributor: Jim Blandy
if (typeof findReferences == "function") {
function makeGenerator(c) { eval(c); yield function generatorClosure() { return x; }; }
var generator = makeGenerator('var x = 42');
var closure = generator.next();
referencesVia(closure, 'parent; generator object', generator);
var o = {};
assertEq(function f() {
return referencesVia(null, 'arguments', arguments) ||
referencesVia(null, 'baseline-args-obj', arguments);
}(), true);
var rvalueCorrect;
function finallyHoldsRval() {
try {
return o;
} finally {
rvalueCorrect = referencesVia(null, 'rval', o) ||
referencesVia(null, 'baseline-rval', o);
}
}
rvalueCorrect = false;
finallyHoldsRval();
assertEq(rvalueCorrect, true);
// Because we don't distinguish between JavaScript stack marking and C++
// stack marking (both use the conservative scanner), we can't really write
// the following tests meaningfully:
// generator frame -> generator object
// stack frame -> local variables
// stack frame -> this
// stack frame -> callee
// for(... in x) loop's reference to x
reportCompare(true, true);
} else {
reportCompare(true, true, "test skipped: findReferences is not a function");
}
@@ -1,18 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Contributor: Jim Blandy
if (typeof findReferences == "function") {
var global = newGlobal();
var o = ({});
global.o = o;
// Don't trip a cross-compartment reference assertion.
findReferences(o);
reportCompare(true, true);
} else {
reportCompare(true, true, "test skipped: findReferences is not a function");
}
-24
View File
@@ -190,30 +190,6 @@ var Match =
})();
function referencesVia(from, edge, to) {
edge = "edge: " + edge;
var edges = findReferences(to);
if (edge in edges && edges[edge].indexOf(from) != -1)
return true;
// Be nice: make it easy to fix if the edge name has just changed.
var alternatives = [];
for (var e in edges) {
if (edges[e].indexOf(from) != -1)
alternatives.push(e);
}
if (alternatives.length == 0) {
print("referent not referred to by referrer after all");
} else {
print("referent is not referenced via: " + uneval(edge));
print("but it is referenced via: " + uneval(alternatives));
}
print("all incoming edges, from any object:");
for (var e in edges)
print(e);
return false;
}
// Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a
// smaller size is given, a regular ArrayBuffer will be returned instead.
function AsmJSArrayBuffer(size) {
+23 -1
View File
@@ -1523,6 +1523,27 @@ FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe
return nullptr;
}
/* static */ Layer*
FrameLayerBuilder::GetDebugSingleOldLayerForFrame(nsIFrame* aFrame)
{
nsTArray<DisplayItemData*>* array =
reinterpret_cast<nsTArray<DisplayItemData*>*>(aFrame->Properties().Get(LayerManagerDataProperty()));
if (!array) {
return nullptr;
}
Layer* layer = nullptr;
for (DisplayItemData* data : *array) {
if (layer && layer != data->mLayer) {
// More than one layer assigned, bail.
return nullptr;
}
layer = data->mLayer;
}
return layer;
}
already_AddRefed<ColorLayer>
ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted)
{
@@ -4264,8 +4285,9 @@ FrameLayerBuilder::GetPaintedLayerScaleForFrame(nsIFrame* aFrame)
}
}
float presShellResolution = last->PresContext()->PresShell()->GetResolution();
return PredictScaleForContent(aFrame, last,
last->PresContext()->PresShell()->GetResolution());
gfxSize(presShellResolution, presShellResolution));
}
#ifdef MOZ_DUMP_PAINTING
+8
View File
@@ -335,6 +335,14 @@ public:
static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey);
/**
* Return the layer that all display items of aFrame were assigned to in the
* last paint, or nullptr if there was no single layer assigned to all of the
* frame's display items (i.e. zero, or more than one).
* This function is for testing purposes and not performance sensitive.
*/
static Layer* GetDebugSingleOldLayerForFrame(nsIFrame* aFrame);
/**
* Destroy any stored LayerManagerDataProperty and the associated data for
* aFrame.
+4 -4
View File
@@ -408,16 +408,16 @@ IsElementClickableAndReadable(nsIFrame* aFrame, WidgetGUIEvent* aEvent, const Ev
nsSize frameSize = aFrame->GetSize();
nsPresContext* pc = aFrame->PresContext();
nsIPresShell* presShell = pc->PresShell();
gfxSize cumulativeResolution = presShell->GetCumulativeResolution();
if ((pc->AppUnitsToGfxUnits(frameSize.height) * cumulativeResolution.height) < limitReadableSize ||
(pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution.width) < limitReadableSize) {
float cumulativeResolution = presShell->GetCumulativeResolution();
if ((pc->AppUnitsToGfxUnits(frameSize.height) * cumulativeResolution) < limitReadableSize ||
(pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution) < limitReadableSize) {
return false;
}
nsRefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm),
nsLayoutUtils::FontSizeInflationFor(aFrame));
if (fm) {
if ((pc->AppUnitsToGfxUnits(fm->EmHeight()) * cumulativeResolution.height) < limitReadableSize) {
if ((pc->AppUnitsToGfxUnits(fm->EmHeight()) * cumulativeResolution) < limitReadableSize) {
return false;
}
}
+11 -11
View File
@@ -800,7 +800,7 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
// Only the root scrollable frame for a given presShell should pick up
// the presShell's resolution. All the other frames are 1.0.
if (aScrollFrame == presShell->GetRootScrollFrame()) {
metrics.SetPresShellResolution(presShell->GetXResolution());
metrics.SetPresShellResolution(presShell->GetResolution());
} else {
metrics.SetPresShellResolution(1.0f);
}
@@ -886,10 +886,10 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
} else {
LayoutDeviceIntSize contentSize;
if (nsLayoutUtils::GetContentViewerSize(presContext, contentSize)) {
LayoutDeviceToParentLayerScale2D scale;
LayoutDeviceToParentLayerScale scale;
if (presContext->GetParentPresContext()) {
gfxSize res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
scale = LayoutDeviceToParentLayerScale2D(res.width, res.height);
float res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
scale = LayoutDeviceToParentLayerScale(res);
}
metrics.mCompositionBounds.SizeTo(contentSize * scale);
}
@@ -1639,7 +1639,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
}
ContainerLayerParameters containerParameters
(presShell->GetXResolution(), presShell->GetYResolution());
(presShell->GetResolution(), presShell->GetResolution());
nsRefPtr<ContainerLayer> root = layerBuilder->
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
containerParameters, nullptr);
@@ -4222,8 +4222,8 @@ nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
bool isRootContentDocument = presContext->IsRootContentDocument();
nsIPresShell* presShell = presContext->PresShell();
ContainerLayerParameters params(
aContainerParameters.mXScale * presShell->GetXResolution(),
aContainerParameters.mYScale * presShell->GetYResolution(),
aContainerParameters.mXScale * presShell->GetResolution(),
aContainerParameters.mYScale * presShell->GetResolution(),
nsIntPoint(), aContainerParameters);
if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
rootScrollFrame->GetContent() &&
@@ -4345,15 +4345,15 @@ nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
const ContainerLayerParameters& aContainerParameters) {
nsIPresShell* presShell = mFrame->PresContext()->PresShell();
ContainerLayerParameters containerParameters(
presShell->GetXResolution(), presShell->GetYResolution(), nsIntPoint(),
presShell->GetResolution(), presShell->GetResolution(), nsIntPoint(),
aContainerParameters);
nsRefPtr<Layer> layer = nsDisplaySubDocument::BuildLayer(
aBuilder, aManager, containerParameters);
layer->SetPostScale(1.0f / presShell->GetXResolution(),
1.0f / presShell->GetYResolution());
layer->SetPostScale(1.0f / presShell->GetResolution(),
1.0f / presShell->GetResolution());
layer->AsContainerLayer()->SetScaleToResolution(
presShell->ScaleToResolution(), presShell->GetXResolution());
presShell->ScaleToResolution(), presShell->GetResolution());
return layer.forget();
}
+6 -9
View File
@@ -1381,17 +1381,15 @@ public:
*
* The resolution defaults to 1.0.
*/
virtual nsresult SetResolution(float aXResolution, float aYResolution) = 0;
gfxSize GetResolution() { return gfxSize(mXResolution, mYResolution); }
float GetXResolution() { return mXResolution; }
float GetYResolution() { return mYResolution; }
virtual gfxSize GetCumulativeResolution() = 0;
virtual nsresult SetResolution(float aResolution) = 0;
float GetResolution() { return mResolution; }
virtual float GetCumulativeResolution() = 0;
/**
* Similar to SetResolution() but also increases the scale of the content
* by the same amount.
*/
virtual nsresult SetResolutionAndScaleTo(float aXResolution, float aYResolution) = 0;
virtual nsresult SetResolutionAndScaleTo(float aResolution) = 0;
/**
* Return whether we are scaling to the set resolution.
@@ -1719,9 +1717,8 @@ protected:
nscolor mCanvasBackgroundColor;
// Used to force allocation and rendering of proportionally more or
// less pixels in the given dimension.
float mXResolution;
float mYResolution;
// less pixels in both dimensions.
float mResolution;
int16_t mSelectionFlags;
+20 -19
View File
@@ -892,9 +892,9 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
if (isRoot) {
// the base rect for root scroll frames is specified in the parent document
// coordinate space, so it doesn't include the local resolution.
gfxSize localRes = presContext->PresShell()->GetResolution();
parentRes.xScale /= localRes.width;
parentRes.yScale /= localRes.height;
float localRes = presContext->PresShell()->GetResolution();
parentRes.xScale /= localRes;
parentRes.yScale /= localRes;
}
ScreenRect screenRect = LayoutDeviceRect::FromAppUnits(base, auPerDevPixel)
* parentRes;
@@ -2818,7 +2818,7 @@ CalculateFrameMetricsForDisplayPort(nsIScrollableFrame* aScrollFrame) {
if (frame == presShell->GetRootScrollFrame()) {
// Only the root scrollable frame for a given presShell should pick up
// the presShell's resolution. All the other frames are 1.0.
resolution = presShell->GetXResolution();
resolution = presShell->GetResolution();
}
// Note: unlike in ComputeFrameMetrics(), we don't know the full cumulative
// resolution including FrameMetrics::mExtraResolution, because layout hasn't
@@ -2842,8 +2842,9 @@ CalculateFrameMetricsForDisplayPort(nsIScrollableFrame* aScrollFrame) {
LayoutDeviceToParentLayerScale2D compBoundsScale;
if (frame == presShell->GetRootScrollFrame() && presContext->IsRootContentDocument()) {
if (presContext->GetParentPresContext()) {
gfxSize res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
compBoundsScale = LayoutDeviceToParentLayerScale2D(res.width, res.height);
float res = presContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
compBoundsScale = LayoutDeviceToParentLayerScale2D(
LayoutDeviceToParentLayerScale(res));
}
} else {
compBoundsScale = cumulativeResolution * layerToParentLayerScale;
@@ -7638,12 +7639,12 @@ nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame)
widgetBounds.height * auPerDevPixel);
#ifdef MOZ_WIDGET_ANDROID
nsRect frameRect = aFrame->GetRect();
gfxSize cumulativeResolution = presShell->GetCumulativeResolution();
LayoutDeviceToParentLayerScale2D layoutToParentLayerScale =
float cumulativeResolution = presShell->GetCumulativeResolution();
LayoutDeviceToParentLayerScale layoutToParentLayerScale =
// The ScreenToParentLayerScale should be mTransformScale which is
// not calculated yet, but we don't yet handle CSS transforms, so we
// assume it's 1 here.
LayoutDeviceToLayerScale2D(cumulativeResolution.width, cumulativeResolution.height) *
LayoutDeviceToLayerScale(cumulativeResolution) *
LayerToScreenScale(1.0) * ScreenToParentLayerScale(1.0);
ParentLayerRect frameRectPixels =
LayoutDeviceRect::FromAppUnits(frameRect, auPerDevPixel)
@@ -7652,7 +7653,7 @@ nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame)
// Our return value is in appunits of the parent, so we need to
// include the resolution.
size.height =
NSToCoordRound(frameRect.height * cumulativeResolution.height);
NSToCoordRound(frameRect.height * cumulativeResolution);
}
#endif
} else {
@@ -7699,9 +7700,9 @@ nsLayoutUtils::CalculateRootCompositionSize(nsIFrame* aFrame,
// TODO: Reuse that code here.
nsIPresShell* rootPresShell = rootPresContext->PresShell();
if (nsIFrame* rootFrame = rootPresShell->GetRootFrame()) {
LayoutDeviceToLayerScale cumulativeResolution(
rootPresShell->GetCumulativeResolution().width
* nsLayoutUtils::GetTransformToAncestorScale(rootFrame).width);
LayoutDeviceToLayerScale2D cumulativeResolution(
rootPresShell->GetCumulativeResolution()
* nsLayoutUtils::GetTransformToAncestorScale(rootFrame));
int32_t rootAUPerDevPixel = rootPresContext->AppUnitsPerDevPixel();
LayerSize frameSize =
(LayoutDeviceRect::FromAppUnits(rootFrame->GetRect(), rootAUPerDevPixel)
@@ -7725,10 +7726,10 @@ nsLayoutUtils::CalculateRootCompositionSize(nsIFrame* aFrame,
} else {
LayoutDeviceIntSize contentSize;
if (nsLayoutUtils::GetContentViewerSize(rootPresContext, contentSize)) {
LayoutDeviceToLayerScale2D scale;
LayoutDeviceToLayerScale scale;
if (rootPresContext->GetParentPresContext()) {
gfxSize res = rootPresContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
scale = LayoutDeviceToLayerScale2D(res.width, res.height);
float res = rootPresContext->GetParentPresContext()->PresShell()->GetCumulativeResolution();
scale = LayoutDeviceToLayerScale(res);
}
rootCompositionSize = contentSize * scale * LayerToScreenScale(1.0f);
}
@@ -7800,9 +7801,9 @@ nsLayoutUtils::CalculateExpandedScrollableRect(nsIFrame* aFrame)
if (aFrame == aFrame->PresContext()->PresShell()->GetRootScrollFrame()) {
// the composition size for the root scroll frame does not include the
// local resolution, so we adjust.
gfxSize res = aFrame->PresContext()->PresShell()->GetResolution();
compSize.width = NSToCoordRound(compSize.width / ((float) res.width));
compSize.height = NSToCoordRound(compSize.height / ((float) res.height));
float res = aFrame->PresContext()->PresShell()->GetResolution();
compSize.width = NSToCoordRound(compSize.width / res);
compSize.height = NSToCoordRound(compSize.height / res);
}
if (scrollableRect.width < compSize.width) {
+15 -12
View File
@@ -777,8 +777,7 @@ PresShell::PresShell()
mPresArenaAllocCount = 0;
#endif
mRenderFlags = 0;
mXResolution = 1.0;
mYResolution = 1.0;
mResolution = 1.0;
mViewportOverridden = false;
mScrollPositionClampingScrollPortSizeSet = false;
@@ -5544,17 +5543,16 @@ void PresShell::SetIgnoreViewportScrolling(bool aIgnore)
SetRenderingState(state);
}
nsresult PresShell::SetResolutionImpl(float aXResolution, float aYResolution, bool aScaleToResolution)
nsresult PresShell::SetResolutionImpl(float aResolution, bool aScaleToResolution)
{
if (!(aXResolution > 0.0 && aYResolution > 0.0)) {
if (!(aResolution > 0.0)) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (aXResolution == mXResolution && aYResolution == mYResolution) {
if (aResolution == mResolution) {
return NS_OK;
}
RenderingState state(this);
state.mXResolution = aXResolution;
state.mYResolution = aYResolution;
state.mResolution = aResolution;
SetRenderingState(state);
mScaleToResolution = aScaleToResolution;
@@ -5566,12 +5564,12 @@ bool PresShell::ScaleToResolution() const
return mScaleToResolution;
}
gfxSize PresShell::GetCumulativeResolution()
float PresShell::GetCumulativeResolution()
{
gfxSize resolution = GetResolution();
float resolution = GetResolution();
nsPresContext* parentCtx = GetPresContext()->GetParentPresContext();
if (parentCtx) {
resolution = resolution * parentCtx->PresShell()->GetCumulativeResolution();
resolution *= parentCtx->PresShell()->GetCumulativeResolution();
}
return resolution;
}
@@ -5588,8 +5586,7 @@ void PresShell::SetRenderingState(const RenderingState& aState)
}
mRenderFlags = aState.mRenderFlags;
mXResolution = aState.mXResolution;
mYResolution = aState.mYResolution;
mResolution = aState.mResolution;
}
void PresShell::SynthesizeMouseMove(bool aFromScroll)
@@ -7414,6 +7411,12 @@ PresShell::HandleEvent(nsIFrame* aFrame,
frame == mFrameConstructor->GetRootFrame()) {
nsIFrame* popupFrame =
nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent);
// If a remote browser is currently capturing input break out if we
// detect a chrome generated popup.
if (popupFrame && capturingContent &&
EventStateManager::IsRemoteTarget(capturingContent)) {
capturingContent = nullptr;
}
// If the popupFrame is an ancestor of the 'frame', the frame should
// handle the event, otherwise, the popup should handle it.
if (popupFrame &&
+9 -12
View File
@@ -199,14 +199,14 @@ public:
virtual void SetIgnoreViewportScrolling(bool aIgnore) override;
virtual nsresult SetResolution(float aXResolution, float aYResolution) override {
return SetResolutionImpl(aXResolution, aYResolution, /* aScaleToResolution = */ false);
virtual nsresult SetResolution(float aResolution) override {
return SetResolutionImpl(aResolution, /* aScaleToResolution = */ false);
}
virtual nsresult SetResolutionAndScaleTo(float aXResolution, float aYResolution) override {
return SetResolutionImpl(aXResolution, aYResolution, /* aScaleToResolution = */ true);
virtual nsresult SetResolutionAndScaleTo(float aResolution) override {
return SetResolutionImpl(aResolution, /* aScaleToResolution = */ true);
}
virtual bool ScaleToResolution() const override;
virtual gfxSize GetCumulativeResolution() override;
virtual float GetCumulativeResolution() override;
//nsIViewObserver interface
@@ -464,12 +464,10 @@ protected:
struct RenderingState {
explicit RenderingState(PresShell* aPresShell)
: mXResolution(aPresShell->mXResolution)
, mYResolution(aPresShell->mYResolution)
: mResolution(aPresShell->mResolution)
, mRenderFlags(aPresShell->mRenderFlags)
{ }
float mXResolution;
float mYResolution;
float mResolution;
RenderFlags mRenderFlags;
};
@@ -482,8 +480,7 @@ protected:
~AutoSaveRestoreRenderingState()
{
mPresShell->mRenderFlags = mOldState.mRenderFlags;
mPresShell->mXResolution = mOldState.mXResolution;
mPresShell->mYResolution = mOldState.mYResolution;
mPresShell->mResolution = mOldState.mResolution;
}
PresShell* mPresShell;
@@ -762,7 +759,7 @@ protected:
// A list of images that are visible or almost visible.
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > mVisibleImages;
nsresult SetResolutionImpl(float aXResolution, float aYResolution, bool aScaleToResolution);
nsresult SetResolutionImpl(float aResolution, bool aScaleToResolution);
#ifdef DEBUG
// The reflow root under which we're currently reflowing. Null when
+4 -4
View File
@@ -21,7 +21,7 @@ public:
nsPresState()
: mContentData(nullptr)
, mScrollState(0, 0)
, mResolution(1.0, 1.0)
, mResolution(1.0)
, mScaleToResolution(false)
, mDisabledSet(false)
, mDisabled(false)
@@ -37,12 +37,12 @@ public:
return mScrollState;
}
void SetResolution(const gfxSize& aSize)
void SetResolution(float aSize)
{
mResolution = aSize;
}
gfxSize GetResolution() const
float GetResolution() const
{
return mResolution;
}
@@ -93,7 +93,7 @@ public:
protected:
nsCOMPtr<nsISupports> mContentData;
nsPoint mScrollState;
gfxSize mResolution;
float mResolution;
bool mScaleToResolution;
bool mDisabledSet;
bool mDisabled;
+6 -6
View File
@@ -1895,7 +1895,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
, mScrollPosAtLastPaint(0, 0)
, mRestorePos(-1, -1)
, mLastPos(-1, -1)
, mResolution(1.0, 1.0)
, mResolution(1.0)
, mScrollPosForLayerPixelAlignment(-1, -1)
, mLastUpdateImagesPos(-1, -1)
, mNeverHasVerticalScrollbar(false)
@@ -3305,14 +3305,14 @@ ScrollFrameHelper::GetScrollPositionClampingScrollPortSize() const
return mScrollPort.Size();
}
gfxSize
float
ScrollFrameHelper::GetResolution() const
{
return mResolution;
}
void
ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
ScrollFrameHelper::SetResolution(float aResolution)
{
mResolution = aResolution;
mIsResolutionSet = true;
@@ -3320,7 +3320,7 @@ ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
}
void
ScrollFrameHelper::SetResolutionAndScaleTo(const gfxSize& aResolution)
ScrollFrameHelper::SetResolutionAndScaleTo(float aResolution)
{
MOZ_ASSERT(mIsRoot); // This API should only be called on root scroll frames.
mResolution = aResolution;
@@ -5250,9 +5250,9 @@ ScrollFrameHelper::RestoreState(nsPresState* aState)
if (mIsRoot) {
nsIPresShell* presShell = mOuter->PresContext()->PresShell();
if (mScaleToResolution) {
presShell->SetResolutionAndScaleTo(mResolution.width, mResolution.height);
presShell->SetResolutionAndScaleTo(mResolution);
} else {
presShell->SetResolution(mResolution.width, mResolution.height);
presShell->SetResolution(mResolution);
}
}
}

Some files were not shown because too many files have changed in this diff Show More