Merge mozilla-central to b2g-inboind

This commit is contained in:
Carsten "Tomcat" Book 2015-11-12 12:40:40 +01:00
Родитель f8d5bb5846 fde361620f
Коммит d577fff5aa
279 изменённых файлов: 4128 добавлений и 2423 удалений

Просмотреть файл

@ -1015,7 +1015,6 @@ pref("apz.allow_zooming", true);
// Gaia relies heavily on scroll events for now, so lets fire them
// more often than the default value (100).
pref("apz.asyncscroll.throttle", 40);
pref("apz.pan_repaint_interval", 16);
// APZ physics settings, tuned by UX designers

Просмотреть файл

@ -5009,6 +5009,10 @@ nsBrowserAccess.prototype = {
isTabContentWindow: function (aWindow) {
return gBrowser.browsers.some(browser => browser.contentWindow == aWindow);
},
canClose() {
return CanCloseWindow();
},
}
function getTogglableToolbars() {
@ -6565,6 +6569,26 @@ var IndexedDBPromptHelper = {
}
};
function CanCloseWindow()
{
// Avoid redundant calls to canClose from showing multiple
// PermitUnload dialogs.
if (window.skipNextCanClose) {
return true;
}
for (let browser of gBrowser.browsers) {
let {permitUnload, timedOut} = browser.permitUnload();
if (timedOut) {
return true;
}
if (!permitUnload) {
return false;
}
}
return true;
}
function WindowIsClosing()
{
if (TabView.isVisible()) {
@ -6575,27 +6599,19 @@ function WindowIsClosing()
if (!closeWindow(false, warnAboutClosingWindow))
return false;
// Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process
if (gMultiProcessBrowser)
// In theory we should exit here and the Window's internal Close
// method should trigger canClose on nsBrowserAccess. However, by
// that point it's too late to be able to show a prompt for
// PermitUnload. So we do it here, when we still can.
if (CanCloseWindow()) {
// This flag ensures that the later canClose call does nothing.
// It's only needed to make tests pass, since they detect the
// prompt even when it's not actually shown.
window.skipNextCanClose = true;
return true;
for (let browser of gBrowser.browsers) {
let ds = browser.docShell;
// Passing true to permitUnload indicates we plan on closing the window.
// This means that once unload is permitted, all further calls to
// permitUnload will be ignored. This avoids getting multiple prompts
// to unload the page.
if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) {
// ... however, if the user aborts closing, we need to undo that,
// to ensure they get prompted again when we next try to close the window.
// We do this on the window's toplevel docshell instead of on the tab, so
// that all tabs we iterated before will get this reset.
window.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow();
return false;
}
}
return true;
return false;
}
/**

Просмотреть файл

@ -131,6 +131,11 @@ chatBrowserAccess.prototype = {
isTabContentWindow: function (aWindow) {
return this.contentWindow == aWindow;
},
canClose() {
let {BrowserUtils} = Cu.import("resource://gre/modules/BrowserUtils.jsm", {});
return BrowserUtils.canCloseWindow(window);
},
};
</script>

Просмотреть файл

@ -1,4 +1,4 @@
// -*- indent-tabs-mode: nil; js-indent-level: 4 -*-
// -*- 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/. */
@ -567,28 +567,17 @@ Sanitizer.prototype = {
openWindows: {
privateStateForNewWindow: "non-private",
_canCloseWindow: function(aWindow) {
// Bug 967873 - Proxy nsDocumentViewer::PermitUnload to the child process
if (!aWindow.gMultiProcessBrowser) {
// Cargo-culted out of browser.js' WindowIsClosing because we don't care
// about TabView or the regular 'warn me before closing windows with N tabs'
// stuff here, and more importantly, we want to set aCallerClosesWindow to true
// when calling into permitUnload:
for (let browser of aWindow.gBrowser.browsers) {
let ds = browser.docShell;
// 'true' here means we will be closing the window soon, so please don't dispatch
// another onbeforeunload event when we do so. If unload is *not* permitted somewhere,
// we will reset the flag that this triggers everywhere so that we don't interfere
// with the browser after all:
if (ds.contentViewer && !ds.contentViewer.permitUnload(true)) {
return false;
}
}
if (aWindow.CanCloseWindow()) {
// We already showed PermitUnload for the window, so let's
// make sure we don't do it again when we actually close the
// window.
aWindow.skipNextCanClose = true;
return true;
}
return true;
},
_resetAllWindowClosures: function(aWindowList) {
for (let win of aWindowList) {
win.getInterface(Ci.nsIDocShell).contentViewer.resetCloseWindow();
win.skipNextCanClose = false;
}
},
clear: Task.async(function*() {

Просмотреть файл

@ -1156,25 +1156,29 @@
this._tabAttrModified(this.mCurrentTab, ["selected"]);
if (oldBrowser != newBrowser &&
oldBrowser.docShell &&
oldBrowser.docShell.contentViewer.inPermitUnload) {
// Since the user is switching away from a tab that has
// a beforeunload prompt active, we remove the prompt.
// This prevents confusing user flows like the following:
// 1. User attempts to close Firefox
// 2. User switches tabs (ingoring a beforeunload prompt)
// 3. User returns to tab, presses "Leave page"
let promptBox = this.getTabModalPromptBox(oldBrowser);
let prompts = promptBox.listPrompts();
// There might not be any prompts here if the tab was closed
// while in an onbeforeunload prompt, which will have
// destroyed aforementioned prompt already, so check there's
// something to remove, first:
if (prompts.length) {
// NB: This code assumes that the beforeunload prompt
// is the top-most prompt on the tab.
prompts[prompts.length - 1].abortPrompt();
}
oldBrowser.getInPermitUnload) {
oldBrowser.getInPermitUnload(inPermitUnload => {
if (!inPermitUnload) {
return;
}
// Since the user is switching away from a tab that has
// a beforeunload prompt active, we remove the prompt.
// This prevents confusing user flows like the following:
// 1. User attempts to close Firefox
// 2. User switches tabs (ingoring a beforeunload prompt)
// 3. User returns to tab, presses "Leave page"
let promptBox = this.getTabModalPromptBox(oldBrowser);
let prompts = promptBox.listPrompts();
// There might not be any prompts here if the tab was closed
// while in an onbeforeunload prompt, which will have
// destroyed aforementioned prompt already, so check there's
// something to remove, first:
if (prompts.length) {
// NB: This code assumes that the beforeunload prompt
// is the top-most prompt on the tab.
prompts[prompts.length - 1].abortPrompt();
}
});
}
oldBrowser._urlbarFocused = (gURLBar && gURLBar.focused);
@ -2103,6 +2107,7 @@
if (aParams) {
var animate = aParams.animate;
var byMouse = aParams.byMouse;
var skipPermitUnload = aParams.skipPermitUnload;
}
// Handle requests for synchronously removing an already
@ -2115,7 +2120,7 @@
var isLastTab = (this.tabs.length - this._removingTabs.length == 1);
if (!this._beginRemoveTab(aTab, false, null, true))
if (!this._beginRemoveTab(aTab, false, null, true, skipPermitUnload))
return;
if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse)
@ -2163,6 +2168,7 @@
<parameter name="aTabWillBeMoved"/>
<parameter name="aCloseWindowWithLastTab"/>
<parameter name="aCloseWindowFastpath"/>
<parameter name="aSkipPermitUnload"/>
<body>
<![CDATA[
if (aTab.closing ||
@ -2193,23 +2199,20 @@
newTab = true;
}
if (!aTab._pendingPermitUnload && !aTabWillBeMoved) {
let ds = browser.docShell;
if (ds && ds.contentViewer) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() returns.
aTab._pendingPermitUnload = true;
let permitUnload = ds.contentViewer.permitUnload();
delete aTab._pendingPermitUnload;
// If we were closed during onbeforeunload, we return false now
// so we don't (try to) close the same tab again. Of course, we
// also stop if the unload was cancelled by the user:
if (aTab.closing || !permitUnload) {
// NB: deliberately keep the _closedDuringPermitUnload set to
// true so we keep exiting early in case of multiple calls.
return false;
}
if (!aTab._pendingPermitUnload && !aTabWillBeMoved && !aSkipPermitUnload) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() returns.
aTab._pendingPermitUnload = true;
let {permitUnload} = browser.permitUnload();
delete aTab._pendingPermitUnload;
// If we were closed during onbeforeunload, we return false now
// so we don't (try to) close the same tab again. Of course, we
// also stop if the unload was cancelled by the user:
if (aTab.closing || !permitUnload) {
// NB: deliberately keep the _closedDuringPermitUnload set to
// true so we keep exiting early in case of multiple calls.
return false;
}
}
@ -4001,8 +4004,8 @@
break;
case "sizemodechange":
if (aEvent.target == window) {
this.mCurrentBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser.setDocShellIsActiveAndForeground(
window.windowState != window.STATE_MINIMIZED);
}
break;
}
@ -4027,13 +4030,19 @@
}
case "DOMWindowClose": {
if (this.tabs.length == 1) {
// We already did PermitUnload in the content process
// for this tab (the only one in the window). So we don't
// need to do it again for any tabs.
window.skipNextCanClose = true;
window.close();
return;
}
let tab = this.getTabForBrowser(browser);
if (tab) {
this.removeTab(tab);
// Skip running PermitUnload since it already happened in
// the content process.
this.removeTab(tab, {skipPermitUnload: true});
}
break;
}
@ -4317,12 +4326,18 @@
if (!event.isTrusted)
return;
if (this.tabs.length == 1)
if (this.tabs.length == 1) {
// We already did PermitUnload in nsGlobalWindow::Close
// for this tab. There are no other tabs we need to do
// PermitUnload for.
window.skipNextCanClose = true;
return;
}
var tab = this._getTabForContentWindow(event.target);
if (tab) {
this.removeTab(tab);
// Skip running PermitUnload since it already happened.
this.removeTab(tab, {skipPermitUnload: true});
event.preventDefault();
}
]]>

Просмотреть файл

@ -149,7 +149,6 @@ skip-if = e10s # Bug 1101993 - times out for unknown reasons when run in the dir
[browser_backButtonFitts.js]
skip-if = os == "mac" # The Fitt's Law back button is not supported on OS X
[browser_beforeunload_duplicate_dialogs.js]
skip-if = e10s # bug 967873 means permitUnload doesn't work in e10s mode
[browser_blob-channelname.js]
[browser_bookmark_titles.js]
skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)

Просмотреть файл

@ -157,6 +157,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
if (action) {
switch (action.type) {
case "switchtab": // Fall through.
case "remotetab": // Fall through.
case "visiturl": {
returnValue = action.params.url;
break;
@ -1490,6 +1491,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
];
break;
case "switchtab":
case "remotetab":
parts = [
item.getAttribute("title"),
action.params.url,

Просмотреть файл

@ -575,6 +575,7 @@ BrowserGlue.prototype = {
switchtab: 6,
tag: 7,
visiturl: 8,
remotetab: 9,
};
if (actionType in buckets) {
Services.telemetry
@ -1329,7 +1330,7 @@ BrowserGlue.prototype = {
let wins = Services.wm.getEnumerator("navigator:browser");
while (wins.hasMoreElements()) {
let win = wins.getNext();
if (win.TabView._tabBrowserHasHiddenTabs() && win.TabView.firstUseExperienced()) {
if (win.TabView._tabBrowserHasHiddenTabs() && win.TabView.firstUseExperienced) {
haveTabGroups = true;
break;
}
@ -1905,7 +1906,7 @@ BrowserGlue.prototype = {
},
_migrateUI: function BG__migrateUI() {
const UI_VERSION = 33;
const UI_VERSION = 34;
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
let currentUIVersion = 0;
try {
@ -2250,7 +2251,7 @@ BrowserGlue.prototype = {
this._notifyNotificationsUpgrade().catch(Cu.reportError);
}
if (currentUIVersion < 33) {
if (currentUIVersion < 34) {
// We'll do something once windows are open:
this._mayNeedToWarnAboutTabGroups = true;
}

Просмотреть файл

@ -1176,7 +1176,7 @@ richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-t
font-size: 0.9em;
}
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
padding: 0 3px;
}

Просмотреть файл

@ -1854,13 +1854,13 @@ richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-t
color: -moz-nativehyperlinktext;
}
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-moz-image-region: rect(0, 16px, 11px, 0);
padding: 0 3px;
}
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(11px, 16px, 22px, 0);
}
@ -1879,13 +1879,13 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
list-style-image: url("chrome://browser/skin/places/tag@2x.png");
}
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab@2x.png");
-moz-image-region: rect(0, 32px, 22px, 0);
width: 22px;
}
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(22px, 32px, 44px, 0);
}
}

Просмотреть файл

@ -1537,7 +1537,7 @@ richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-si
}
}
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-moz-image-region: rect(0, 16px, 11px, 0);
padding: 0 3px;
@ -1546,7 +1546,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
}
@media (min-resolution: 1.1dppx) {
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab@2x.png");
-moz-image-region: rect(0, 32px, 22px, 0);
}
@ -1556,12 +1556,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
not all and (-moz-windows-default-theme) {
@media not all and (-moz-os-version: windows-win7),
not all and (-moz-windows-default-theme) {
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(11px, 16px, 22px, 0);
}
@media (min-resolution: 1.1dppx) {
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
richlistitem[type~="action"][actiontype$="tab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(22px, 32px, 44px, 0);
}
}

Просмотреть файл

@ -71,7 +71,6 @@ public:
bool MayLoadInternal(nsIURI* aURI) override;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
};
#endif // nsNullPrincipal_h__

Просмотреть файл

@ -25,6 +25,7 @@
#include "nsNetCID.h"
#include "jswrapper.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#include "mozilla/HashFunctions.h"
@ -76,7 +77,12 @@ nsPrincipal::nsPrincipal()
{ }
nsPrincipal::~nsPrincipal()
{ }
{
// let's clear the principal within the csp to avoid a tangling pointer
if (mCSP) {
static_cast<nsCSPContext*>(mCSP.get())->clearLoadingPrincipal();
}
}
nsresult
nsPrincipal::Init(nsIURI *aCodebase, const OriginAttributes& aOriginAttributes)
@ -404,7 +410,7 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
// need to link in the CSP context here (link in the URI of the protected
// resource).
if (csp) {
csp->SetRequestContext(codebase, nullptr, nullptr);
csp->SetRequestContext(nullptr, this);
}
SetDomain(domain);

1
config/external/nss/nss.def поставляемый
Просмотреть файл

@ -668,6 +668,7 @@ SSL_SetStapledOCSPResponses
SSL_SetURL
SSL_SNISocketConfigHook
SSL_VersionRangeGet
SSL_VersionRangeGetDefault
SSL_VersionRangeGetSupported
SSL_VersionRangeSet
SSL_VersionRangeSetDefault

Просмотреть файл

@ -127,6 +127,8 @@ $(addprefix $(TOPOBJDIR)/,$(MANIFEST_TARGETS)): FORCE
# Files to build with the recursive backend and simply copy
$(TOPOBJDIR)/dist/bin/platform.ini: $(TOPOBJDIR)/toolkit/xre/platform.ini
$(TOPOBJDIR)/toolkit/xre/platform.ini: $(TOPOBJDIR)/config/buildid
# The xpidl target in config/makefiles/xpidl requires the install manifest for
# dist/idl to have been processed.
$(TOPOBJDIR)/config/makefiles/xpidl/xpidl: $(TOPOBJDIR)/install-dist_idl

Просмотреть файл

@ -32,6 +32,10 @@ snapshot.io.save=Save
# saving a snapshot to disk.
snapshot.io.save.window=Save Heap Snapshot
# LOCALIZATION NOTE (snapshot.io.import.window): The title for the window displayed when
# importing a snapshot form disk.
snapshot.io.import.window=Import Heap Snapshot
# LOCALIZATION NOTE (snapshot.io.filter): The title for the filter used to
# filter file types (*.fxsnapshot)
snapshot.io.filter=Firefox Heap Snapshots
@ -60,6 +64,10 @@ toolbar.breakdownBy=Group by:
# taking a snapshot, either as the main label, or a tooltip.
take-snapshot=Take snapshot
# LOCALIZATION NOTE (import-snapshot): The label describing the button that initiates
# importing a snapshot.
import-snapshot=Import…
# LOCALIZATION NOTE (filter.placeholder): The placeholder text used for the
# memory tool's filter search box.
filter.placeholder=Filter
@ -89,6 +97,11 @@ tree-item.percent=%S%
# state SAVING, used in the main heap view.
snapshot.state.saving.full=Saving snapshot…
# LOCALIZATION NOTE (snapshot.state.importing.full): The label describing the snapshot
# state IMPORTING, used in the main heap view. %S represents the basename of the file
# imported.
snapshot.state.importing.full=Importing %S…
# LOCALIZATION NOTE (snapshot.state.reading.full): The label describing the snapshot
# state READING, and SAVED, due to these states being combined visually, used
# in the main heap view.
@ -106,6 +119,10 @@ snapshot.state.error.full=There was an error processing this snapshot.
# state SAVING, used in the snapshot list view
snapshot.state.saving=Saving snapshot…
# LOCALIZATION NOTE (snapshot.state.importing): The label describing the snapshot
# state IMPORTING, used in the snapshot list view
snapshot.state.importing=Importing snapshot…
# LOCALIZATION NOTE (snapshot.state.reading): The label describing the snapshot
# state READING, and SAVED, due to these states being combined visually, used
# in the snapshot list view.

Просмотреть файл

@ -3,9 +3,10 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { assert } = require("devtools/shared/DevToolsUtils");
const { reportException, assert } = require("devtools/shared/DevToolsUtils");
const { snapshotState: states, actions } = require("../constants");
const { L10N, openFilePicker } = require("../utils");
const { L10N, openFilePicker, createSnapshot } = require("../utils");
const { readSnapshot, takeCensus, selectSnapshot } = require("./snapshot");
const { OS } = require("resource://gre/modules/osfile.jsm");
const VALID_EXPORT_STATES = [states.SAVED, states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
@ -14,7 +15,8 @@ exports.pickFileAndExportSnapshot = function (snapshot) {
let outputFile = yield openFilePicker({
title: L10N.getFormatStr("snapshot.io.save.window"),
defaultName: OS.Path.basename(snapshot.path),
filters: [[L10N.getFormatStr("snapshot.io.filter"), "*.fxsnapshot"]]
filters: [[L10N.getFormatStr("snapshot.io.filter"), "*.fxsnapshot"]],
mode: "save",
});
if (!outputFile) {
@ -43,3 +45,43 @@ const exportSnapshot = exports.exportSnapshot = function (snapshot, dest) {
dispatch({ type: actions.EXPORT_SNAPSHOT_END, snapshot });
};
};
const pickFileAndImportSnapshotAndCensus = exports.pickFileAndImportSnapshotAndCensus = function (heapWorker) {
return function* (dispatch, getState) {
let input = yield openFilePicker({
title: L10N.getFormatStr("snapshot.io.import.window"),
filters: [[L10N.getFormatStr("snapshot.io.filter"), "*.fxsnapshot"]],
mode: "open",
});
if (!input) {
return;
}
yield dispatch(importSnapshotAndCensus(heapWorker, input.path));
};
};
const importSnapshotAndCensus = exports.importSnapshotAndCensus = function (heapWorker, path) {
return function* (dispatch, getState) {
let snapshot = createSnapshot();
// Override the defaults for a new snapshot
snapshot.path = path;
snapshot.state = states.IMPORTING;
snapshot.imported = true;
dispatch({ type: actions.IMPORT_SNAPSHOT_START, snapshot });
dispatch(selectSnapshot(snapshot));
try {
yield dispatch(readSnapshot(heapWorker, snapshot));
yield dispatch(takeCensus(heapWorker, snapshot));
} catch (error) {
reportException("importSnapshot", error);
dispatch({ type: actions.IMPORT_SNAPSHOT_ERROR, error, snapshot });
}
dispatch({ type: actions.IMPORT_SNAPSHOT_END, snapshot });
};
};

Просмотреть файл

@ -72,7 +72,7 @@ const takeSnapshot = exports.takeSnapshot = function (front) {
*/
const readSnapshot = exports.readSnapshot = function readSnapshot (heapWorker, snapshot) {
return function *(dispatch, getState) {
assert(snapshot.state === states.SAVED,
assert([states.SAVED, states.IMPORTING].includes(snapshot.state),
`Should only read a snapshot once. Found snapshot in state ${snapshot.state}`);
let creationTime;

Просмотреть файл

@ -9,7 +9,7 @@ const { toggleRecordingAllocationStacks } = require("./actions/allocations");
const { setBreakdownAndRefresh } = require("./actions/breakdown");
const { toggleInvertedAndRefresh } = require("./actions/inverted");
const { setFilterStringAndRefresh } = require("./actions/filter");
const { pickFileAndExportSnapshot } = require("./actions/io");
const { pickFileAndExportSnapshot, pickFileAndImportSnapshotAndCensus } = require("./actions/io");
const { selectSnapshotAndRefresh, takeSnapshotAndCensus } = require("./actions/snapshot");
const { breakdownNameToSpec, getBreakdownDisplayData } = require("./utils");
const Toolbar = createFactory(require("./components/toolbar"));
@ -61,6 +61,7 @@ const App = createClass({
Toolbar({
breakdowns: getBreakdownDisplayData(),
onImportClick: () => dispatch(pickFileAndImportSnapshotAndCensus(heapWorker)),
onTakeSnapshotClick: () => dispatch(takeSnapshotAndCensus(front, heapWorker)),
onBreakdownChange: breakdown =>
dispatch(setBreakdownAndRefresh(heapWorker, breakdownNameToSpec(breakdown))),

Просмотреть файл

@ -113,6 +113,7 @@ const Heap = module.exports = createClass({
dom.pre({}, safeErrorString(snapshot.error))
];
break;
case states.IMPORTING:
case states.SAVING:
case states.SAVED:
case states.READING:

Просмотреть файл

@ -14,6 +14,7 @@ const Toolbar = module.exports = createClass({
displayName: PropTypes.string.isRequired,
})).isRequired,
onTakeSnapshotClick: PropTypes.func.isRequired,
onImportClick: PropTypes.func.isRequired,
onBreakdownChange: PropTypes.func.isRequired,
onToggleRecordAllocationStacks: PropTypes.func.isRequired,
allocations: models.allocations,
@ -26,6 +27,7 @@ const Toolbar = module.exports = createClass({
render() {
let {
onTakeSnapshotClick,
onImportClick,
onBreakdownChange,
breakdowns,
onToggleRecordAllocationStacks,
@ -45,6 +47,14 @@ const Toolbar = module.exports = createClass({
title: L10N.getStr("take-snapshot")
}),
dom.button({
id: "import-snapshot",
className: "devtools-toolbarbutton import-snapshot devtools-button",
onClick: onImportClick,
title: L10N.getStr("import-snapshot"),
"data-text-only": true,
}, L10N.getStr("import-snapshot")),
dom.div({ className: "toolbar-group" },
dom.label({ className: "breakdown-by" },
L10N.getStr("toolbar.breakdownBy"),

Просмотреть файл

@ -29,6 +29,12 @@ actions.EXPORT_SNAPSHOT_START = "export-snapshot-start";
actions.EXPORT_SNAPSHOT_END = "export-snapshot-end";
actions.EXPORT_SNAPSHOT_ERROR = "export-snapshot-error";
// When a heap snapshot is being read from a user selected file,
// and represents the entire state until the census is available.
actions.IMPORT_SNAPSHOT_START = "import-snapshot-start";
actions.IMPORT_SNAPSHOT_END = "import-snapshot-end";
actions.IMPORT_SNAPSHOT_ERROR = "import-snapshot-error";
// Fired by UI to select a snapshot to view.
actions.SELECT_SNAPSHOT = "select-snapshot";
@ -93,14 +99,15 @@ const snapshotState = exports.snapshotState = {};
* Various states a snapshot can be in.
* An FSM describing snapshot states:
*
* SAVING -> SAVED -> READING -> READ <- <- <- SAVED_CENSUS
*
* SAVING_CENSUS
* SAVING -> SAVED -> READING -> READ SAVED_CENSUS
* IMPORTING
* SAVING_CENSUS
*
* Any of these states may go to the ERROR state, from which they can never
* leave (mwah ha ha ha!)
*/
snapshotState.ERROR = "snapshot-state-error";
snapshotState.IMPORTING = "snapshot-state-importing";
snapshotState.SAVING = "snapshot-state-saving";
snapshotState.SAVED = "snapshot-state-saved";
snapshotState.READING = "snapshot-state-reading";

Просмотреть файл

@ -39,13 +39,15 @@ let snapshotModel = exports.snapshot = PropTypes.shape({
filter: PropTypes.string,
// If an error was thrown while processing this snapshot, the `Error` instance is attached here.
error: PropTypes.object,
// Boolean indicating whether or not this snapshot was imported.
imported: PropTypes.bool.isRequired,
// The creation time of the snapshot; required after the snapshot has been read.
creationTime: PropTypes.number,
// The current state the snapshot is in.
// @see ./constants.js
state: function (snapshot, propName) {
let current = snapshot.state;
let shouldHavePath = [states.SAVED, states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
let shouldHavePath = [states.IMPORTING, states.SAVED, states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
let shouldHaveCreationTime = [states.READ, states.SAVING_CENSUS, states.SAVED_CENSUS];
let shouldHaveCensus = [states.SAVED_CENSUS];

Просмотреть файл

@ -28,6 +28,8 @@ handlers[actions.TAKE_SNAPSHOT_END] = function (snapshots, action) {
});
};
handlers[actions.IMPORT_SNAPSHOT_START] = handlers[actions.TAKE_SNAPSHOT_START];
handlers[actions.READ_SNAPSHOT_START] = function (snapshots, action) {
let snapshot = getSnapshot(snapshots, action.snapshot);
snapshot.state = states.READING;

Просмотреть файл

@ -119,3 +119,12 @@ function isBreakdownType (census, type) {
throw new Error(`isBreakdownType does not yet support ${type}`);
}
}
function *createTempFile () {
let file = FileUtils.getFile("TmpD", ["tmp.fxsnapshot"]);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
let destPath = file.path;
let stat = yield OS.File.stat(destPath);
ok(stat.size === 0, "new file is 0 bytes at start");
return destPath;
}

Просмотреть файл

@ -18,12 +18,7 @@ add_task(function *() {
let store = Store();
const { getState, dispatch } = store;
let file = FileUtils.getFile("TmpD", ["tmp.fxsnapshot"]);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
let destPath = file.path;
let stat = yield OS.File.stat(destPath);
ok(stat.size === 0, "new file is 0 bytes at start");
let destPath = yield createTempFile();
dispatch(takeSnapshotAndCensus(front, heapWorker));
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);

Просмотреть файл

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the task creator `importSnapshotAndCensus()` for the whole flow of
* importing a snapshot, and its sub-actions.
*/
let { actions, snapshotState: states } = require("devtools/client/memory/constants");
let { breakdownEquals } = require("devtools/client/memory/utils");
let { exportSnapshot, importSnapshotAndCensus } = require("devtools/client/memory/actions/io");
let { takeSnapshotAndCensus } = require("devtools/client/memory/actions/snapshot");
function run_test() {
run_next_test();
}
add_task(function *() {
let front = new StubbedMemoryFront();
let heapWorker = new HeapAnalysesClient();
yield front.attach();
let store = Store();
let { subscribe, dispatch, getState } = store;
let destPath = yield createTempFile();
dispatch(takeSnapshotAndCensus(front, heapWorker));
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
let exportEvents = Promise.all([
waitUntilAction(store, actions.EXPORT_SNAPSHOT_START),
waitUntilAction(store, actions.EXPORT_SNAPSHOT_END)
]);
dispatch(exportSnapshot(getState().snapshots[0], destPath));
yield exportEvents;
// Now import our freshly exported snapshot
let i = 0;
let expected = ["IMPORTING", "READING", "READ", "SAVING_CENSUS", "SAVED_CENSUS"];
let expectStates = () => {
let snapshot = getState().snapshots[1];
if (!snapshot) {
return;
}
let isCorrectState = snapshot.state === states[expected[i]];
if (isCorrectState) {
ok(true, `Found expected state ${expected[i]}`);
i++;
}
};
let unsubscribe = subscribe(expectStates);
dispatch(importSnapshotAndCensus(heapWorker, destPath));
yield waitUntilState(store, () => i === 5);
unsubscribe();
equal(i, 5, "importSnapshotAndCensus() produces the correct sequence of states in a snapshot");
equal(getState().snapshots[1].state, states.SAVED_CENSUS, "imported snapshot is in SAVED_CENSUS state");
ok(getState().snapshots[1].selected, "imported snapshot is selected");
// Check snapshot data
let snapshot1 = getState().snapshots[0];
let snapshot2 = getState().snapshots[1];
ok(breakdownEquals(snapshot1.breakdown, snapshot2.breakdown),
"imported snapshot has correct breakdown");
// Clone the census data so we can destructively remove the ID/parents to compare
// equal census data
let census1 = stripUnique(JSON.parse(JSON.stringify(snapshot1.census)));
let census2 = stripUnique(JSON.parse(JSON.stringify(snapshot2.census)));
equal(JSON.stringify(census1), JSON.stringify(census2), "Imported snapshot has correct census");
function stripUnique (obj) {
let children = obj.children || [];
for (let child of children) {
delete child.id;
delete child.parent;
stripUnique(child);
}
delete obj.id;
delete obj.parent;
return obj;
}
});

Просмотреть файл

@ -9,6 +9,7 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_action-filter-01.js]
[test_action-filter-02.js]
[test_action-filter-03.js]
[test_action-import-snapshot-and-census.js]
[test_action-select-snapshot.js]
[test_action-set-breakdown.js]
[test_action-set-breakdown-and-refresh-01.js]

Просмотреть файл

@ -9,6 +9,7 @@ const STRINGS_URI = "chrome://devtools/locale/memory.properties"
const L10N = exports.L10N = new ViewHelpers.L10N(STRINGS_URI);
const { URL } = require("sdk/url");
const { OS } = require("resource://gre/modules/osfile.jsm");
const { assert } = require("devtools/shared/DevToolsUtils");
const { Preferences } = require("resource://gre/modules/Preferences.jsm");
const CUSTOM_BREAKDOWN_PREF = "devtools.memory.custom-breakdowns";
@ -27,6 +28,11 @@ exports.getSnapshotTitle = function (snapshot) {
return L10N.getStr("snapshot-title.loading");
}
if (snapshot.imported) {
// Strip out the extension if it's the expected ".fxsnapshot"
return OS.Path.basename(snapshot.path.replace(/\.fxsnapshot$/, ""));
}
let date = new Date(snapshot.creationTime / 1000);
return date.toLocaleTimeString(void 0, {
year: "2-digit",
@ -124,6 +130,8 @@ exports.getSnapshotStatusText = function (snapshot) {
return L10N.getStr("snapshot.state.error");
case states.SAVING:
return L10N.getStr("snapshot.state.saving");
case states.IMPORTING:
return L10N.getStr("snapshot.state.importing");
case states.SAVED:
case states.READING:
return L10N.getStr("snapshot.state.reading");
@ -155,6 +163,8 @@ exports.getSnapshotStatusTextFull = function (snapshot) {
return L10N.getStr("snapshot.state.error.full");
case states.SAVING:
return L10N.getStr("snapshot.state.saving.full");
case states.IMPORTING:
return L10N.getFormatStr("snapshot.state.importing", OS.Path.basename(snapshot.path));
case states.SAVED:
case states.READING:
return L10N.getStr("snapshot.state.reading.full");
@ -198,6 +208,8 @@ exports.createSnapshot = function createSnapshot () {
state: states.SAVING,
census: null,
path: null,
imported: false,
selected: false,
};
};
@ -327,12 +339,21 @@ exports.parseSource = function (source) {
* (like "*.json").
* @param {String} .defaultName
* The default name chosen by the file picker window.
* @param {String} .mode
* The mode that this filepicker should open in. Can be "open" or "save".
* @return {Promise<?nsILocalFile>}
* The file selected by the user, or null, if cancelled.
*/
exports.openFilePicker = function({ title, filters, defaultName }) {
exports.openFilePicker = function({ title, filters, defaultName, mode }) {
mode = mode === "save" ? Ci.nsIFilePicker.modeSave :
mode === "open" ? Ci.nsIFilePicker.modeOpen : null;
if (mode == void 0) {
throw new Error("No valid mode specified for nsIFilePicker.");
}
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, title, Ci.nsIFilePicker.modeSave);
fp.init(window, title, mode);
for (let filter of (filters || [])) {
fp.appendFilter(filter[0], filter[1]);

Просмотреть файл

@ -18,10 +18,11 @@ const EVENTS = {
TARGET_WILL_NAVIGATE: "NetMonitor:TargetWillNavigate",
TARGET_DID_NAVIGATE: "NetMonitor:TargetNavigate",
// When a network event is received.
// When a network or timeline event is received.
// See https://developer.mozilla.org/docs/Tools/Web_Console/remoting for
// more information about what each packet is supposed to deliver.
NETWORK_EVENT: "NetMonitor:NetworkEvent",
TIMELINE_EVENT: "NetMonitor:TimelineEvent",
// When a network event is added to the view
REQUEST_ADDED: "NetMonitor:RequestAdded",
@ -124,6 +125,7 @@ const Editor = require("devtools/client/sourceeditor/editor");
const {Tooltip} = require("devtools/client/shared/widgets/Tooltip");
const {ToolSidebar} = require("devtools/client/framework/sidebar");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const {TimelineFront} = require("devtools/server/actors/timeline");
XPCOMUtils.defineConstant(this, "EVENTS", EVENTS);
XPCOMUtils.defineConstant(this, "ACTIVITY_TYPE", ACTIVITY_TYPE);
@ -163,21 +165,22 @@ Object.defineProperty(this, "NetworkHelper", {
*/
var NetMonitorController = {
/**
* Initializes the view.
* Initializes the view and connects the monitor client.
*
* @return object
* A promise that is resolved when the monitor finishes startup.
*/
startupNetMonitor: function() {
startupNetMonitor: Task.async(function*() {
if (this._startup) {
return this._startup;
return this._startup.promise;
}
NetMonitorView.initialize();
// Startup is synchronous, for now.
return this._startup = promise.resolve();
},
this._startup = promise.defer();
{
NetMonitorView.initialize();
yield this.connect();
}
this._startup.resolve();
}),
/**
* Destroys the view and disconnects the monitor client from the server.
@ -185,19 +188,19 @@ var NetMonitorController = {
* @return object
* A promise that is resolved when the monitor finishes shutdown.
*/
shutdownNetMonitor: function() {
shutdownNetMonitor: Task.async(function*() {
if (this._shutdown) {
return this._shutdown;
return this._shutdown.promise;
}
NetMonitorView.destroy();
this.TargetEventsHandler.disconnect();
this.NetworkEventsHandler.disconnect();
this.disconnect();
// Shutdown is synchronous, for now.
return this._shutdown = promise.resolve();
},
this._shutdown = promise.defer();;
{
NetMonitorView.destroy();
this.TargetEventsHandler.disconnect();
this.NetworkEventsHandler.disconnect();
yield this.disconnect();
}
this._shutdown.resolve();
}),
/**
* Initiates remote or chrome network monitoring based on the current target,
@ -210,47 +213,78 @@ var NetMonitorController = {
*/
connect: Task.async(function*() {
if (this._connection) {
return this._connection;
return this._connection.promise;
}
this._connection = promise.defer();
let deferred = promise.defer();
this._connection = deferred.promise;
this.client = this._target.client;
// Some actors like AddonActor or RootActor for chrome debugging
// aren't actual tabs.
if (this._target.isTabActor) {
this.tabClient = this._target.activeTab;
}
this.webConsoleClient = this._target.activeConsole;
this.webConsoleClient.setPreferences(NET_PREFS, () => {
this.TargetEventsHandler.connect();
this.NetworkEventsHandler.connect();
deferred.resolve();
});
yield deferred.promise;
let connectWebConsole = () => {
let deferred = promise.defer();
this.webConsoleClient = this._target.activeConsole;
this.webConsoleClient.setPreferences(NET_PREFS, deferred.resolve);
return deferred.promise;
};
let connectTimeline = () => {
// Don't start up waiting for timeline markers if the server isn't
// recent enough to emit the markers we're interested in.
if (this._target.getTrait("documentLoadingMarkers")) {
this.timelineFront = new TimelineFront(this._target.client, this._target.form);
return this.timelineFront.start({ withDocLoadingEvents: true });
}
};
yield connectWebConsole();
yield connectTimeline();
this.TargetEventsHandler.connect();
this.NetworkEventsHandler.connect();
window.emit(EVENTS.CONNECTED);
this._connection.resolve();
this._connected = true;
}),
/**
* Disconnects the debugger client and removes event handlers as necessary.
*/
disconnect: function() {
disconnect: Task.async(function*() {
if (this._disconnection) {
return this._disconnection.promise;
}
this._disconnection = promise.defer();
// Wait for the connection to finish first.
yield this._connection.promise;
// When debugging local or a remote instance, the connection is closed by
// the RemoteTarget.
this._connection = null;
this.client = null;
// the RemoteTarget. The webconsole actor is stopped on disconnect.
this.tabClient = null;
this.webConsoleClient = null;
},
// The timeline front wasn't initialized and started if the server wasn't
// recent enough to emit the markers we were interested in.
if (this._target.getTrait("documentLoadingMarkers")) {
yield this.timelineFront.destroy();
this.timelineFront = null;
}
this._disconnection.resolve();
this._connected = false;
}),
/**
* Checks whether the netmonitor connection is active.
* @return boolean
*/
isConnected: function() {
return !!this.client;
return !!this._connected;
},
/**
@ -391,15 +425,7 @@ var NetMonitorController = {
get supportsPerfStats() {
return this.tabClient &&
(this.tabClient.traits.reconfigure || !this._target.isApp);
},
_startup: null,
_shutdown: null,
_connection: null,
_currentActivity: null,
client: null,
tabClient: null,
webConsoleClient: null
}
};
/**
@ -458,6 +484,8 @@ TargetEventsHandler.prototype = {
if (NetMonitorController.getCurrentActivity() == ACTIVITY_TYPE.NONE) {
NetMonitorView.showNetworkInspectorView();
}
// Clear any accumulated markers.
NetMonitorController.NetworkEventsHandler.clearMarkers();
window.emit(EVENTS.TARGET_WILL_NAVIGATE);
break;
@ -481,8 +509,11 @@ TargetEventsHandler.prototype = {
* Functions handling target network events.
*/
function NetworkEventsHandler() {
this._markers = [];
this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
this._onDocLoadingMarker = this._onDocLoadingMarker.bind(this);
this._onRequestHeaders = this._onRequestHeaders.bind(this);
this._onRequestCookies = this._onRequestCookies.bind(this);
this._onRequestPostData = this._onRequestPostData.bind(this);
@ -501,6 +532,20 @@ NetworkEventsHandler.prototype = {
return NetMonitorController.webConsoleClient;
},
get timelineFront() {
return NetMonitorController.timelineFront;
},
get firstDocumentDOMContentLoadedTimestamp() {
let marker = this._markers.filter(e => e.name == "document::DOMContentLoaded")[0];
return marker ? marker.unixTime / 1000 : -1;
},
get firstDocumentLoadTimestamp() {
let marker = this._markers.filter(e => e.name == "document::Load")[0];
return marker ? marker.unixTime / 1000 : -1;
},
/**
* Connect to the current target client.
*/
@ -508,9 +553,30 @@ NetworkEventsHandler.prototype = {
dumpn("NetworkEventsHandler is connecting...");
this.webConsoleClient.on("networkEvent", this._onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate", this._onNetworkEventUpdate);
if (this.timelineFront) {
this.timelineFront.on("doc-loading", this._onDocLoadingMarker);
}
this._displayCachedEvents();
},
/**
* Disconnect from the client.
*/
disconnect: function() {
if (!this.client) {
return;
}
dumpn("NetworkEventsHandler is disconnecting...");
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
if (this.timelineFront) {
this.timelineFront.off("doc-loading", this._onDocLoadingMarker);
}
},
/**
* Display any network events already in the cache.
*/
@ -531,15 +597,12 @@ NetworkEventsHandler.prototype = {
},
/**
* Disconnect from the client.
* The "DOMContentLoaded" and "Load" events sent by the timeline actor.
* @param object marker
*/
disconnect: function() {
if (!this.client) {
return;
}
dumpn("NetworkEventsHandler is disconnecting...");
this.webConsoleClient.off("networkEvent", this._onNetworkEvent);
this.webConsoleClient.off("networkEventUpdate", this._onNetworkEventUpdate);
_onDocLoadingMarker: function(marker) {
window.emit(EVENTS.TIMELINE_EVENT, marker);
this._markers.push(marker);
},
/**
@ -741,6 +804,13 @@ NetworkEventsHandler.prototype = {
});
},
/**
* Clears all accumulated markers.
*/
clearMarkers: function() {
this._markers.length = 0;
},
/**
* Fetches the full text of a LongString.
*

Просмотреть файл

@ -30,6 +30,8 @@ const REQUESTS_WATERFALL_BACKGROUND_TICKS_SPACING_MIN = 10; // px
const REQUESTS_WATERFALL_BACKGROUND_TICKS_COLOR_RGB = [128, 136, 144];
const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 32; // byte
const REQUESTS_WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 32; // byte
const REQUESTS_WATERFALL_DOMCONTENTLOADED_TICKS_COLOR_RGBA = [255, 0, 0, 128];
const REQUESTS_WATERFALL_LOAD_TICKS_COLOR_RGBA = [0, 0, 255, 128];
const REQUEST_TIME_DECIMALS = 2;
const HEADERS_SIZE_DECIMALS = 3;
const CONTENT_SIZE_DECIMALS = 2;
@ -1086,6 +1088,7 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* Removes all network requests and closes the sidebar if open.
*/
clear: function() {
NetMonitorController.NetworkEventsHandler.clearMarkers();
NetMonitorView.Sidebar.toggle(false);
$("#details-pane-toggle").disabled = true;
@ -1962,6 +1965,19 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
}
}
{
let t = NetMonitorController.NetworkEventsHandler.firstDocumentDOMContentLoadedTimestamp;
let delta = Math.floor((t - this._firstRequestStartedMillis) * aScale);
let [r, g, b, a] = REQUESTS_WATERFALL_DOMCONTENTLOADED_TICKS_COLOR_RGBA;
view32bit[delta] = (a << 24) | (r << 16) | (g << 8) | b;
}
{
let t = NetMonitorController.NetworkEventsHandler.firstDocumentLoadTimestamp;
let delta = Math.floor((t - this._firstRequestStartedMillis) * aScale);
let [r, g, b, a] = REQUESTS_WATERFALL_LOAD_TICKS_COLOR_RGBA;
view32bit[delta] = (a << 24) | (r << 16) | (g << 8) | b;
}
// Flush the image data and cache the waterfall background.
pixelArray.set(view8bit);
ctx.putImageData(imageData, 0, 0);

Просмотреть файл

@ -13,7 +13,6 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
function NetMonitorPanel(iframeWindow, toolbox) {
this.panelWin = iframeWindow;
this._toolbox = toolbox;
this._destroyer = null;
this._view = this.panelWin.NetMonitorView;
this._controller = this.panelWin.NetMonitorController;
@ -31,28 +30,25 @@ NetMonitorPanel.prototype = {
* @return object
* A promise that is resolved when the NetMonitor completes opening.
*/
open: function() {
let targetPromise;
open: Task.async(function*() {
if (this._opening) {
return this._opening;
}
let deferred = promise.defer();
this._opening = deferred.promise;
// Local monitoring needs to make the target remote.
if (!this.target.isRemote) {
targetPromise = this.target.makeRemote();
} else {
targetPromise = promise.resolve(this.target);
yield this.target.makeRemote();
}
return targetPromise
.then(() => this._controller.startupNetMonitor())
.then(() => this._controller.connect())
.then(() => {
this.isReady = true;
this.emit("ready");
return this;
})
.then(null, function onError(aReason) {
DevToolsUtils.reportException("NetMonitorPanel.prototype.open", aReason);
});
},
yield this._controller.startupNetMonitor();
this.isReady = true;
this.emit("ready");
deferred.resolve(this);
return this._opening;
}),
// DevToolPanel API
@ -60,14 +56,17 @@ NetMonitorPanel.prototype = {
return this._toolbox.target;
},
destroy: function() {
// Make sure this panel is not already destroyed.
if (this._destroyer) {
return this._destroyer;
destroy: Task.async(function*() {
if (this._destroying) {
return this._destroying;
}
let deferred = promise.defer();
this._destroying = deferred.promise;
return this._destroyer = this._controller.shutdownNetMonitor().then(() => {
this.emit("destroyed");
});
}
yield this._controller.shutdownNetMonitor();
this.emit("destroyed");
deferred.resolve();
return this._destroying;
})
};

Просмотреть файл

@ -91,6 +91,7 @@ skip-if = e10s # Bug 1091596
[browser_net_prefs-reload.js]
[browser_net_raw_headers.js]
[browser_net_reload-button.js]
[browser_net_reload-markers.js]
[browser_net_req-resp-bodies.js]
[browser_net_resend.js]
skip-if = e10s # Bug 1091612

Просмотреть файл

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the empty-requests reload button works.
*/
add_task(function* () {
let [tab, debuggee, monitor] = yield initNetMonitor(SINGLE_GET_URL);
info("Starting test... ");
let { document, EVENTS, NetworkEventsHandler } = monitor.panelWin;
let button = document.querySelector("#requests-menu-reload-notice-button");
button.click();
let deferred = promise.defer();
let markers = [];
monitor.panelWin.on(EVENTS.TIMELINE_EVENT, (_, marker) => {
markers.push(marker);
});
yield waitForNetworkEvents(monitor, 2);
yield waitUntil(() => markers.length == 2);
ok(true, "Reloading finished");
is(markers[0].name, "document::DOMContentLoaded",
"The first received marker is correct.");
is(markers[1].name, "document::Load",
"The second received marker is correct.");
teardown(monitor).then(finish);
});
function waitUntil(predicate, interval = 10) {
if (predicate()) {
return Promise.resolve(true);
}
return new Promise(resolve => {
setTimeout(function() {
waitUntil(predicate).then(() => resolve(true));
}, interval);
});
}

Просмотреть файл

@ -32,12 +32,12 @@ function test() {
ok(aMonitor.isReady,
"The network monitor panel appears to be ready (" + aTag + ").");
ok(aMonitor._controller.client,
"There should be a client available at this point (" + aTag + ").");
ok(aMonitor._controller.tabClient,
"There should be a tabClient available at this point (" + aTag + ").");
ok(aMonitor._controller.webConsoleClient,
"There should be a webConsoleClient available at this point (" + aTag + ").");
ok(aMonitor._controller.timelineFront,
"There should be a timelineFront available at this point (" + aTag + ").");
}
function checkIfDestroyed(aTag) {
@ -50,12 +50,12 @@ function test() {
gOk(aMonitor._controller._shutdown,
"The network monitor controller object still exists and is destroyed (" + aTag + ").");
gOk(!aMonitor._controller.client,
"There shouldn't be a client available after destruction (" + aTag + ").");
gOk(!aMonitor._controller.tabClient,
"There shouldn't be a tabClient available after destruction (" + aTag + ").");
gOk(!aMonitor._controller.webConsoleClient,
"There shouldn't be a webConsoleClient available after destruction (" + aTag + ").");
gOk(!aMonitor._controller.timelineFront,
"There shouldn't be a timelineFront available after destruction (" + aTag + ").");
}
executeSoon(() => {

Просмотреть файл

@ -46,6 +46,9 @@ const LegacyPerformanceFront = Class({
withMarkers: true,
withTicks: true,
withMemory: false,
withFrames: false,
withGCEvents: false,
withDocLoadingEvents: false,
withAllocations: false,
withJITOptimizations: false,
},

Просмотреть файл

@ -258,8 +258,10 @@ var PerformanceController = {
startRecording: Task.async(function *() {
let options = {
withMarkers: true,
withMemory: this.getOption("enable-memory"),
withTicks: this.getOption("enable-framerate"),
withMemory: this.getOption("enable-memory"),
withFrames: true,
withGCEvents: true,
withJITOptimizations: this.getOption("enable-jit-optimizations"),
withAllocations: this.getOption("enable-allocations"),
allocationsSampleProbability: this.getPref("memory-sample-probability"),

Просмотреть файл

@ -64,9 +64,10 @@ html, body, #app, #memory-tool {
/**
* We want this to be exactly at a --sidebar-width distance from the
* toolbar's start boundary. A .devtools-toolbar has a 3px start padding
* and the preceeding .take-snapshot button is exactly 32px.
* and the preceeding .take-snapshot button is exactly 32px, and the import
* button 78px.
*/
margin-inline-start: calc(var(--sidebar-width) - 3px - 32px);
margin-inline-start: calc(var(--sidebar-width) - 3px - 32px - 78px);
border-inline-start: 1px solid var(--theme-splitter-color);
padding-inline-start: 5px;
}
@ -96,6 +97,14 @@ html, body, #app, #memory-tool {
}
}
/**
* Due to toolbar styles of `.devtools-toolbarbutton:not([label])` which overrides
* .devtools-toolbarbutton's min-width of 78px, reset the min-width.
*/
#import-snapshot {
min-width: 78px;
}
.spacer {
flex: 1;
}

Просмотреть файл

@ -46,8 +46,11 @@ var PerformanceActor = exports.PerformanceActor = protocol.ActorClass({
traits: {
features: {
withMarkers: true,
withMemory: true,
withTicks: true,
withMemory: true,
withFrames: true,
withGCEvents: true,
withDocLoadingEvents: true,
withAllocations: true,
withJITOptimizations: true,
},

Просмотреть файл

@ -176,6 +176,9 @@ RootActor.prototype = {
// Whether or not the MemoryActor's heap snapshot abilities are
// fully equipped to handle heap snapshots for the memory tool. Fx44+
heapSnapshots: true,
// Whether or not the timeline actor can emit DOMContentLoaded and Load
// markers, currently in use by the network monitor. Fx45+
documentLoadingMarkers: true
},
/**

Просмотреть файл

@ -43,6 +43,15 @@ var TimelineActor = exports.TimelineActor = protocol.ActorClass({
typeName: "timeline",
events: {
/**
* Events emitted when "DOMContentLoaded" and "Load" markers are received.
*/
"doc-loading" : {
type: "doc-loading",
marker: Arg(0, "json"),
endTime: Arg(0, "number")
},
/**
* The "markers" events emitted every DEFAULT_TIMELINE_DATA_PULL_TIMEOUT ms
* at most, when profile markers are found. The timestamps on each marker
@ -139,8 +148,12 @@ var TimelineActor = exports.TimelineActor = protocol.ActorClass({
start: actorBridge("start", {
request: {
withMarkers: Option(0, "boolean"),
withTicks: Option(0, "boolean"),
withMemory: Option(0, "boolean"),
withTicks: Option(0, "boolean")
withFrames: Option(0, "boolean"),
withGCEvents: Option(0, "boolean"),
withDocLoadingEvents: Option(0, "boolean")
},
response: {
value: RetVal("number")

Просмотреть файл

@ -68,16 +68,6 @@ var Timeline = exports.Timeline = Class({
events.off(this.tabActor, "window-ready", this._onWindowReady);
this.tabActor = null;
if (this._memory) {
this._memory.destroy();
this._memory = null;
}
if (this._framerate) {
this._framerate.destroy();
this._framerate = null;
}
},
/**
@ -91,6 +81,7 @@ var Timeline = exports.Timeline = Class({
*/
get docShells() {
let originalDocShell;
let docShells = [];
if (this.tabActor.isRootActor) {
originalDocShell = this.tabActor.docShell;
@ -98,12 +89,15 @@ var Timeline = exports.Timeline = Class({
originalDocShell = this.tabActor.originalDocShell;
}
if (!originalDocShell) {
return docShells;
}
let docShellsEnum = originalDocShell.getDocShellEnumerator(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
let docShells = [];
while (docShellsEnum.hasMoreElements()) {
let docShell = docShellsEnum.getNext();
docShells.push(docShell.QueryInterface(Ci.nsIDocShell));
@ -117,44 +111,67 @@ var Timeline = exports.Timeline = Class({
* markers, memory, tick and frames events, if any.
*/
_pullTimelineData: function() {
if (!this._isRecording || !this.docShells.length) {
let docShells = this.docShells;
if (!this._isRecording || !docShells.length) {
return;
}
let endTime = this.docShells[0].now();
let endTime = docShells[0].now();
let markers = [];
for (let docShell of this.docShells) {
markers.push(...docShell.popProfileTimelineMarkers());
}
// Gather markers if requested.
if (this._withMarkers || this._withDocLoadingEvents) {
for (let docShell of docShells) {
for (let marker of docShell.popProfileTimelineMarkers()) {
markers.push(marker);
// The docshell may return markers with stack traces attached.
// Here we transform the stack traces via the stack frame cache,
// which lets us preserve tail sharing when transferring the
// frames to the client. We must waive xrays here because Firefox
// doesn't understand that the Debugger.Frame object is safe to
// use from chrome. See Tutorial-Alloc-Log-Tree.md.
for (let marker of markers) {
if (marker.stack) {
marker.stack = this._stackFrames.addFrame(Cu.waiveXrays(marker.stack));
}
if (marker.endStack) {
marker.endStack = this._stackFrames.addFrame(Cu.waiveXrays(marker.endStack));
// The docshell may return markers with stack traces attached.
// Here we transform the stack traces via the stack frame cache,
// which lets us preserve tail sharing when transferring the
// frames to the client. We must waive xrays here because Firefox
// doesn't understand that the Debugger.Frame object is safe to
// use from chrome. See Tutorial-Alloc-Log-Tree.md.
if (this._withFrames) {
if (marker.stack) {
marker.stack = this._stackFrames.addFrame(Cu.waiveXrays(marker.stack));
}
if (marker.endStack) {
marker.endStack = this._stackFrames.addFrame(Cu.waiveXrays(marker.endStack));
}
}
// Emit some helper events for "DOMContentLoaded" and "Load" markers.
if (this._withDocLoadingEvents) {
if (marker.name == "document::DOMContentLoaded" ||
marker.name == "document::Load") {
events.emit(this, "doc-loading", marker, endTime);
}
}
}
}
}
let frames = this._stackFrames.makeEvent();
if (frames) {
events.emit(this, "frames", endTime, frames);
}
if (markers.length > 0) {
// Emit markers if requested.
if (this._withMarkers && markers.length > 0) {
events.emit(this, "markers", markers, endTime);
}
// Emit framerate data if requested.
if (this._withTicks) {
events.emit(this, "ticks", endTime, this._framerate.getPendingTicks());
}
// Emit memory data if requested.
if (this._withMemory) {
events.emit(this, "memory", endTime, this._memory.measure());
}
if (this._withTicks) {
events.emit(this, "ticks", endTime, this._framerate.getPendingTicks());
// Emit stack frames data if requested.
if (this._withFrames && this._withMarkers) {
let frames = this._stackFrames.makeEvent();
if (frames) {
events.emit(this, "frames", endTime, frames);
}
}
this._dataPullTimeout = Timers.setTimeout(() => {
@ -172,40 +189,75 @@ var Timeline = exports.Timeline = Class({
/**
* Start recording profile markers.
*
* @option {boolean} withMemory
* Boolean indiciating whether we want memory measurements sampled. A memory actor
* will be created regardless (to hook into GC events), but this determines
* whether or not a `memory` event gets fired.
* @option {boolean} withMarkers
* Boolean indicating whether or not timeline markers are emitted
* once they're accumulated every `DEFAULT_TIMELINE_DATA_PULL_TIMEOUT`
* milliseconds.
* @option {boolean} withTicks
* Boolean indicating whether a `ticks` event is fired and a FramerateActor
* is created.
* Boolean indicating whether a `ticks` event is fired and a
* FramerateActor is created.
* @option {boolean} withMemory
* Boolean indiciating whether we want memory measurements sampled.
* @option {boolean} withFrames
* Boolean indicating whether or not stack frames should be handled
* from timeline markers.
* @option {boolean} withGCEvents
* Boolean indicating whether or not GC markers should be emitted.
* TODO: Remove these fake GC markers altogether in bug 1198127.
* @option {boolean} withDocLoadingEvents
* Boolean indicating whether or not DOMContentLoaded and Load
* marker events are emitted.
*/
start: Task.async(function *({ withMemory, withTicks }) {
let startTime = this._startTime = this.docShells[0].now();
start: Task.async(function *({
withMarkers,
withTicks,
withMemory,
withFrames,
withGCEvents,
withDocLoadingEvents,
}) {
let docShells = this.docShells;
if (!docShells.length) {
return -1;
}
let startTime = this._startTime = docShells[0].now();
if (this._isRecording) {
return startTime;
}
this._isRecording = true;
this._stackFrames = new StackFrameCache();
this._stackFrames.initFrames();
this._withMemory = withMemory;
this._withTicks = withTicks;
this._withMarkers = !!withMarkers;
this._withTicks = !!withTicks;
this._withMemory = !!withMemory;
this._withFrames = !!withFrames;
this._withGCEvents = !!withGCEvents;
this._withDocLoadingEvents = !!withDocLoadingEvents;
for (let docShell of this.docShells) {
docShell.recordProfileTimelineMarkers = true;
if (this._withMarkers || this._withDocLoadingEvents) {
for (let docShell of docShells) {
docShell.recordProfileTimelineMarkers = true;
}
}
this._memory = new Memory(this.tabActor, this._stackFrames);
this._memory.attach();
events.on(this._memory, "garbage-collection", this._onGarbageCollection);
if (withTicks) {
if (this._withTicks) {
this._framerate = new Framerate(this.tabActor);
this._framerate.startRecording();
}
if (this._withMemory || this._withGCEvents) {
this._memory = new Memory(this.tabActor, this._stackFrames);
this._memory.attach();
}
if (this._withGCEvents) {
events.on(this._memory, "garbage-collection", this._onGarbageCollection);
}
if (this._withFrames && this._withMarkers) {
this._stackFrames = new StackFrameCache();
this._stackFrames.initFrames();
}
this._pullTimelineData();
return startTime;
}),
@ -214,26 +266,51 @@ var Timeline = exports.Timeline = Class({
* Stop recording profile markers.
*/
stop: Task.async(function *() {
if (!this._isRecording) {
return;
let docShells = this.docShells;
if (!docShells.length) {
return -1;
}
let endTime = this._startTime = docShells[0].now();
if (!this._isRecording) {
return endTime;
}
this._isRecording = false;
this._stackFrames = null;
events.off(this._memory, "garbage-collection", this._onGarbageCollection);
this._memory.detach();
if (this._withMarkers || this._withDocLoadingEvents) {
for (let docShell of docShells) {
docShell.recordProfileTimelineMarkers = false;
}
}
if (this._framerate) {
if (this._withTicks) {
this._framerate.stopRecording();
this._framerate.destroy();
this._framerate = null;
}
for (let docShell of this.docShells) {
docShell.recordProfileTimelineMarkers = false;
if (this._withMemory || this._withGCEvents) {
this._memory.detach();
this._memory.destroy();
}
if (this._withGCEvents) {
events.off(this._memory, "garbage-collection", this._onGarbageCollection);
}
if (this._withFrames && this._withMarkers) {
this._stackFrames = null;
}
this._isRecording = false;
this._withMarkers = false;
this._withTicks = false;
this._withMemory = false;
this._withFrames = false;
this._withDocLoadingEvents = false;
this._withGCEvents = false;
Timers.clearTimeout(this._dataPullTimeout);
return this.docShells[0].now();
return endTime;
}),
/**
@ -259,11 +336,12 @@ var Timeline = exports.Timeline = Class({
* not incrementally collect garbage.
*/
_onGarbageCollection: function ({ collections, gcCycleNumber, reason, nonincrementalReason }) {
if (!this._isRecording || !this.docShells.length) {
let docShells = this.docShells;
if (!this._isRecording || !docShells.length) {
return;
}
let endTime = this.docShells[0].now();
let endTime = docShells[0].now();
events.emit(this, "markers", collections.map(({ startTimestamp: start, endTimestamp: end }) => {
return {

Просмотреть файл

@ -50,6 +50,9 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
[browser_canvasframe_helper_06.js]
skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
[browser_markers-cycle-collection.js]
[browser_markers-docloading-01.js]
[browser_markers-docloading-02.js]
[browser_markers-docloading-03.js]
[browser_markers-gc.js]
[browser_markers-parse-html.js]
[browser_markers-styles.js]

Просмотреть файл

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we get DOMContentLoaded and Load markers
*/
const { TimelineFront } = require("devtools/server/actors/timeline");
const MARKER_NAMES = ["document::DOMContentLoaded", "document::Load"];
add_task(function*() {
let doc = yield addTab(MAIN_DOMAIN + "doc_innerHTML.html");
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let front = TimelineFront(client, form);
let rec = yield front.start({ withMarkers: true });
front.once("doc-loading", e => {
ok(false, "Should not be emitting doc-loading events.");
});
executeSoon(() => doc.location.reload());
yield waitForMarkerType(front, MARKER_NAMES, () => true, e => e, "markers");
yield front.stop(rec);
ok(true, "Found the required marker names.");
// Wait some more time to make sure the 'doc-loading' events never get fired.
yield DevToolsUtils.waitForTime(1000);
yield closeDebuggerClient(client);
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -0,0 +1,34 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we get DOMContentLoaded and Load markers
*/
const { TimelineFront } = require("devtools/server/actors/timeline");
const MARKER_NAMES = ["document::DOMContentLoaded", "document::Load"];
add_task(function*() {
let doc = yield addTab(MAIN_DOMAIN + "doc_innerHTML.html");
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let front = TimelineFront(client, form);
let rec = yield front.start({ withMarkers: true, withDocLoadingEvents: true });
yield new Promise(resolve => {
front.once("doc-loading", resolve);
doc.location.reload();
});
ok(true, "At least one doc-loading event got fired.");
yield waitForMarkerType(front, MARKER_NAMES, () => true, e => e, "markers");
yield front.stop(rec);
ok(true, "Found the required marker names.");
yield closeDebuggerClient(client);
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we get DOMContentLoaded and Load markers
*/
const { TimelineFront } = require("devtools/server/actors/timeline");
const MARKER_NAMES = ["document::DOMContentLoaded", "document::Load"];
add_task(function*() {
let doc = yield addTab(MAIN_DOMAIN + "doc_innerHTML.html");
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let front = TimelineFront(client, form);
let rec = yield front.start({ withDocLoadingEvents: true });
waitForMarkerType(front, MARKER_NAMES, () => true, e => e, "markers").then(e => {
ok(false, "Should not be emitting doc-loading markers.");
});
yield new Promise(resolve => {
front.once("doc-loading", resolve);
doc.location.reload();
});
ok(true, "At least one doc-loading event got fired.");
yield front.stop(rec);
// Wait some more time to make sure the 'doc-loading' markers never get fired.
yield DevToolsUtils.waitForTime(1000);
yield closeDebuggerClient(client);
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -29,7 +29,7 @@ add_task(function*() {
let forceSyncReflow = doc.body.innerHeight;
info("Start recording");
yield front.start();
yield front.start({ withMarkers: true });
isActive = yield front.isRecording();
ok(isActive, "The TimelineFront is now recording");

Просмотреть файл

@ -18,7 +18,7 @@ add_task(function*() {
let front = TimelineFront(client, form);
info("Start timeline marker recording");
yield front.start();
yield front.start({ withMarkers: true });
// Check that we get markers for a few iterations of the timer that runs in
// the child frame.

Просмотреть файл

@ -185,7 +185,10 @@ function waitUntil(predicate, interval = 10) {
});
}
function waitForMarkerType(front, types, predicate) {
function waitForMarkerType(front, types, predicate,
unpackFun = (name, data) => data.markers,
eventName = "timeline-data")
{
types = [].concat(types);
predicate = predicate || function(){ return true; };
let filteredMarkers = [];
@ -194,21 +197,21 @@ function waitForMarkerType(front, types, predicate) {
info("Waiting for markers of type: " + types);
function handler (name, data) {
if (name !== "markers") {
if (typeof name === "string" && name !== "markers") {
return;
}
let markers = data.markers;
let markers = unpackFun(name, data);
info("Got markers: " + JSON.stringify(markers, null, 2));
filteredMarkers = filteredMarkers.concat(markers.filter(m => types.indexOf(m.name) !== -1));
if (types.every(t => filteredMarkers.some(m => m.name === t)) && predicate(filteredMarkers)) {
front.off("timeline-data", handler);
front.off(eventName, handler);
resolve(filteredMarkers);
}
}
front.on("timeline-data", handler);
front.on(eventName, handler);
return promise;
}

Просмотреть файл

@ -15,6 +15,7 @@ var events = require("sdk/event/core");
add_task(function*() {
let client = yield startTestDebuggerServer("test-promises-timetosettle");
let chromeActors = yield getChromeActors(client);
yield attachTab(client, chromeActors);
ok(Promise.toString().contains("native code"), "Expect native DOM Promise.");
@ -24,6 +25,7 @@ add_task(function*() {
let response = yield listTabs(client);
let targetTab = findTab(response.tabs, "test-promises-timetosettle");
ok(targetTab, "Found our target tab.");
yield attachTab(client, targetTab);
yield testGetTimeToSettle(client, targetTab, v => {
const debuggee =
@ -47,9 +49,10 @@ function* testGetTimeToSettle(client, form, makePromise) {
for (let p of promises) {
if (p.promiseState.state === "fulfilled" &&
p.promiseState.value === resolution) {
equal(Math.floor(p.promiseState.timeToSettle / 100) * 100, 100,
let timeToSettle = Math.floor(p.promiseState.timeToSettle / 100) * 100;
ok(timeToSettle >= 100,
"Expect time to settle for resolved promise to be " +
"approximately 100ms.");
"at least 100ms, got " + timeToSettle + "ms.");
found = true;
resolve();
} else {

Просмотреть файл

@ -29,8 +29,12 @@ function mapRecordingOptions (type, options) {
if (type === "timeline") {
return {
withMemory: options.withMemory,
withMarkers: true,
withTicks: options.withTicks,
withMemory: options.withMemory,
withFrames: true,
withGCEvents: true,
withDocLoadingEvents: false
};
}

Просмотреть файл

@ -5982,8 +5982,20 @@ nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetIsActiveAndForeground(bool aIsActive)
{
return SetIsActiveInternal(aIsActive, false);
}
NS_IMETHODIMP
nsDocShell::SetIsActive(bool aIsActive)
{
return SetIsActiveInternal(aIsActive, true);
}
nsresult
nsDocShell::SetIsActiveInternal(bool aIsActive, bool aIsHidden)
{
// We disallow setting active on chrome docshells.
if (mItemType == nsIDocShellTreeItem::typeChrome) {
@ -5996,7 +6008,7 @@ nsDocShell::SetIsActive(bool aIsActive)
// Tell the PresShell about it.
nsCOMPtr<nsIPresShell> pshell = GetPresShell();
if (pshell) {
pshell->SetIsActive(aIsActive);
pshell->SetIsActive(aIsActive, aIsHidden);
}
// Tell the window about it
@ -6030,7 +6042,11 @@ nsDocShell::SetIsActive(bool aIsActive)
}
if (!docshell->GetIsBrowserOrApp()) {
docshell->SetIsActive(aIsActive);
if (aIsHidden) {
docshell->SetIsActive(aIsActive);
} else {
docshell->SetIsActiveAndForeground(aIsActive);
}
}
}
@ -7789,7 +7805,7 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
mTiming->NotifyBeforeUnload();
bool okToUnload;
rv = mContentViewer->PermitUnload(false, &okToUnload);
rv = mContentViewer->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// The user chose not to unload the page, interrupt the load.
@ -10127,7 +10143,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
// protocol handler deals with this for javascript: URLs.
if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
bool okToUnload;
rv = mContentViewer->PermitUnload(false, &okToUnload);
rv = mContentViewer->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// The user chose not to unload the page, interrupt the

Просмотреть файл

@ -485,6 +485,8 @@ protected:
uint32_t aRedirectFlags,
uint32_t aStateFlags) override;
nsresult SetIsActiveInternal(bool aIsActive, bool aIsHidden);
/**
* Helper function that determines if channel is an HTTP POST.
*

Просмотреть файл

@ -31,7 +31,7 @@ class nsDOMNavigationTiming;
[ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming);
[ref] native nsIContentViewerTArray(nsTArray<nsCOMPtr<nsIContentViewer> >);
[scriptable, builtinclass, uuid(fbd04c99-e149-473f-8a68-44f53d82f98b)]
[scriptable, builtinclass, uuid(91b6c1f3-fc5f-43a9-88f4-9286bd19387f)]
interface nsIContentViewer : nsISupports
{
[noscript] void init(in nsIWidgetPtr aParentWidget,
@ -45,12 +45,8 @@ interface nsIContentViewer : nsISupports
/**
* Checks if the document wants to prevent unloading by firing beforeunload on
* the document, and if it does, prompts the user. The result is returned.
*
* @param aCallerClosesWindow indicates that the current caller will close the
* window. If the method returns true, all subsequent calls will be
* ignored.
*/
boolean permitUnload([optional] in boolean aCallerClosesWindow);
boolean permitUnload();
/**
* Exposes whether we're blocked in a call to permitUnload.
@ -62,8 +58,7 @@ interface nsIContentViewer : nsISupports
* track of whether the user has responded to a prompt.
* Used internally by the scriptable version to ensure we only prompt once.
*/
[noscript,nostdcall] boolean permitUnloadInternal(in boolean aCallerClosesWindow,
inout boolean aShouldPrompt);
[noscript,nostdcall] boolean permitUnloadInternal(inout boolean aShouldPrompt);
/**
* Exposes whether we're in the process of firing the beforeunload event.
@ -71,16 +66,6 @@ interface nsIContentViewer : nsISupports
*/
readonly attribute boolean beforeUnloadFiring;
/**
* Works in tandem with permitUnload, if the caller decides not to close the
* window it indicated it will, it is the caller's responsibility to reset
* that with this method.
*
* @Note this method is only meant to be called on documents for which the
* caller has indicated that it will close the window. If that is not the case
* the behavior of this method is undefined.
*/
void resetCloseWindow();
void pageHide(in boolean isUnload);
/**

Просмотреть файл

@ -43,7 +43,7 @@ interface nsITabParent;
typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(b1df6e41-c8dd-45c2-bc18-dd330d986214)]
[scriptable, builtinclass, uuid(41b1cf17-b37b-4a62-9df8-5f67cfecab3f)]
interface nsIDocShell : nsIDocShellTreeItem
{
/**
@ -628,6 +628,12 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
attribute boolean isActive;
/**
* Sets whether a docshell is active, as above, but ensuring it does
* not discard its layers
*/
void setIsActiveAndForeground(in boolean aIsActive);
/**
* Puts the docshell in prerendering mode. noscript because we want only
* native code to be able to put a docshell in prerendering.

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_DocLoadingTimelineMarker_h_
#define mozilla_DocLoadingTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class DocLoadingTimelineMarker : public TimelineMarker
{
public:
explicit DocLoadingTimelineMarker(const char* aName)
: TimelineMarker(aName, MarkerTracingType::TIMESTAMP)
, mUnixTime(PR_Now())
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
TimelineMarker::AddDetails(aCx, aMarker);
aMarker.mUnixTime.Construct(mUnixTime);
}
private:
// Certain consumers might use Date.now() or similar for tracing time.
// However, TimelineMarkers use process creation as an epoch, which provides
// more precision. To allow syncing, attach an additional unix timestamp.
// Using this instead of `AbstractTimelineMarker::GetTime()'s` timestamp
// is strongly discouraged.
PRTime mUnixTime;
};
} // namespace mozilla
#endif // mozilla_DocLoadingTimelineMarker_h_

Просмотреть файл

@ -10,6 +10,7 @@ EXPORTS.mozilla += [
'AutoTimelineMarker.h',
'CompositeTimelineMarker.h',
'ConsoleTimelineMarker.h',
'DocLoadingTimelineMarker.h',
'EventTimelineMarker.h',
'JavascriptTimelineMarker.h',
'LayerTimelineMarker.h',

Просмотреть файл

@ -83,7 +83,6 @@ skip-if = e10s # Bug 1220927 - Test tries to do addSHistoryListener on content.
[browser_loadURI.js]
[browser_multiple_pushState.js]
[browser_onbeforeunload_navigation.js]
skip-if = e10s
[browser_search_notification.js]
[browser_timelineMarkers-01.js]
[browser_timelineMarkers-02.js]

Просмотреть файл

@ -1,38 +1,41 @@
/* The test text decoded correctly as Shift_JIS */
const rightText="\u30E6\u30CB\u30B3\u30FC\u30C9\u306F\u3001\u3059\u3079\u3066\u306E\u6587\u5B57\u306B\u56FA\u6709\u306E\u756A\u53F7\u3092\u4ED8\u4E0E\u3057\u307E\u3059";
const TEXT = {
/* The test text decoded correctly as Shift_JIS */
rightText: "\u30E6\u30CB\u30B3\u30FC\u30C9\u306F\u3001\u3059\u3079\u3066\u306E\u6587\u5B57\u306B\u56FA\u6709\u306E\u756A\u53F7\u3092\u4ED8\u4E0E\u3057\u307E\u3059",
const enteredText1="The quick brown fox jumps over the lazy dog";
const enteredText2="\u03BE\u03B5\u03C3\u03BA\u03B5\u03C0\u03AC\u03B6\u03C9\u0020\u03C4\u1F74\u03BD\u0020\u03C8\u03C5\u03C7\u03BF\u03C6\u03B8\u03CC\u03C1\u03B1\u0020\u03B2\u03B4\u03B5\u03BB\u03C5\u03B3\u03BC\u03AF\u03B1";
enteredText1: "The quick brown fox jumps over the lazy dog",
enteredText2: "\u03BE\u03B5\u03C3\u03BA\u03B5\u03C0\u03AC\u03B6\u03C9\u0020\u03C4\u1F74\u03BD\u0020\u03C8\u03C5\u03C7\u03BF\u03C6\u03B8\u03CC\u03C1\u03B1\u0020\u03B2\u03B4\u03B5\u03BB\u03C5\u03B3\u03BC\u03AF\u03B1",
};
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "test-form_sjis.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(afterOpen);
}
function afterOpen() {
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(afterChangeCharset);
gBrowser.contentDocument.getElementById("testtextarea").value = enteredText1;
gBrowser.contentDocument.getElementById("testinput").value = enteredText2;
/* Force the page encoding to Shift_JIS */
BrowserSetForcedCharacterSet("Shift_JIS");
ContentTask.spawn(gBrowser.selectedBrowser, TEXT, function(TEXT) {
content.document.getElementById("testtextarea").value = TEXT.enteredText1;
content.document.getElementById("testinput").value = TEXT.enteredText2;
}).then(() => {
/* Force the page encoding to Shift_JIS */
BrowserSetForcedCharacterSet("Shift_JIS");
});
}
function afterChangeCharset() {
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.getElementById("testpar").innerHTML, rightText,
"encoding successfully changed");
is(gBrowser.contentDocument.getElementById("testtextarea").value, enteredText1,
"text preserved in <textarea>");
is(gBrowser.contentDocument.getElementById("testinput").value, enteredText2,
"text preserved in <input>");
gBrowser.removeCurrentTab();
finish();
ContentTask.spawn(gBrowser.selectedBrowser, TEXT, function(TEXT) {
is(content.document.getElementById("testpar").innerHTML, TEXT.rightText,
"encoding successfully changed");
is(content.document.getElementById("testtextarea").value, TEXT.enteredText1,
"text preserved in <textarea>");
is(content.document.getElementById("testinput").value, TEXT.enteredText2,
"text preserved in <input>");
}).then(() => {
gBrowser.removeCurrentTab();
finish();
});
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-1.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-1.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 129, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 129, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 85, "Child doc should be windows-1252 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 85, "Child doc should be windows-1252 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 129, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u0402'), 85, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 129, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u0402'), 85, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-10.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-10.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 151, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 151, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 71, "Child doc should be utf-8 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 71, "Child doc should be utf-8 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 151, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 71, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 151, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 71, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-11.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-11.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 193, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 193, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should be utf-8 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should be utf-8 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 193, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 193, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-2.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-2.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 129, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 129, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u00E2\u201A\u00AC'), 78, "Child doc should be windows-1252 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u00E2\u201A\u00AC'), 78, "Child doc should be windows-1252 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 129, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 78, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 129, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 78, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-3.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-3.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 118, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 118, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 73, "Child doc should be utf-8 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 73, "Child doc should be utf-8 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 118, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 73, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 118, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 73, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-4.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-4.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 132, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 132, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 79, "Child doc should be utf-8 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 79, "Child doc should be utf-8 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 132, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 79, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 132, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 79, "Child doc should decode as utf-8 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "UTF-8", "Child doc should report UTF-8 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-5.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-5.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 146, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 146, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 87, "Child doc should be utf-16 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 87, "Child doc should be utf-16 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 146, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 87, "Child doc should decode as utf-16 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 146, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 87, "Child doc should decode as utf-16 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "UTF-16LE", "Child doc should report UTF-16LE subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "UTF-16LE", "Child doc should report UTF-16LE subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-6.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-6.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 190, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 190, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 109, "Child doc should be utf-16 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 109, "Child doc should be utf-16 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 190, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 109, "Child doc should decode as utf-16 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 190, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 109, "Child doc should decode as utf-16 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "UTF-16BE", "Child doc should report UTF-16 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "UTF-16BE", "Child doc should report UTF-16 subsequently");
}

Просмотреть файл

@ -1,39 +1,18 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-7.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-7.html", afterOpen, "windows-1251", afterChangeCharset);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 188, "Parent doc should be windows-1252 initially");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 188, "Parent doc should be windows-1252 initially");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should be utf-8 initially");
BrowserSetForcedCharacterSet("windows-1251");
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 107, "Child doc should be utf-8 initially");
}
function afterChangeCharset(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
function afterChangeCharset() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 188, "Parent doc should decode as windows-1251 subsequently");
is(content.frames[0].document.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 107, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 188, "Parent doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u0432\u201A\u00AC'), 107, "Child doc should decode as windows-1251 subsequently");
is(gBrowser.contentDocument.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
gBrowser.removeCurrentTab();
finish();
is(content.document.characterSet, "windows-1251", "Parent doc should report windows-1251 subsequently");
is(content.frames[0].document.characterSet, "windows-1251", "Child doc should report windows-1251 subsequently");
}

Просмотреть файл

@ -1,23 +1,11 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-8.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-8.html", afterOpen);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u0402'), 156, "Parent doc should be windows-1251");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u0402'), 156, "Parent doc should be windows-1251");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u0402'), 99, "Child doc should be windows-1251");
gBrowser.removeCurrentTab();
finish();
is(content.frames[0].document.documentElement.textContent.indexOf('\u0402'), 99, "Child doc should be windows-1251");
}

Просмотреть файл

@ -1,23 +1,11 @@
function test() {
waitForExplicitFinish();
var rootDir = "http://mochi.test:8888/browser/docshell/test/browser/";
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug234628-9.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
runCharsetTest(rootDir + "file_bug234628-9.html", afterOpen);
}
function afterOpen(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
function afterOpen() {
is(content.document.documentElement.textContent.indexOf('\u20AC'), 145, "Parent doc should be UTF-16");
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
is(gBrowser.contentDocument.documentElement.textContent.indexOf('\u20AC'), 145, "Parent doc should be UTF-16");
is(gBrowser.contentDocument.getElementsByTagName("iframe")[0].contentDocument.documentElement.textContent.indexOf('\u20AC'), 96, "Child doc should be windows-1252");
gBrowser.removeCurrentTab();
finish();
is(content.frames[0].document.documentElement.textContent.indexOf('\u20AC'), 96, "Child doc should be windows-1252");
}

Просмотреть файл

@ -22,28 +22,30 @@ function test() {
let tab = gBrowser.addTab(doc);
let tabBrowser = tab.linkedBrowser;
tabBrowser.addEventListener('load', function(aEvent) {
tabBrowser.removeEventListener('load', arguments.callee, true);
BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(() => {
return ContentTask.spawn(tab.linkedBrowser, null, () => {
return new Promise(resolve => {
// The main page has loaded. Now wait for the iframe to load.
let iframe = content.document.getElementById('iframe');
iframe.addEventListener('load', function listener(aEvent) {
// The main page has loaded. Now wait for the iframe to load.
let iframe = tabBrowser.contentWindow.document.getElementById('iframe');
iframe.addEventListener('load', function(aEvent) {
// Wait for the iframe to load the new document, not about:blank.
if (!iframe.src)
return;
// Wait for the iframe to load the new document, not about:blank.
if (!iframe.src)
return;
iframe.removeEventListener('load', listener, true);
let shistory = content
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.sessionHistory;
iframe.removeEventListener('load', arguments.callee, true);
let shistory = tabBrowser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.sessionHistory;
is(shistory.count, 1, 'shistory count should be 1.');
gBrowser.removeTab(tab);
finish();
}, true);
}, true);
is(shistory.count, 1, 'shistory count should be 1.');
resolve();
}, true);
});
});
}).then(() => {
gBrowser.removeTab(tab);
finish();
});
}

Просмотреть файл

@ -4,28 +4,18 @@ function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug852909.png");
gBrowser.selectedBrowser.addEventListener("load", image, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(image);
}
function image(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", image, true);
ok(!gBrowser.selectedTab.mayEnableCharacterEncodingMenu, "Docshell should say the menu should be disabled for images.");
gBrowser.removeCurrentTab();
gBrowser.selectedTab = gBrowser.addTab(rootDir + "file_bug852909.pdf");
gBrowser.selectedBrowser.addEventListener("load", pdf, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(pdf);
}
function pdf(event) {
if (event.target != gBrowser.contentDocument) {
return;
}
gBrowser.selectedBrowser.removeEventListener("load", pdf, true);
ok(!gBrowser.selectedTab.mayEnableCharacterEncodingMenu, "Docshell should say the menu should be disabled for PDF.js.");
gBrowser.removeCurrentTab();

Просмотреть файл

@ -2,40 +2,39 @@
* %83%86%83%6a%83%52%81%5b%83%68%82%cd%81%41%82%b7%82%d7%82%c4%82%cc%95%b6%8e%9a%82%c9%8c%c5%97%4c%82%cc%94%d4%8d%86%82%f0%95%74%97%5e%82%b5%82%dc%82%b7
*/
/* The test text decoded correctly as Shift_JIS */
const rightText="\u30E6\u30CB\u30B3\u30FC\u30C9\u306F\u3001\u3059\u3079\u3066\u306E\u6587\u5B57\u306B\u56FA\u6709\u306E\u756A\u53F7\u3092\u4ED8\u4E0E\u3057\u307E\u3059";
/* The test text decoded incorrectly as Windows-1251. This is the "right" wrong
text; anything else is unexpected. */
const wrongText="\u0453\u2020\u0453\u006A\u0453\u0052\u0403\u005B\u0453\u0068\u201A\u041D\u0403\u0041\u201A\u00B7\u201A\u0427\u201A\u0414\u201A\u041C\u2022\u00B6\u040B\u0459\u201A\u0419\u040A\u0415\u2014\u004C\u201A\u041C\u201D\u0424\u040C\u2020\u201A\u0440\u2022\u0074\u2014\u005E\u201A\u00B5\u201A\u042C\u201A\u00B7";
function testContent(text) {
is(gBrowser.contentDocument.getElementById("testpar").innerHTML, text,
"<p> contains expected text");
is(gBrowser.contentDocument.getElementById("testtextarea").innerHTML, text,
"<textarea> contains expected text");
is(gBrowser.contentDocument.getElementById("testinput").value, text,
"<input> contains expected text");
return ContentTask.spawn(gBrowser.selectedBrowser, text, text => {
is(content.document.getElementById("testpar").innerHTML, text,
"<p> contains expected text");
is(content.document.getElementById("testtextarea").innerHTML, text,
"<textarea> contains expected text");
is(content.document.getElementById("testinput").value, text,
"<input> contains expected text");
});
}
function afterOpen() {
gBrowser.selectedBrowser.removeEventListener("load", afterOpen, true);
gBrowser.selectedBrowser.addEventListener("load", afterChangeCharset, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(afterChangeCharset);
/* The test text decoded incorrectly as Windows-1251. This is the "right" wrong
text; anything else is unexpected. */
const wrongText="\u0453\u2020\u0453\u006A\u0453\u0052\u0403\u005B\u0453\u0068\u201A\u041D\u0403\u0041\u201A\u00B7\u201A\u0427\u201A\u0414\u201A\u041C\u2022\u00B6\u040B\u0459\u201A\u0419\u040A\u0415\u2014\u004C\u201A\u041C\u201D\u0424\u040C\u2020\u201A\u0440\u2022\u0074\u2014\u005E\u201A\u00B5\u201A\u042C\u201A\u00B7";
/* Test that the content on load is the expected wrong decoding */
testContent(wrongText);
/* Force the page encoding to Shift_JIS */
BrowserSetForcedCharacterSet("Shift_JIS");
testContent(wrongText).then(() => {
BrowserSetForcedCharacterSet("Shift_JIS");
});
}
function afterChangeCharset() {
gBrowser.selectedBrowser.removeEventListener("load", afterChangeCharset, true);
/* The test text decoded correctly as Shift_JIS */
const rightText="\u30E6\u30CB\u30B3\u30FC\u30C9\u306F\u3001\u3059\u3079\u3066\u306E\u6587\u5B57\u306B\u56FA\u6709\u306E\u756A\u53F7\u3092\u4ED8\u4E0E\u3057\u307E\u3059";
/* test that the content is decoded correctly */
testContent(rightText);
gBrowser.removeCurrentTab();
finish();
testContent(rightText).then(() => {
gBrowser.removeCurrentTab();
finish();
});
}
function test() {
@ -51,5 +50,5 @@ function test() {
var rootDir = Services.io.newFileURI(dir).spec;
gBrowser.selectedTab = gBrowser.addTab(rootDir + "test-form_sjis.html");
gBrowser.selectedBrowser.addEventListener("load", afterOpen, true);
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(afterOpen);
}

Просмотреть файл

@ -60,3 +60,40 @@ function timelineTestOpenUrl(url) {
return Promise.all([tabSwitchPromise, loadPromise]).then(([_, tab]) => tab);
}
/**
* Helper function for charset tests. It loads |url| in a new tab,
* runs |check1| in a ContentTask when the page is ready, switches the
* charset to |charset|, and then runs |check2| in a ContentTask when
* the page has finished reloading.
*
* |charset| and |check2| can be omitted, in which case the test
* finishes when |check1| completes.
*/
function runCharsetTest(url, check1, charset, check2) {
waitForExplicitFinish();
BrowserTestUtils.openNewForegroundTab(gBrowser, url, true).then(afterOpen);
function afterOpen() {
if (charset) {
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(afterChangeCharset);
ContentTask.spawn(gBrowser.selectedBrowser, null, check1).then(() => {
BrowserSetForcedCharacterSet(charset);
});
} else {
ContentTask.spawn(gBrowser.selectedBrowser, null, check1).then(() => {
gBrowser.removeCurrentTab();
finish();
});
}
}
function afterChangeCharset() {
ContentTask.spawn(gBrowser.selectedBrowser, null, check2).then(() => {
gBrowser.removeCurrentTab();
finish();
});
}
}

Просмотреть файл

@ -89,7 +89,6 @@ function testApp(isValidWidget) {
"mozbrowsertitlechange",
"mozbrowseropenwindow",
"mozbrowserscroll",
"mozbrowserasyncscroll"
].forEach( function(topic) {
ifr.addEventListener(topic, function() {
ok(false, topic + " should be hidden");
@ -173,7 +172,7 @@ function checkIsWidgetScript(testMozbrowserEvent) {
var win = content.window.open("about:blank"); /* test mozbrowseropenwindow */
/*Close new window to avoid mochitest "unable to restore focus" failures.*/
win.close();
content.window.scrollTo(4000, 4000); /* test mozbrowser(async)scroll */
content.window.scrollTo(4000, 4000); /* test mozbrowserscroll */
}
}

Просмотреть файл

@ -3,35 +3,22 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var archiveReaderEnabled = false;
var testGenerator = testSteps();
var testGenerator;
function runTest()
{
enableArchiveReader();
SimpleTest.waitForExplicitFinish();
testGenerator.next();
SpecialPowers.pushPrefEnv({'set': [ ["dom.archivereader.enabled", true] ]}, function() {
testGenerator = testSteps();
return testGenerator.next();
});
}
function finishTest()
{
resetArchiveReader();
SimpleTest.executeSoon(function() {
SpecialPowers.popPrefEnv(function() {
testGenerator.close();
SimpleTest.finish();
});
}
function enableArchiveReader()
{
archiveReaderEnabled = SpecialPowers.getBoolPref("dom.archivereader.enabled");
SpecialPowers.setBoolPref("dom.archivereader.enabled", true);
}
function resetArchiveReader()
{
SpecialPowers.setBoolPref("dom.archivereader.enabled", archiveReaderEnabled);
}

Просмотреть файл

@ -64,8 +64,8 @@
ok(false, "Should have thrown for bogus encoding label.");
} catch (e) {
ok(e instanceof RangeError, "Expected a RangeError");
finishTest();
}
finishTest();
}
function testSteps()

Просмотреть файл

@ -2326,7 +2326,7 @@ nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool *aResult)
NS_IMETHODIMP
nsDOMWindowUtils::SetAsyncScrollOffset(nsIDOMNode* aNode,
int32_t aX, int32_t aY)
float aX, float aY)
{
nsCOMPtr<Element> element = do_QueryInterface(aNode);
if (!element) {

Просмотреть файл

@ -174,6 +174,7 @@
// FOR CSP (autogenerated by xpidl)
#include "nsIContentSecurityPolicy.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/dom/nsCSPService.h"
#include "nsHTMLStyleSheet.h"
#include "nsHTMLCSSStyleSheet.h"
@ -240,6 +241,8 @@
#include "gfxVR.h"
#include "gfxPrefs.h"
#include "mozilla/DocLoadingTimelineMarker.h"
#include "nsISpeculativeConnect.h"
#ifdef MOZ_MEDIA_NAVIGATOR
@ -2583,24 +2586,6 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
return NS_OK;
}
void
CSPErrorQueue::Add(const char* aMessageName)
{
mErrors.AppendElement(aMessageName);
}
void
CSPErrorQueue::Flush(nsIDocument* aDocument)
{
for (uint32_t i = 0; i < mErrors.Length(); i++) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("CSP"), aDocument,
nsContentUtils::eSECURITY_PROPERTIES,
mErrors[i]);
}
mErrors.Clear();
}
void
nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
{
@ -2779,7 +2764,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
aChannel->GetURI(getter_AddRefs(selfURI));
// Store the request context for violation reports
csp->SetRequestContext(nullptr, nullptr, aChannel);
csp->SetRequestContext(this, nullptr);
// ----- if the doc is an app and we want a default CSP, apply it.
if (applyAppDefaultCSP) {
@ -4598,7 +4583,12 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
// Now that we know what our window is, we can flush the CSP errors to the
// Web Console. We are flushing all messages that occured and were stored
// in the queue prior to this point.
FlushCSPWebConsoleErrorQueue();
nsCOMPtr<nsIContentSecurityPolicy> csp;
NodePrincipal()->GetCsp(getter_AddRefs(csp));
if (csp) {
static_cast<nsCSPContext*>(csp.get())->flushConsoleMessages();
}
nsCOMPtr<nsIHttpChannelInternal> internalChannel =
do_QueryInterface(GetChannel());
if (internalChannel) {
@ -4997,8 +4987,8 @@ nsDocument::DispatchContentLoadedEvents()
nsIDocShell* docShell = this->GetDocShell();
if (timelines && timelines->HasConsumer(docShell)) {
timelines->AddMarkerForDocShell(
docShell, "document::DOMContentLoaded", MarkerTracingType::TIMESTAMP);
timelines->AddMarkerForDocShell(docShell,
MakeUnique<DocLoadingTimelineMarker>("document::DOMContentLoaded"));
}
if (mTiming) {

Просмотреть файл

@ -661,29 +661,6 @@ protected:
bool mHaveShutDown;
};
class CSPErrorQueue
{
public:
/**
* Note this was designed to be passed string literals. If you give it
* a dynamically allocated string, it is your responsibility to make sure
* it never dies and is properly freed!
*/
void Add(const char* aMessageName);
void Flush(nsIDocument* aDocument);
CSPErrorQueue()
{
}
~CSPErrorQueue()
{
}
private:
nsAutoTArray<const char*,5> mErrors;
};
// Base class for our document implementations.
//
// Note that this class *implements* nsIDOMXMLDocument, but it's not
@ -1740,11 +1717,6 @@ private:
bool IsLoopDocument(nsIChannel* aChannel);
nsresult InitCSP(nsIChannel* aChannel);
void FlushCSPWebConsoleErrorQueue()
{
mCSPWebConsoleErrorQueue.Flush(this);
}
/**
* Find the (non-anonymous) content in this document for aFrame. It will
* be aFrame's content node if that content is in this document and not
@ -1868,8 +1840,6 @@ private:
nsrefcnt mStackRefCnt;
bool mNeedsReleaseAfterStackRefCntRelease;
CSPErrorQueue mCSPWebConsoleErrorQueue;
nsCOMPtr<nsIDocument> mMasterDocument;
RefPtr<mozilla::dom::ImportManager> mImportManager;
nsTArray<nsCOMPtr<nsINode> > mSubImportLinks;

Просмотреть файл

@ -7998,6 +7998,17 @@ nsGlobalWindow::CanClose()
{
MOZ_ASSERT(IsOuterWindow());
if (mIsChrome) {
nsCOMPtr<nsIBrowserDOMWindow> bwin;
nsIDOMChromeWindow* chromeWin = static_cast<nsGlobalChromeWindow*>(this);
chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));
bool canClose = true;
if (bwin && NS_SUCCEEDED(bwin->CanClose(&canClose))) {
return canClose;
}
}
if (!mDocShell) {
return true;
}
@ -8011,7 +8022,7 @@ nsGlobalWindow::CanClose()
mDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
bool canClose;
nsresult rv = cv->PermitUnload(false, &canClose);
nsresult rv = cv->PermitUnload(&canClose);
if (NS_SUCCEEDED(rv) && !canClose)
return false;

Просмотреть файл

@ -304,79 +304,4 @@ BrowserElementParent::OpenWindowInProcess(nsIDOMWindow* aOpenerWindow,
return !!*aReturnWindow ? opened : BrowserElementParent::OPEN_WINDOW_CANCELLED;
}
class DispatchAsyncScrollEventRunnable : public nsRunnable
{
public:
DispatchAsyncScrollEventRunnable(TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize)
: mTabParent(aTabParent)
, mContentRect(aContentRect)
, mContentSize(aContentSize)
{}
NS_IMETHOD Run();
private:
RefPtr<TabParent> mTabParent;
const CSSRect mContentRect;
const CSSSize mContentSize;
};
NS_IMETHODIMP DispatchAsyncScrollEventRunnable::Run()
{
nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement();
NS_ENSURE_STATE(frameElement);
nsIDocument *doc = frameElement->OwnerDoc();
nsCOMPtr<nsIGlobalObject> globalObject = doc->GetScopeObject();
NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
// Create the event's detail object.
AsyncScrollEventDetail detail;
detail.mLeft = mContentRect.x;
detail.mTop = mContentRect.y;
detail.mWidth = mContentRect.width;
detail.mHeight = mContentRect.height;
detail.mScrollWidth = mContentRect.width;
detail.mScrollHeight = mContentRect.height;
AutoSafeJSContext cx;
JS::Rooted<JSObject*> globalJSObject(cx, globalObject->GetGlobalJSObject());
NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
JSAutoCompartment ac(cx, globalJSObject);
JS::Rooted<JS::Value> val(cx);
if (!ToJSValue(cx, detail, &val)) {
MOZ_CRASH("Failed to convert dictionary to JS::Value due to OOM.");
return NS_ERROR_FAILURE;
}
nsEventStatus status = nsEventStatus_eIgnore;
DispatchCustomDOMEvent(frameElement,
NS_LITERAL_STRING("mozbrowserasyncscroll"),
cx,
val, &status);
return NS_OK;
}
bool
BrowserElementParent::DispatchAsyncScrollEvent(TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize)
{
// Do not dispatch a mozbrowserasyncscroll event of a widget to its embedder
nsCOMPtr<Element> frameElement = aTabParent->GetOwnerElement();
NS_ENSURE_TRUE(frameElement, false);
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(frameElement);
if (browserFrame && browserFrame->GetReallyIsWidget()) {
return true;
}
RefPtr<DispatchAsyncScrollEventRunnable> runnable =
new DispatchAsyncScrollEventRunnable(aTabParent, aContentRect,
aContentSize);
return NS_SUCCEEDED(NS_DispatchToMainThread(runnable));
}
} // namespace mozilla

Просмотреть файл

@ -109,26 +109,6 @@ public:
const nsACString& aFeatures,
nsIDOMWindow** aReturnWindow);
/**
* Fire a mozbrowserasyncscroll CustomEvent on the given TabParent's frame element.
* This event's detail is an AsyncScrollEventDetail dictionary.
*
* @param aContentRect: The portion of the page which is currently visible
* onscreen in CSS pixels.
*
* @param aContentSize: The content width/height in CSS pixels.
*
* aContentRect.top + aContentRect.height may be larger than aContentSize.height.
* This indicates that the content is over-scrolled, which occurs when the
* page "rubber-bands" after being scrolled all the way to the bottom.
* Similarly, aContentRect.left + aContentRect.width may be greater than
* contentSize.width, and both left and top may be negative.
*/
static bool
DispatchAsyncScrollEvent(dom::TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize);
private:
static OpenWindowResult
DispatchOpenWindowEvent(dom::Element* aOpenerFrameElement,

Просмотреть файл

@ -9,6 +9,27 @@ SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
// We'll need to get the appId from the current document,
// it's either SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID when
// we are not running inside an app (e.g. Firefox Desktop),
// or the appId of Mochitest app when we are running inside that app
// (e.g. Emulator).
var currentAppId = SpecialPowers.wrap(document).nodePrincipal.appId;
var inApp =
currentAppId !== SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID;
// We will also need the manifest URL and set it on iframes.
var currentAppManifestURL;
if (inApp) {
let appsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"]
.getService(SpecialPowers.Ci.nsIAppsService);
currentAppManifestURL = appsService.getManifestURLByLocalId(currentAppId);
};
info('appId=' + currentAppId);
info('manifestURL=' + currentAppManifestURL);
function setup() {
let appInfo = SpecialPowers.Cc['@mozilla.org/xre/app-info;1']
.getService(SpecialPowers.Ci.nsIXULAppInfo);
@ -27,110 +48,134 @@ function tearDown() {
}
function runTest() {
let path = location.pathname;
let imeUrl = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/')) +
'/file_inputmethod.html';
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: {
url: imeUrl,
originAttributes: {inBrowser: true}
}
}], SimpleTest.waitForFocus.bind(SimpleTest, createFrames));
createFrames();
}
var gFrames = [];
var gInputMethodFrames = [];
var gInputFrame;
function createFrames() {
// Create two input method iframes.
let loadendCount = 0;
let countLoadend = function() {
if (this === gInputFrame) {
// The frame script running in the frame where the input is hosted.
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
value: this.value
});
};
input.onblur = function() {
// "Expected" lost of focus since the test is finished.
if (input.value === '#0#1hello') {
return;
}
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
error: true,
value: 'Unexpected lost of focus on the input frame!'
});
};
input.focus();
}
// Inject frame script to receive input.
let mm = SpecialPowers.getBrowserFrameMessageManager(gInputFrame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", next);
} else {
ok(this.setInputMethodActive, 'Can access setInputMethodActive.');
// The frame script running in the input method frames.
let appFrameScript = function appFrameScript() {
content.addEventListener("message", function(evt) {
sendAsyncMessage('test:InputMethod:imFrameMessage', {
from: 'im',
value: evt.data
});
});
}
// Inject frame script to receive message.
let mm = SpecialPowers.getBrowserFrameMessageManager(this);
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
mm.addMessageListener("test:InputMethod:imFrameMessage", next);
}
loadendCount++;
if (loadendCount === 3) {
startTest();
setPermissions();
}
};
// Create an input field to receive string from input method iframes.
gInputFrame = document.createElement('iframe');
gInputFrame.setAttribute('mozbrowser', 'true');
gInputFrame.src =
'data:text/html,<input autofocus value="hello" />' +
'<p>This is targetted mozbrowser frame.</p>';
document.body.appendChild(gInputFrame);
gInputFrame.addEventListener('mozbrowserloadend', countLoadend);
for (let i = 0; i < 2; i++) {
let frame = gInputMethodFrames[i] = document.createElement('iframe');
frame.setAttribute('mozbrowser', 'true');
if (currentAppManifestURL) {
frame.setAttribute('mozapp', currentAppManifestURL);
}
};
frame.src = 'file_empty.html#' + i;
document.body.appendChild(frame);
frame.addEventListener('mozbrowserloadend', countLoadend);
}
}
// Create an input field to receive string from input method iframes.
gInputFrame = document.createElement('iframe');
gInputFrame.setAttribute('mozbrowser', 'true');
gInputFrame.src =
'data:text/html,<input autofocus value="hello" />' +
'<p>This is targetted mozbrowser frame.</p>';
document.body.appendChild(gInputFrame);
gInputFrame.addEventListener('mozbrowserloadend', countLoadend);
function setPermissions() {
let permissions = [{
type: 'input',
allow: true,
context: {
url: SimpleTest.getTestFileURL('/file_empty.html'),
originAttributes: {
appId: currentAppId,
inBrowser: true
}
}
}];
for (let i = 0; i < 2; i++) {
let frame = gFrames[i] = document.createElement('iframe');
gFrames[i].setAttribute('mozbrowser', 'true');
// When the input method iframe is activated, it will send the URL
// hash to current focused element. We set different hash to each
// iframe so that iframes can be differentiated by their hash.
frame.src = 'file_inputmethod.html#' + i;
document.body.appendChild(frame);
frame.addEventListener('mozbrowserloadend', countLoadend);
if (inApp) {
// The current document would also need to be given access for IPC to
// recognize our permission (why)?
permissions.push({
type: 'input', allow: true, context: document });
}
SpecialPowers.pushPermissions(permissions,
SimpleTest.waitForFocus.bind(SimpleTest, startTest));
}
function startTest() {
// Set focus to the input field and wait for input methods' inputting.
SpecialPowers.DOMWindowUtils.focus(gInputFrame);
function startTest() {
// The frame script running in the frame where the input is hosted.
let appFrameScript = function appFrameScript() {
let input = content.document.body.firstElementChild;
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
value: this.value
});
};
let req0 = gFrames[0].setInputMethodActive(true);
input.onblur = function() {
// "Expected" lost of focus since the test is finished.
if (input.value === '#0#1hello') {
return;
}
sendAsyncMessage('test:InputMethod:oninput', {
from: 'input',
error: true,
value: 'Unexpected lost of focus on the input frame!'
});
};
input.focus();
};
// Inject frame script to receive input.
let mm = SpecialPowers.getBrowserFrameMessageManager(gInputFrame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", next);
gInputMethodFrames.forEach((frame) => {
ok(frame.setInputMethodActive, 'Can access setInputMethodActive.');
// The frame script running in the input method frames.
let appFrameScript = function appFrameScript() {
let im = content.navigator.mozInputMethod;
im.oninputcontextchange = function() {
let ctx = im.inputcontext;
// Report back to parent frame on status of ctx gotten.
// (A setTimeout() here to ensure this always happens after
// DOMRequest succeed.)
content.setTimeout(() => {
sendAsyncMessage('test:InputMethod:imFrameMessage', {
from: 'im',
value: content.location.hash + !!ctx
});
});
// If there is a context, send out the hash.
if (ctx) {
ctx.replaceSurroundingText(content.location.hash);
}
};
};
// Inject frame script to receive message.
let mm = SpecialPowers.getBrowserFrameMessageManager(frame);
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
mm.addMessageListener("test:InputMethod:imFrameMessage", next);
});
// Set focus to the input field and wait for input methods' inputting.
SpecialPowers.DOMWindowUtils.focus(gInputFrame);
let req0 = gInputMethodFrames[0].setInputMethodActive(true);
req0.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (0).');
};
@ -203,14 +248,14 @@ function next(msg) {
gCount++;
let req0 = gFrames[0].setInputMethodActive(false);
let req0 = gInputMethodFrames[0].setInputMethodActive(false);
req0.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (0).');
};
req0.onerror = function() {
ok(false, 'setInputMethodActive failed (0): ' + this.error.name);
};
let req1 = gFrames[1].setInputMethodActive(true);
let req1 = gInputMethodFrames[1].setInputMethodActive(true);
req1.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded (1).');
};
@ -259,7 +304,7 @@ function next(msg) {
// Receive the second input from the second iframe.
// Deactive the second iframe.
let req3 = gFrames[1].setInputMethodActive(false);
let req3 = gInputMethodFrames[1].setInputMethodActive(false);
req3.onsuccess = function() {
ok(true, 'setInputMethodActive(false) succeeded (2).');
};

Просмотреть файл

@ -1,20 +0,0 @@
<!DOCTYPE HTML>
<html>
<body>
<script>
var im = navigator.mozInputMethod;
if (im) {
im.oninputcontextchange = function() {
var ctx = im.inputcontext;
// Report back to parent frame on status of ctx gotten.
window.postMessage(window.location.hash + !!ctx, '*');
// If there is a context, send out the hash.
if (ctx) {
ctx.replaceSurroundingText(location.hash);
}
};
}
</script>
<p>This frame represents the input method frame.</p>
</body>
</html>

Просмотреть файл

@ -76,8 +76,10 @@ skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
[test_browserElement_oop_PrivateBrowsing.html]
[test_browserElement_oop_PromptCheck.html]
[test_browserElement_oop_PromptConfirm.html]
# Disabled on B2G Emulator because permission cannot be asserted in content process,
# need to fix either bug 1094055 or bug 1020135.
[test_browserElement_oop_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (toolkit == 'gonk')
[test_browserElement_oop_PurgeHistory.html]
[test_browserElement_oop_Reload.html]
[test_browserElement_oop_ReloadPostRequest.html]
@ -89,7 +91,7 @@ skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug
skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
[test_browserElement_oop_SendEvent.html]
[test_browserElement_oop_SetInputMethodActive.html]
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (os == "android")
[test_browserElement_oop_SetVisible.html]
[test_browserElement_oop_SetVisibleFrames.html]
[test_browserElement_oop_SetVisibleFrames2.html]

Просмотреть файл

@ -129,12 +129,10 @@ support-files =
file_focus.html
file_http_401_response.sjs
file_http_407_response.sjs
file_inputmethod.html
file_microdata.html
file_microdata_bad_itemref.html
file_microdata_itemref.html
file_microformats.html
file_inputmethod.html
file_post_request.html
file_wyciwyg.html
file_audio.html
@ -213,8 +211,10 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_PrivateBrowsing.html]
[test_browserElement_inproc_PromptCheck.html]
[test_browserElement_inproc_PromptConfirm.html]
# Disabled on B2G Emulator because permission cannot be asserted in content process,
# need to fix either bug 1094055 or bug 1020135.
[test_browserElement_inproc_Proxy.html]
skip-if = (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (toolkit == 'gonk')
[test_browserElement_inproc_PurgeHistory.html]
[test_browserElement_inproc_ReloadPostRequest.html]
[test_browserElement_inproc_RemoveBrowserElement.html]
@ -226,7 +226,7 @@ skip-if = (toolkit == 'gonk') # Disabled on b2g due to bug 1097419
[test_browserElement_inproc_SendEvent.html]
# The setInputMethodActive() tests will timed out on Android
[test_browserElement_inproc_SetInputMethodActive.html]
skip-if = (os == "android") || (toolkit == 'gonk') # Disabled on B2G Emulator bug 1198163
skip-if = (os == "android")
[test_browserElement_inproc_SetVisible.html]
[test_browserElement_inproc_SetVisibleFrames.html]
[test_browserElement_inproc_SetVisibleFrames2.html]

Просмотреть файл

@ -4847,7 +4847,8 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
// Rendering directly is faster and can be done if mTarget supports Azure
// and does not need alpha blending.
if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
GlobalAlpha() == 1.0f)
GlobalAlpha() == 1.0f &&
UsedOperation() == CompositionOp::OP_OVER)
{
thebes = new gfxContext(mTarget);
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
@ -4892,7 +4893,7 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
gfx::Rect sourceRect(0, 0, sw, sh);
mTarget->DrawSurface(source, destRect, sourceRect,
DrawSurfaceOptions(gfx::Filter::POINT),
DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER,
DrawOptions(GlobalAlpha(), UsedOperation(),
AntialiasMode::NONE));
mTarget->Flush();
} else {

Просмотреть файл

@ -214,7 +214,7 @@ ContentEventHandler::QueryContentRect(nsIContent* aContent,
resultRect.UnionRect(resultRect, frameRect);
}
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
aEvent->mReply.mRect = LayoutDeviceIntRect::FromUnknownRect(
resultRect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
aEvent->mSucceeded = true;
@ -1081,7 +1081,7 @@ ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent)
} else {
rect.UnionRect(rect, frameRect);
}
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
aEvent->mReply.mRect = LayoutDeviceIntRect::FromUnknownRect(
rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
aEvent->mReply.mWritingMode = lastFrame->GetWritingMode();
aEvent->mSucceeded = true;
@ -1129,7 +1129,7 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
NS_ENSURE_SUCCESS(rv, rv);
nscoord appUnitsPerDevPixel =
caretFrame->PresContext()->AppUnitsPerDevPixel();
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
aEvent->mReply.mRect = LayoutDeviceIntRect::FromUnknownRect(
caretRect.ToOutsidePixels(appUnitsPerDevPixel));
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
@ -1189,7 +1189,7 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
rv = ConvertToRootRelativeOffset(frame, rect);
NS_ENSURE_SUCCESS(rv, rv);
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
aEvent->mReply.mRect = LayoutDeviceIntRect::FromUnknownRect(
rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
// If the caret rect is empty, let's make it non-empty rect.
if (!aEvent->mReply.mRect.width) {

Просмотреть файл

@ -807,9 +807,9 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage;
notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
notification.mMouseButtonEventData.mCursorPos.Set(
LayoutDeviceIntPoint::ToUntyped(charAtPt.refPoint));
charAtPt.refPoint.ToUnknownPoint());
notification.mMouseButtonEventData.mCharRect.Set(
LayoutDevicePixel::ToUntyped(charAtPt.mReply.mRect));
charAtPt.mReply.mRect.ToUnknownRect());
notification.mMouseButtonEventData.mButton = aMouseEvent->button;
notification.mMouseButtonEventData.mButtons = aMouseEvent->buttons;
notification.mMouseButtonEventData.mModifiers = aMouseEvent->modifiers;

Просмотреть файл

@ -338,8 +338,8 @@ WheelTransaction::GetScreenPoint(WidgetGUIEvent* aEvent)
{
NS_ASSERTION(aEvent, "aEvent is null");
NS_ASSERTION(aEvent->widget, "aEvent-widget is null");
return LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint +
aEvent->widget->WidgetToScreenOffset());
return (aEvent->refPoint + aEvent->widget->WidgetToScreenOffset())
.ToUnknownPoint();
}
/* static */ uint32_t

Просмотреть файл

@ -1522,7 +1522,7 @@ nsHTMLDocument::Open(JSContext* cx,
if (cv) {
bool okToUnload;
if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) && !okToUnload) {
if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) && !okToUnload) {
// We don't want to unload, so stop here, but don't throw an
// exception.
nsCOMPtr<nsIDocument> ret = this;

Просмотреть файл

@ -199,7 +199,7 @@ this.Keyboard = {
}
if (!Utils.checkPermissionForMM(mm, permName)) {
dump("Keyboard.jsm: Message " + msg.name +
" from a content process with no '" + permName + "' privileges.");
" from a content process with no '" + permName + "' privileges.\n");
return;
}
}

Просмотреть файл

@ -17,7 +17,7 @@ interface nsIOpenURIInFrameParams : nsISupports
attribute boolean isPrivate;
};
[scriptable, uuid(99f5a347-722c-4337-bd38-f14ec94801b3)]
[scriptable, uuid(31da1ce2-aec4-4c26-ac66-d622935c3bf4)]
/**
* The C++ source has access to the browser script source through
@ -99,6 +99,14 @@ interface nsIBrowserDOMWindow : nsISupports
* @return whether the window is the main content window for any
* currently open tab in this toplevel browser window.
*/
boolean isTabContentWindow(in nsIDOMWindow aWindow);
boolean isTabContentWindow(in nsIDOMWindow aWindow);
/**
* This function is responsible for calling
* nsIContentViewer::PermitUnload on each frame in the window. It
* returns true if closing the window is allowed. See canClose() in
* BrowserUtils.jsm for a simple implementation of this method.
*/
boolean canClose();
};

Просмотреть файл

@ -49,7 +49,7 @@ interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
interface nsIObserver;
[scriptable, uuid(a30a95ac-3b95-4251-88dc-8efa89ba9f9c)]
[scriptable, uuid(3f3f2bf4-d411-44b2-b2f7-dee5948c4763)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -1431,7 +1431,7 @@ interface nsIDOMWindowUtils : nsISupports {
* with that offset if async scrolling is enabled, and then the offset
* will be removed. Only call this while test-controlled refreshes is enabled.
*/
void setAsyncScrollOffset(in nsIDOMNode aNode, in int32_t aX, in int32_t aY);
void setAsyncScrollOffset(in nsIDOMNode aNode, in float aX, in float aY);
/**
* Set async zoom value. aRootElement should be the document element of our

Просмотреть файл

@ -5,7 +5,7 @@
#include "domstubs.idl"
[scriptable, uuid(3dd203e4-66ec-40fd-acde-43f0b35c98e9)]
[scriptable, uuid(7615408c-1fb3-4128-8dd5-a3e2f3fa8842)]
interface nsITabParent : nsISupports
{
void injectTouchEvent(in AString aType,
@ -28,6 +28,17 @@ interface nsITabParent : nsISupports
*/
attribute boolean docShellIsActive;
/**
* As an optimisation, setting the docshell's active state to
* inactive also triggers a layer invalidation to free up some
* potentially unhelpful memory usage. This attribute should be
* used where callers would like to set the docshell's state
* without losing any layer data.
*
* Otherwise, this does the same as setting the attribute above.
*/
void setDocShellIsActiveAndForeground(in boolean aIsActive);
/**
* During interactions where painting performance
* is more important than scrolling, we may temporarily

Просмотреть файл

@ -8,6 +8,7 @@
interface nsIURI;
interface nsIChannel;
interface nsIDocShell;
interface nsIDOMDocument;
interface nsIPrincipal;
interface nsIURI;
@ -20,7 +21,7 @@ interface nsIURI;
typedef unsigned short CSPDirective;
[scriptable, uuid(36c6d419-24c2-40e8-9adb-11d0b1341770)]
[scriptable, builtinclass, uuid(b9a029c3-9484-4bf7-826d-0c6b545790bc)]
interface nsIContentSecurityPolicy : nsISerializable
{
/**
@ -86,12 +87,6 @@ interface nsIContentSecurityPolicy : nsISerializable
*/
bool getReferrerPolicy(out unsigned long policy);
/**
* Remove a policy associated with this CSP context.
* @throws NS_ERROR_FAILURE if the index is out of bounds or invalid.
*/
void removePolicy(in unsigned long index);
/**
* Parse and install a CSP policy.
* @param aPolicy
@ -173,16 +168,12 @@ interface nsIContentSecurityPolicy : nsISerializable
/**
* Called after the CSP object is created to fill in appropriate request
* context and give it a reference to its owning principal for violation
* report generation.
* This will use whatever data is available, choosing earlier arguments first
* if multiple are available. Either way, it will attempt to obtain the URI,
* referrer and the principal from whatever is available. If the channel is
* available, it'll also store that for processing policy-uri directives.
* context. Either use
* * aDocument (preferred), or if no document is available, then provide
* * aPrincipal
*/
void setRequestContext(in nsIURI selfURI,
in nsIURI referrer,
in nsIChannel aChannel);
void setRequestContext(in nsIDOMDocument aDocument,
in nsIPrincipal aPrincipal);
/**
* Verifies ancestry as permitted by the policy.

Просмотреть файл

@ -2262,6 +2262,39 @@ ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
return true;
}
bool
ContentChild::RecvDataStoragePut(const nsString& aFilename,
const DataStorageItem& aItem)
{
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
if (storage) {
storage->Put(aItem.key(), aItem.value(), aItem.type());
}
return true;
}
bool
ContentChild::RecvDataStorageRemove(const nsString& aFilename,
const nsCString& aKey,
const DataStorageType& aType)
{
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
if (storage) {
storage->Remove(aKey, aType);
}
return true;
}
bool
ContentChild::RecvDataStorageClear(const nsString& aFilename)
{
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
if (storage) {
storage->Clear();
}
return true;
}
bool
ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
{

Просмотреть файл

@ -338,6 +338,13 @@ public:
virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
virtual bool RecvDataStoragePut(const nsString& aFilename,
const DataStorageItem& aItem) override;
virtual bool RecvDataStorageRemove(const nsString& aFilename,
const nsCString& aKey,
const DataStorageType& aType) override;
virtual bool RecvDataStorageClear(const nsString& aFilename) override;
virtual bool RecvNotifyAlertsObserver(const nsCString& aType,
const nsString& aData) override;

Просмотреть файл

@ -35,6 +35,7 @@
#include "imgIContainer.h"
#include "mozIApplication.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/DataStorage.h"
#include "mozilla/devtools/HeapSnapshotTempFileHelperParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/DataStoreService.h"
@ -1222,10 +1223,12 @@ ContentParent::RecvGetBlocklistState(const uint32_t& aPluginId,
bool
ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
nsresult* aRv,
nsTArray<PluginTag>* aPlugins,
uint32_t* aNewPluginEpoch)
{
return mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aNewPluginEpoch);
*aRv = mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aNewPluginEpoch);
return true;
}
/*static*/ TabParent*
@ -2670,6 +2673,15 @@ ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
return true;
}
bool
ContentParent::RecvReadDataStorageArray(const nsString& aFilename,
InfallibleTArray<DataStorageItem>* aValues)
{
RefPtr<DataStorage> storage = DataStorage::Get(aFilename);
storage->GetAll(aValues);
return true;
}
bool
ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
{

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше