зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inboind
This commit is contained in:
Коммит
d577fff5aa
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче