зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
61d400da1c
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "InterfaceInitFuncs.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "AccessibleWrap.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
|
|
|
@ -104,6 +104,15 @@ Accessible::HasNumericValue() const
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Accessible::IsDefunct() const
|
||||
{
|
||||
MOZ_ASSERT(mStateFlags & eIsDefunct || IsApplication() || IsDoc() ||
|
||||
mStateFlags & eSharedNode || mContent,
|
||||
"No content");
|
||||
return mStateFlags & eIsDefunct;
|
||||
}
|
||||
|
||||
inline void
|
||||
Accessible::ScrollTo(uint32_t aHow) const
|
||||
{
|
||||
|
|
|
@ -861,7 +861,7 @@ public:
|
|||
/**
|
||||
* Return true if the accessible is defunct.
|
||||
*/
|
||||
bool IsDefunct() const { return mStateFlags & eIsDefunct; }
|
||||
bool IsDefunct() const;
|
||||
|
||||
/**
|
||||
* Return false if the accessible is no longer in the document.
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "XULListboxAccessibleWrap.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "sdnDocAccessible.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "ISimpleDOM.h"
|
||||
|
||||
#include "nsNameSpaceManager.h"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "uiaRawElmProvider.h"
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "AccessibleWrap.h"
|
||||
#include "ARIAMap.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
|
|
|
@ -1659,17 +1659,9 @@ pref("extensions.pocket.enabled", true);
|
|||
|
||||
pref("signon.schemeUpgrades", true);
|
||||
|
||||
// "Simplify Page" feature in Print Preview. This feature is disabled by default
|
||||
// in toolkit.
|
||||
//
|
||||
// This feature is only enabled on Nightly for Linux until bug 1306295 is fixed.
|
||||
#ifdef UNIX_BUT_NOT_MAC
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
// Enable the "Simplify Page" feature in Print Preview. This feature
|
||||
// is disabled by default in toolkit.
|
||||
pref("print.use_simplify_page", true);
|
||||
#endif
|
||||
#else
|
||||
pref("print.use_simplify_page", true);
|
||||
#endif
|
||||
|
||||
// Space separated list of URLS that are allowed to send objects (instead of
|
||||
// only strings) through webchannels. This list is duplicated in mobile/android/app/mobile.js
|
||||
|
|
|
@ -360,6 +360,15 @@ var SidebarUI = {
|
|||
return this.show(commandID, triggerNode);
|
||||
},
|
||||
|
||||
_loadSidebarExtension(sidebarBroadcaster) {
|
||||
let extensionId = sidebarBroadcaster.getAttribute("extensionId");
|
||||
if (extensionId) {
|
||||
let extensionUrl = sidebarBroadcaster.getAttribute("panel");
|
||||
let browserStyle = sidebarBroadcaster.getAttribute("browserStyle");
|
||||
SidebarUI.browser.contentWindow.loadPanel(extensionId, extensionUrl, browserStyle);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the sidebar, using the parameters from the specified broadcaster.
|
||||
* @see SidebarUI note.
|
||||
|
@ -371,7 +380,9 @@ var SidebarUI = {
|
|||
* showing of the sidebar.
|
||||
*/
|
||||
show(commandID, triggerNode) {
|
||||
return this._show(commandID).then(() => {
|
||||
return this._show(commandID).then((sidebarBroadcaster) => {
|
||||
this._loadSidebarExtension(sidebarBroadcaster);
|
||||
|
||||
if (triggerNode) {
|
||||
updateToggleControlLabel(triggerNode);
|
||||
}
|
||||
|
@ -388,9 +399,11 @@ var SidebarUI = {
|
|||
*
|
||||
* @param {string} commandID ID of the xul:broadcaster element to use.
|
||||
*/
|
||||
showInitially(commandID) {
|
||||
return this._show(commandID);
|
||||
},
|
||||
showInitially(commandID) {
|
||||
return this._show(commandID).then((sidebarBroadcaster) => {
|
||||
this._loadSidebarExtension(sidebarBroadcaster);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Implementation for show. Also used internally for sidebars that are shown
|
||||
|
@ -446,14 +459,14 @@ var SidebarUI = {
|
|||
// We're handling the 'load' event before it bubbles up to the usual
|
||||
// (non-capturing) event handlers. Let it bubble up before resolving.
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
resolve(sidebarBroadcaster);
|
||||
|
||||
// Now that the currentId is updated, fire a show event.
|
||||
this._fireShowEvent();
|
||||
}, 0);
|
||||
}, {capture: true, once: true});
|
||||
} else {
|
||||
resolve();
|
||||
resolve(sidebarBroadcaster);
|
||||
|
||||
// Now that the currentId is updated, fire a show event.
|
||||
this._fireShowEvent();
|
||||
|
|
|
@ -44,31 +44,6 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
|
|||
},
|
||||
];
|
||||
|
||||
const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
|
||||
/**
|
||||
* The synced tabs view has labels that are multiline. Because of bugs in
|
||||
* XUL layout relating to multiline text in scrollable containers, we need
|
||||
* to manually read their height in order to ensure container heights are
|
||||
* correct. Unfortunately this requires 2 sync reflows.
|
||||
*
|
||||
* If we add more views where this is necessary, we may need to duplicate
|
||||
* these expected reflows further. Bug 1392340 is on file to remove the
|
||||
* reflows completely when opening subviews.
|
||||
*/
|
||||
{
|
||||
stack: [
|
||||
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
|
||||
"_transitionViews@resource:///modules/PanelMultiView.jsm",
|
||||
],
|
||||
|
||||
maxCount: 4, // This number should only ever go down - never up.
|
||||
},
|
||||
|
||||
/**
|
||||
* Please don't add anything new!
|
||||
*/
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
await ensureNoPreloadedBrowser();
|
||||
|
||||
|
@ -96,8 +71,10 @@ add_task(async function() {
|
|||
|
||||
for (let button of navButtons) {
|
||||
info("Click " + button.id);
|
||||
let promiseViewShown = BrowserTestUtils.waitForEvent(PanelUI.panel,
|
||||
"ViewShown");
|
||||
button.click();
|
||||
await BrowserTestUtils.waitForEvent(PanelUI.panel, "ViewShown");
|
||||
let viewShownEvent = await promiseViewShown;
|
||||
|
||||
// Workaround until bug 1363756 is fixed, then this can be removed.
|
||||
let container = PanelUI.multiView.querySelector(".panel-viewcontainer");
|
||||
|
@ -105,10 +82,12 @@ add_task(async function() {
|
|||
return !container.hasAttribute("width");
|
||||
});
|
||||
|
||||
info("Shown " + PanelUI.multiView.current.id);
|
||||
await openSubViewsRecursively(PanelUI.multiView.current);
|
||||
info("Shown " + viewShownEvent.originalTarget.id);
|
||||
await openSubViewsRecursively(viewShownEvent.originalTarget);
|
||||
promiseViewShown = BrowserTestUtils.waitForEvent(currentView,
|
||||
"ViewShown");
|
||||
PanelUI.multiView.goBack();
|
||||
await BrowserTestUtils.waitForEvent(PanelUI.panel, "ViewShown");
|
||||
await promiseViewShown;
|
||||
|
||||
// Workaround until bug 1363756 is fixed, then this can be removed.
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
|
@ -122,5 +101,5 @@ add_task(async function() {
|
|||
let hidden = BrowserTestUtils.waitForEvent(PanelUI.panel, "popuphidden");
|
||||
PanelUI.hide();
|
||||
await hidden;
|
||||
}, EXPECTED_APPMENU_SUBVIEW_REFLOWS);
|
||||
}, []);
|
||||
});
|
||||
|
|
|
@ -97,4 +97,8 @@ tags = mcb
|
|||
support-files =
|
||||
../general/moz.png
|
||||
test_no_mcb_for_loopback.html
|
||||
[browser_no_mcb_for_onions.js]
|
||||
tags = mcb
|
||||
support-files =
|
||||
test_no_mcb_for_onions.html
|
||||
[browser_check_identity_state.js]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// The test loads a HTTPS web page with active content from HTTP .onion URLs
|
||||
// and makes sure that the mixed content flags on the docshell are not set.
|
||||
//
|
||||
// Note that the URLs referenced within the test page intentionally use the
|
||||
// unassigned port 8 because we don't want to actually load anything, we just
|
||||
// want to check that the URLs are not blocked.
|
||||
|
||||
const TEST_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "test_no_mcb_for_onions.html";
|
||||
|
||||
const PREF_BLOCK_DISPLAY = "security.mixed_content.block_display_content";
|
||||
const PREF_BLOCK_ACTIVE = "security.mixed_content.block_active_content";
|
||||
const PREF_ONION_WHITELIST = "dom.securecontext.whitelist_onions";
|
||||
|
||||
add_task(async function allowOnionMixedContent() {
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
await SpecialPowers.pushPrefEnv({set: [[PREF_BLOCK_DISPLAY, true]]});
|
||||
await SpecialPowers.pushPrefEnv({set: [[PREF_BLOCK_ACTIVE, true]]});
|
||||
await SpecialPowers.pushPrefEnv({set: [[PREF_ONION_WHITELIST, true]]});
|
||||
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
const browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
await ContentTask.spawn(browser, null, function() {
|
||||
is(docShell.hasMixedDisplayContentBlocked, false, "hasMixedDisplayContentBlocked not set");
|
||||
is(docShell.hasMixedActiveContentBlocked, false, "hasMixedActiveContentBlocked not set");
|
||||
});
|
||||
|
||||
await assertMixedContentBlockingState(browser, {
|
||||
activeBlocked: false,
|
||||
activeLoaded: false,
|
||||
passiveLoaded: false,
|
||||
});
|
||||
});
|
|
@ -0,0 +1,28 @@
|
|||
<!-- See browser_no_mcb_for_onions.js -->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Bug 1382359</title>
|
||||
</head>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
src: url("http://123456789abcdef.onion:8/test.ttf");
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<img src="http://123456789abcdef.onion:8/test.png">
|
||||
|
||||
<iframe src="http://123456789abcdef.onion:8/test.html"></iframe>
|
||||
</body>
|
||||
|
||||
<script src="http://123456789abcdef.onion:8/test.js"></script>
|
||||
|
||||
<link href="http://123456789abcdef.onion:8/test.css" rel="stylesheet"></link>
|
||||
|
||||
<script>
|
||||
fetch("http://123456789abcdef.onion:8");
|
||||
</script>
|
||||
</html>
|
|
@ -90,10 +90,6 @@ var whitelist = [
|
|||
// browser/extensions/pdfjs/content/web/viewer.js
|
||||
{file: "resource://pdf.js/build/pdf.worker.js"},
|
||||
|
||||
// browser/components/newtab bug 1355166
|
||||
{file: "resource://app/modules/NewTabSearchProvider.jsm"},
|
||||
{file: "resource://app/modules/NewTabWebChannel.jsm"},
|
||||
|
||||
// layout/mathml/nsMathMLChar.cpp
|
||||
{file: "resource://gre/res/fonts/mathfontSTIXGeneral.properties"},
|
||||
{file: "resource://gre/res/fonts/mathfontUnicode.properties"},
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
ChromeUtils.defineModuleGetter(this, "ExtensionParent",
|
||||
"resource://gre/modules/ExtensionParent.jsm");
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
var {
|
||||
|
@ -88,18 +89,16 @@ var gBrowser = {
|
|||
},
|
||||
};
|
||||
|
||||
function loadWebPanel() {
|
||||
let sidebarURI = new URL(location);
|
||||
async function loadPanel(extensionId, extensionUrl, browserStyle) {
|
||||
let policy = WebExtensionPolicy.getByID(extensionId);
|
||||
let sidebar = {
|
||||
uri: sidebarURI.searchParams.get("panel"),
|
||||
remote: sidebarURI.searchParams.get("remote"),
|
||||
browserStyle: sidebarURI.searchParams.get("browser-style"),
|
||||
uri: extensionUrl,
|
||||
remote: policy.extension.remote,
|
||||
browserStyle,
|
||||
};
|
||||
getBrowser(sidebar).then(browser => {
|
||||
browser.loadURI(sidebar.uri);
|
||||
let uri = Services.io.newURI(policy.getURL());
|
||||
let triggeringPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
browser.loadURIWithFlags(extensionUrl, {triggeringPrincipal});
|
||||
});
|
||||
}
|
||||
|
||||
function load() {
|
||||
this.loadWebPanel();
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
<page id="webextpanels-window"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="load()">
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser-places.js"/>
|
||||
|
|
Двоичные данные
browser/branding/nightly/dsstore
Двоичные данные
browser/branding/nightly/dsstore
Двоичный файл не отображается.
|
@ -1802,34 +1802,18 @@ var CustomizableUIInternal = {
|
|||
}
|
||||
}
|
||||
|
||||
// We can't use event.target because we might have passed a panelview
|
||||
// anonymous content boundary as well, and so target points to the
|
||||
// panelmultiview in that case. Unfortunately, this means we get
|
||||
// anonymous child nodes instead of the real ones, so looking for the
|
||||
// 'stoooop, don't close me' attributes is more involved.
|
||||
// We can't use event.target because we might have passed an anonymous
|
||||
// content boundary as well, and so target points to the outer element in
|
||||
// that case. Unfortunately, this means we get anonymous child nodes instead
|
||||
// of the real ones, so looking for the 'stoooop, don't close me' attributes
|
||||
// is more involved.
|
||||
let target = aEvent.originalTarget;
|
||||
let closemenu = "auto";
|
||||
let widgetType = "button";
|
||||
while (target.parentNode && target.localName != "panel") {
|
||||
closemenu = target.getAttribute("closemenu");
|
||||
widgetType = target.getAttribute("widget-type");
|
||||
if (closemenu == "none" || closemenu == "single" ||
|
||||
widgetType == "view") {
|
||||
break;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
if (closemenu == "none" || widgetType == "view") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (closemenu == "single") {
|
||||
let panel = this._getPanelForNode(target);
|
||||
let multiview = panel.querySelector("panelmultiview");
|
||||
if (multiview.showingSubView) {
|
||||
multiview.goBack();
|
||||
if (target.getAttribute("closemenu") == "none" ||
|
||||
target.getAttribute("widget-type") == "view") {
|
||||
return;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
// If we get here, we can actually hide the popup:
|
||||
|
|
|
@ -62,12 +62,14 @@
|
|||
* visible, but a visible view may be inactive. For example, during a scroll
|
||||
* transition, both views will be inactive.
|
||||
*
|
||||
* When a view becomes active, the ViewShown event is fired synchronously.
|
||||
* For the main view of the panel, this happens during the "popupshown"
|
||||
* event, which means that other "popupshown" handlers may be called before
|
||||
* the view is active. However, the main view can already receive mouse and
|
||||
* keyboard events at this point, only because this allows regression tests
|
||||
* to use the "popupshown" event to simulate interaction.
|
||||
* When a view becomes active, the ViewShown event is fired synchronously,
|
||||
* and the showSubView and goBack methods can be called for navigation.
|
||||
*
|
||||
* For the main view of the panel, the ViewShown event is dispatched during
|
||||
* the "popupshown" event, which means that other "popupshown" handlers may
|
||||
* be called before the view is active. Thus, code that needs to perform
|
||||
* further navigation automatically should either use the ViewShown event or
|
||||
* wait for an event loop tick, like BrowserTestUtils.waitForEvent does.
|
||||
*
|
||||
* -- Navigating with the keyboard
|
||||
*
|
||||
|
@ -93,10 +95,6 @@
|
|||
* │ │ └── Currently visible view
|
||||
* │ │ │
|
||||
* └───┴───┴── Open views
|
||||
*
|
||||
* If the <panelmultiview> element is "ephemeral", imported subviews will be
|
||||
* moved out again to the element specified by the viewCacheId attribute, so
|
||||
* that the panel element can be removed safely.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
@ -128,7 +126,6 @@ const TRANSITION_PHASES = Object.freeze({
|
|||
START: 1,
|
||||
PREPARE: 2,
|
||||
TRANSITION: 3,
|
||||
END: 4
|
||||
});
|
||||
|
||||
let gNodeToObjectMap = new WeakMap();
|
||||
|
@ -307,6 +304,10 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
* Removes the specified <panel> from the document, ensuring that any
|
||||
* <panelmultiview> node it contains is destroyed properly.
|
||||
*
|
||||
* If the viewCacheId attribute is present on the <panelmultiview> element,
|
||||
* imported subviews will be moved out again to the element it specifies, so
|
||||
* that the panel element can be removed safely.
|
||||
*
|
||||
* If the panel does not contain a <panelmultiview>, it is removed directly.
|
||||
* This allows consumers like page actions to accept different panel types.
|
||||
*/
|
||||
|
@ -314,7 +315,9 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
try {
|
||||
let panelMultiViewNode = panelNode.querySelector("panelmultiview");
|
||||
if (panelMultiViewNode) {
|
||||
this.forNode(panelMultiViewNode).disconnect();
|
||||
let panelMultiView = this.forNode(panelMultiViewNode);
|
||||
panelMultiView._moveOutKids();
|
||||
panelMultiView.disconnect();
|
||||
}
|
||||
} finally {
|
||||
// Make sure to remove the panel element even if disconnecting fails.
|
||||
|
@ -345,18 +348,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
return this.node.parentNode;
|
||||
}
|
||||
|
||||
get _mainViewId() {
|
||||
return this.node.getAttribute("mainViewId");
|
||||
}
|
||||
get _mainView() {
|
||||
return this.document.getElementById(this._mainViewId);
|
||||
}
|
||||
|
||||
get _transitioning() {
|
||||
return this.__transitioning;
|
||||
}
|
||||
set _transitioning(val) {
|
||||
this.__transitioning = val;
|
||||
if (val) {
|
||||
this.node.setAttribute("transitioning", "true");
|
||||
} else {
|
||||
|
@ -364,38 +356,12 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Boolean} |true| when the 'ephemeral' attribute is set, which means
|
||||
* that this instance should be ready to be thrown away at
|
||||
* any time.
|
||||
*/
|
||||
get _ephemeral() {
|
||||
return this.node.hasAttribute("ephemeral");
|
||||
}
|
||||
|
||||
get _screenManager() {
|
||||
if (this.__screenManager)
|
||||
return this.__screenManager;
|
||||
return this.__screenManager = Cc["@mozilla.org/gfx/screenmanager;1"]
|
||||
.getService(Ci.nsIScreenManager);
|
||||
}
|
||||
/**
|
||||
* @return {panelview} the currently visible subview OR the subview that is
|
||||
* about to be shown whilst a 'ViewShowing' event is being
|
||||
* dispatched.
|
||||
*/
|
||||
get current() {
|
||||
return this.node && this._currentSubView;
|
||||
}
|
||||
get _currentSubView() {
|
||||
// Peek the top of the stack, but fall back to the main view if the list of
|
||||
// opened views is currently empty.
|
||||
let panelView = this.openViews[this.openViews.length - 1];
|
||||
return (panelView && panelView.node) || this._mainView;
|
||||
}
|
||||
get showingSubView() {
|
||||
return this.openViews.length > 1;
|
||||
}
|
||||
|
||||
constructor(node) {
|
||||
super(node);
|
||||
|
@ -428,12 +394,6 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
this.node.prepend(viewContainer);
|
||||
|
||||
this.openViews = [];
|
||||
this.__transitioning = false;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "_panelViewCache", () => {
|
||||
let viewCacheId = this.node.getAttribute("viewCacheId");
|
||||
return viewCacheId ? this.document.getElementById(viewCacheId) : null;
|
||||
});
|
||||
|
||||
this._panel.addEventListener("popupshowing", this);
|
||||
this._panel.addEventListener("popuppositioned", this);
|
||||
|
@ -452,12 +412,6 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
value: (...args) => this[method](...args)
|
||||
});
|
||||
});
|
||||
["current", "showingSubView"].forEach(property => {
|
||||
Object.defineProperty(this.node, property, {
|
||||
enumerable: true,
|
||||
get: () => this[property]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
|
@ -465,15 +419,6 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
if (!this.node || !this.connected)
|
||||
return;
|
||||
|
||||
this._cleanupTransitionPhase();
|
||||
let mainView = this._mainView;
|
||||
if (mainView) {
|
||||
if (this._panelViewCache)
|
||||
this._panelViewCache.appendChild(mainView);
|
||||
mainView.removeAttribute("mainview");
|
||||
}
|
||||
|
||||
this._moveOutKids(this._viewStack);
|
||||
this._panel.removeEventListener("mousemove", this);
|
||||
this._panel.removeEventListener("popupshowing", this);
|
||||
this._panel.removeEventListener("popuppositioned", this);
|
||||
|
@ -482,7 +427,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
this.window.removeEventListener("keydown", this);
|
||||
this.node = this._openPopupPromise = this._openPopupCancelCallback =
|
||||
this._viewContainer = this._viewStack = this.__dwu =
|
||||
this._panelViewCache = this._transitionDetails = null;
|
||||
this._transitionDetails = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -621,22 +566,21 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove any child subviews into the panelViewCache, to ensure
|
||||
* they remain usable even if this panelmultiview instance is removed
|
||||
* from the DOM.
|
||||
* @param viewNodeContainer the container from which to remove subviews
|
||||
* Move any child subviews into the element defined by "viewCacheId" to make
|
||||
* sure they will not be removed together with the <panelmultiview> element.
|
||||
*/
|
||||
_moveOutKids(viewNodeContainer) {
|
||||
if (!this._panelViewCache)
|
||||
_moveOutKids() {
|
||||
let viewCacheId = this.node.getAttribute("viewCacheId");
|
||||
if (!viewCacheId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Node.children and Node.childNodes is live to DOM changes like the
|
||||
// ones we're about to do, so iterate over a static copy:
|
||||
let subviews = Array.from(viewNodeContainer.childNodes);
|
||||
let subviews = Array.from(this._viewStack.childNodes);
|
||||
let viewCache = this.document.getElementById(viewCacheId);
|
||||
for (let subview of subviews) {
|
||||
// XBL lists the 'children' XBL element explicitly. :-(
|
||||
if (subview.nodeName != "children")
|
||||
this._panelViewCache.appendChild(subview);
|
||||
viewCache.appendChild(subview);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,32 +605,73 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.openViews.length) {
|
||||
Cu.reportError(new Error(`Cannot show a subview in a closed panel.`));
|
||||
return;
|
||||
}
|
||||
|
||||
let prevPanelView = this.openViews[this.openViews.length - 1];
|
||||
let nextPanelView = PanelView.forNode(viewNode);
|
||||
if (this.openViews.includes(nextPanelView)) {
|
||||
Cu.reportError(new Error(`Subview ${viewNode.id} is already open.`));
|
||||
return;
|
||||
}
|
||||
if (!(await this._openView(nextPanelView))) {
|
||||
|
||||
// Do not re-enter the process if navigation is already in progress. Since
|
||||
// there is only one active view at any given time, we can do this check
|
||||
// safely, even considering that during the navigation process the actual
|
||||
// view to which prevPanelView refers will change.
|
||||
if (!prevPanelView.active) {
|
||||
return;
|
||||
}
|
||||
// Marking the view that is about to scrolled out of the visible area as
|
||||
// inactive will prevent re-entrancy and also disable keyboard navigation.
|
||||
// From this point onwards, "await" statements can be used safely.
|
||||
prevPanelView.active = false;
|
||||
|
||||
prevPanelView.captureKnownSize();
|
||||
|
||||
// The main view of a panel can be a subview in another one. Make sure to
|
||||
// reset all the properties that may be set on a subview.
|
||||
nextPanelView.mainview = false;
|
||||
// The header may change based on how the subview was opened.
|
||||
nextPanelView.headerText = viewNode.getAttribute("title") ||
|
||||
(anchor && anchor.getAttribute("label"));
|
||||
// The constrained width of subviews may also vary between panels.
|
||||
nextPanelView.minMaxWidth = prevPanelView.knownWidth;
|
||||
|
||||
// Provide visual feedback while navigation is in progress, starting before
|
||||
// the transition starts and ending when the previous view is invisible.
|
||||
if (anchor) {
|
||||
viewNode.classList.add("PanelUI-subView");
|
||||
anchor.setAttribute("open", "true");
|
||||
}
|
||||
try {
|
||||
// If the ViewShowing event cancels the operation we have to re-enable
|
||||
// keyboard navigation, but this must be avoided if the panel was closed.
|
||||
if (!(await this._openView(nextPanelView))) {
|
||||
if (prevPanelView.isOpenIn(this)) {
|
||||
// We don't raise a ViewShown event because nothing actually changed.
|
||||
// Technically we should use a different state flag just because there
|
||||
// is code that could check the "active" property to determine whether
|
||||
// to wait for a ViewShown event later, but this only happens in
|
||||
// regression tests and is less likely to be a technique used in
|
||||
// production code, where use of ViewShown is less common.
|
||||
prevPanelView.active = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
prevPanelView.captureKnownSize();
|
||||
|
||||
// The main view of a panel can be a subview in another one. Make sure to
|
||||
// reset all the properties that may be set on a subview.
|
||||
nextPanelView.mainview = false;
|
||||
// The header may change based on how the subview was opened.
|
||||
nextPanelView.headerText = viewNode.getAttribute("title") ||
|
||||
(anchor && anchor.getAttribute("label"));
|
||||
// The constrained width of subviews may also vary between panels.
|
||||
nextPanelView.minMaxWidth = prevPanelView.knownWidth;
|
||||
|
||||
if (anchor) {
|
||||
viewNode.classList.add("PanelUI-subView");
|
||||
}
|
||||
|
||||
await this._transitionViews(prevPanelView.node, viewNode, false, anchor);
|
||||
} finally {
|
||||
if (anchor) {
|
||||
anchor.removeAttribute("open");
|
||||
}
|
||||
}
|
||||
|
||||
await this._transitionViews(prevPanelView.node, viewNode, false, anchor);
|
||||
this._activateView(nextPanelView);
|
||||
}
|
||||
|
||||
|
@ -706,6 +691,14 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
let prevPanelView = this.openViews[this.openViews.length - 1];
|
||||
let nextPanelView = this.openViews[this.openViews.length - 2];
|
||||
|
||||
// Like in the showSubView method, do not re-enter navigation while it is
|
||||
// in progress, and make the view inactive immediately. From this point
|
||||
// onwards, "await" statements can be used safely.
|
||||
if (!prevPanelView.active) {
|
||||
return;
|
||||
}
|
||||
prevPanelView.active = false;
|
||||
|
||||
prevPanelView.captureKnownSize();
|
||||
await this._transitionViews(prevPanelView.node, nextPanelView.node, true);
|
||||
|
||||
|
@ -718,11 +711,8 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
* Prepares the main view before showing the panel.
|
||||
*/
|
||||
async _showMainView() {
|
||||
if (!this.node || !this._mainViewId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let nextPanelView = PanelView.forNode(this._mainView);
|
||||
let nextPanelView = PanelView.forNode(this.document.getElementById(
|
||||
this.node.getAttribute("mainViewId")));
|
||||
|
||||
// If the view is already open in another panel, close the panel first.
|
||||
let oldPanelMultiViewNode = nextPanelView.node.panelMultiView;
|
||||
|
@ -744,7 +734,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
nextPanelView.headerText = "";
|
||||
nextPanelView.minMaxWidth = 0;
|
||||
|
||||
await this._cleanupTransitionPhase();
|
||||
// Ensure the view will be visible once the panel is opened.
|
||||
nextPanelView.visible = true;
|
||||
nextPanelView.descriptionHeightWorkaround();
|
||||
|
||||
|
@ -755,6 +745,9 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
* Opens the specified PanelView and dispatches the ViewShowing event, which
|
||||
* can be used to populate the subview or cancel the operation.
|
||||
*
|
||||
* This also clears all the attributes and styles that may be left by a
|
||||
* transition that was interrupted.
|
||||
*
|
||||
* @resolves With true if the view was opened, false otherwise.
|
||||
*/
|
||||
async _openView(panelView) {
|
||||
|
@ -783,6 +776,13 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Clean up all the attributes and styles related to transitions. We do this
|
||||
// here rather than when the view is closed because we are likely to make
|
||||
// other DOM modifications soon, which isn't the case when closing.
|
||||
let { style } = panelView.node;
|
||||
style.removeProperty("outline");
|
||||
style.removeProperty("width");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -791,7 +791,7 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
* view was closed in the meantime.
|
||||
*/
|
||||
_activateView(panelView) {
|
||||
if (panelView.node.panelMultiView == this.node) {
|
||||
if (panelView.isOpenIn(this)) {
|
||||
panelView.active = true;
|
||||
panelView.dispatchCustomEvent("ViewShown");
|
||||
}
|
||||
|
@ -809,7 +809,8 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
panelView.dispatchCustomEvent("ViewHiding");
|
||||
panelView.node.panelMultiView = null;
|
||||
// Views become invisible synchronously when they are closed, and they won't
|
||||
// become visible again until they are opened.
|
||||
// become visible again until they are opened. When this is called at the
|
||||
// end of backwards navigation, the view is already invisible.
|
||||
panelView.visible = false;
|
||||
}
|
||||
|
||||
|
@ -830,41 +831,24 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
* is and the active panelview slides in from the left in LTR mode, right in
|
||||
* RTL mode.
|
||||
*
|
||||
* @param {panelview} previousViewNode Node that is currently shown as active,
|
||||
* but is about to be transitioned away.
|
||||
* @param {panelview} previousViewNode Node that is currently displayed, but
|
||||
* is about to be transitioned away. This
|
||||
* must be already inactive at this point.
|
||||
* @param {panelview} viewNode Node that will becode the active view,
|
||||
* after the transition has finished.
|
||||
* @param {Boolean} reverse Whether we're navigation back to a
|
||||
* previous view or forward to a next view.
|
||||
* @param {Element} anchor the anchor for which we're opening
|
||||
* a new panelview, if any
|
||||
*/
|
||||
async _transitionViews(previousViewNode, viewNode, reverse, anchor) {
|
||||
// Clean up any previous transition that may be active at this point.
|
||||
await this._cleanupTransitionPhase();
|
||||
|
||||
// There's absolutely no need to show off our epic animation skillz when
|
||||
// the panel's not even open.
|
||||
if (this._panel.state != "open") {
|
||||
return;
|
||||
}
|
||||
|
||||
async _transitionViews(previousViewNode, viewNode, reverse) {
|
||||
const { window } = this;
|
||||
|
||||
let nextPanelView = PanelView.forNode(viewNode);
|
||||
let prevPanelView = PanelView.forNode(previousViewNode);
|
||||
|
||||
if (this._autoResizeWorkaroundTimer)
|
||||
window.clearTimeout(this._autoResizeWorkaroundTimer);
|
||||
|
||||
let details = this._transitionDetails = {
|
||||
phase: TRANSITION_PHASES.START,
|
||||
previousViewNode, viewNode, reverse, anchor
|
||||
};
|
||||
|
||||
if (anchor)
|
||||
anchor.setAttribute("open", "true");
|
||||
|
||||
// Set the viewContainer dimensions to make sure only the current view is
|
||||
// visible.
|
||||
let olderView = reverse ? nextPanelView : prevPanelView;
|
||||
|
@ -884,8 +868,10 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
height: nextPanelView.knownHeight };
|
||||
nextPanelView.visible = true;
|
||||
} else if (viewNode.customRectGetter) {
|
||||
// Can't use Object.assign directly with a DOM Rect object because its properties
|
||||
// aren't enumerable.
|
||||
// We use a customRectGetter for WebExtensions panels, because they need
|
||||
// to query the size from an embedded browser. The presence of this
|
||||
// getter also provides an indication that the view node shouldn't be
|
||||
// moved around, otherwise the state of the browser would get disrupted.
|
||||
let width = prevPanelView.knownWidth;
|
||||
let height = prevPanelView.knownHeight;
|
||||
viewRect = Object.assign({height, width}, viewNode.customRectGetter());
|
||||
|
@ -894,27 +880,28 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
viewRect.height += this._dwu.getBoundsWithoutFlushing(header).height;
|
||||
}
|
||||
nextPanelView.visible = true;
|
||||
nextPanelView.descriptionHeightWorkaround();
|
||||
await nextPanelView.descriptionHeightWorkaround();
|
||||
} else {
|
||||
let oldSibling = viewNode.nextSibling || null;
|
||||
this._offscreenViewStack.style.minHeight = olderView.knownHeight + "px";
|
||||
this._offscreenViewStack.appendChild(viewNode);
|
||||
nextPanelView.visible = true;
|
||||
|
||||
// Now that the subview is visible, we can check the height of the
|
||||
// description elements it contains.
|
||||
nextPanelView.descriptionHeightWorkaround();
|
||||
await nextPanelView.descriptionHeightWorkaround();
|
||||
|
||||
viewRect = await window.promiseDocumentFlushed(() => {
|
||||
return this._dwu.getBoundsWithoutFlushing(viewNode);
|
||||
});
|
||||
|
||||
try {
|
||||
this._viewStack.insertBefore(viewNode, oldSibling);
|
||||
} catch (ex) {
|
||||
this._viewStack.appendChild(viewNode);
|
||||
// Bail out if the panel was closed in the meantime.
|
||||
if (!nextPanelView.isOpenIn(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Place back the view after all the other views that are already open in
|
||||
// order for the transition to work as expected.
|
||||
this._viewStack.appendChild(viewNode);
|
||||
|
||||
this._offscreenViewStack.style.removeProperty("min-height");
|
||||
}
|
||||
|
||||
|
@ -945,6 +932,10 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
// Now that all the elements are in place for the start of the transition,
|
||||
// give the layout code a chance to set the initial values.
|
||||
await window.promiseDocumentFlushed(() => {});
|
||||
// Bail out if the panel was closed in the meantime.
|
||||
if (!nextPanelView.isOpenIn(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Now set the viewContainer dimensions to that of the new view, which
|
||||
// kicks of the height animation.
|
||||
|
@ -956,14 +947,6 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
// sliding animation with smaller views.
|
||||
viewNode.style.width = viewRect.width + "px";
|
||||
|
||||
// For proper bookkeeping, mark the view that is about to scrolled out of
|
||||
// the visible area as inactive, because it won't be possible to simulate
|
||||
// mouse events on it properly. In practice this isn't important, because we
|
||||
// use the separate "transitioning" attribute on the panel to suppress
|
||||
// pointer events. This allows mouse events to be available for the main
|
||||
// view in regression tests that wait for the "popupshown" event.
|
||||
prevPanelView.active = false;
|
||||
|
||||
// Kick off the transition!
|
||||
details.phase = TRANSITION_PHASES.TRANSITION;
|
||||
this._viewStack.style.transform = "translateX(" + (moveToLeft ? "" : "-") + deltaX + "px)";
|
||||
|
@ -989,69 +972,46 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
});
|
||||
});
|
||||
|
||||
details.phase = TRANSITION_PHASES.END;
|
||||
|
||||
// Apply the final visibility, unless the view was closed in the meantime.
|
||||
if (nextPanelView.node.panelMultiView == this.node) {
|
||||
prevPanelView.visible = false;
|
||||
// Bail out if the panel was closed during the transition.
|
||||
if (!nextPanelView.isOpenIn(this)) {
|
||||
return;
|
||||
}
|
||||
prevPanelView.visible = false;
|
||||
|
||||
// This will complete the operation by removing any transition properties.
|
||||
await this._cleanupTransitionPhase(details);
|
||||
nextPanelView.node.style.removeProperty("width");
|
||||
deepestNode.style.removeProperty("outline");
|
||||
this._cleanupTransitionPhase();
|
||||
|
||||
// Focus the correct element, unless the view was closed in the meantime.
|
||||
if (nextPanelView.node.panelMultiView == this.node) {
|
||||
nextPanelView.focusSelectedElement();
|
||||
}
|
||||
nextPanelView.focusSelectedElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to clean up the attributes and properties set by `_transitionViews`
|
||||
* above. Which attributes and properties depends on the phase the transition
|
||||
* was left from - normally that'd be `TRANSITION_PHASES.END`.
|
||||
*
|
||||
* @param {Object} details Dictionary object containing details of the transition
|
||||
* that should be cleaned up after. Defaults to the most
|
||||
* recent details.
|
||||
* was left from.
|
||||
*/
|
||||
async _cleanupTransitionPhase(details = this._transitionDetails) {
|
||||
if (!details || !this.node)
|
||||
_cleanupTransitionPhase() {
|
||||
if (!this._transitionDetails) {
|
||||
return;
|
||||
}
|
||||
|
||||
let {phase, previousViewNode, viewNode, reverse, resolve, listener, cancelListener, anchor} = details;
|
||||
if (details == this._transitionDetails)
|
||||
this._transitionDetails = null;
|
||||
|
||||
// Do the things we _always_ need to do whenever the transition ends or is
|
||||
// interrupted.
|
||||
if (anchor)
|
||||
anchor.removeAttribute("open");
|
||||
let {phase, resolve, listener, cancelListener} = this._transitionDetails;
|
||||
this._transitionDetails = null;
|
||||
|
||||
if (phase >= TRANSITION_PHASES.START) {
|
||||
this._panel.removeAttribute("width");
|
||||
this._panel.removeAttribute("height");
|
||||
// Myeah, panel layout auto-resizing is a funky thing. We'll wait
|
||||
// another few milliseconds to remove the width and height 'fixtures',
|
||||
// to be sure we don't flicker annoyingly.
|
||||
// NB: HACK! Bug 1363756 is there to fix this.
|
||||
this._autoResizeWorkaroundTimer = this.window.setTimeout(() => {
|
||||
if (!this._viewContainer)
|
||||
return;
|
||||
this._viewContainer.style.removeProperty("height");
|
||||
this._viewContainer.style.removeProperty("width");
|
||||
}, 500);
|
||||
this._viewContainer.style.removeProperty("height");
|
||||
this._viewContainer.style.removeProperty("width");
|
||||
}
|
||||
if (phase >= TRANSITION_PHASES.PREPARE) {
|
||||
this._transitioning = false;
|
||||
if (reverse)
|
||||
this._viewStack.style.removeProperty("margin-inline-start");
|
||||
let deepestNode = reverse ? previousViewNode : viewNode;
|
||||
deepestNode.style.removeProperty("outline");
|
||||
this._viewStack.style.removeProperty("margin-inline-start");
|
||||
this._viewStack.style.removeProperty("transition");
|
||||
}
|
||||
if (phase >= TRANSITION_PHASES.TRANSITION) {
|
||||
this._viewStack.style.removeProperty("transform");
|
||||
viewNode.style.removeProperty("width");
|
||||
if (listener)
|
||||
this._viewContainer.removeEventListener("transitionend", listener);
|
||||
if (cancelListener)
|
||||
|
@ -1059,13 +1019,6 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
if (resolve)
|
||||
resolve();
|
||||
}
|
||||
if (phase >= TRANSITION_PHASES.END) {
|
||||
// We force 'display: none' on the previous view node to make sure that it
|
||||
// doesn't cause an annoying flicker whilst resetting the styles above.
|
||||
previousViewNode.style.display = "none";
|
||||
await this.window.promiseDocumentFlushed(() => {});
|
||||
previousViewNode.style.removeProperty("display");
|
||||
}
|
||||
}
|
||||
|
||||
_calculateMaxHeight() {
|
||||
|
@ -1114,10 +1067,11 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
}
|
||||
switch (aEvent.type) {
|
||||
case "keydown":
|
||||
if (!this._transitioning) {
|
||||
PanelView.forNode(this._currentSubView)
|
||||
.keyNavigation(aEvent, this._dir);
|
||||
}
|
||||
// Since we start listening for the "keydown" event when the popup is
|
||||
// already showing and stop listening when the panel is hidden, we
|
||||
// always have at least one view open.
|
||||
let currentView = this.openViews[this.openViews.length - 1];
|
||||
currentView.keyNavigation(aEvent, this._dir);
|
||||
break;
|
||||
case "mousemove":
|
||||
this.openViews.forEach(panelView => panelView.clearNavigation());
|
||||
|
@ -1148,10 +1102,13 @@ var PanelMultiView = class extends this.AssociatedToNode {
|
|||
break;
|
||||
}
|
||||
case "popupshown":
|
||||
let mainPanelView = PanelView.forNode(this._mainView);
|
||||
// Now that the main view is visible, we can check the height of the
|
||||
// description elements it contains.
|
||||
mainPanelView.descriptionHeightWorkaround();
|
||||
// The main view is always open and visible when the panel is first
|
||||
// shown, so we can check the height of the description elements it
|
||||
// contains and notify consumers using the ViewShown event. In order to
|
||||
// minimize flicker we need to allow synchronous reflows, and we still
|
||||
// make sure the ViewShown event is dispatched synchronously.
|
||||
let mainPanelView = this.openViews[0];
|
||||
mainPanelView.descriptionHeightWorkaround(true).catch(Cu.reportError);
|
||||
this._activateView(mainPanelView);
|
||||
break;
|
||||
case "popuphidden": {
|
||||
|
@ -1192,6 +1149,13 @@ var PanelView = class extends this.AssociatedToNode {
|
|||
this.active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the view is open in the specified PanelMultiView object.
|
||||
*/
|
||||
isOpenIn(panelMultiView) {
|
||||
return this.node.panelMultiView == panelMultiView.node;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "mainview" attribute is set before the panel is opened when this view
|
||||
* is displayed as the main view, and is removed before the <panelview> is
|
||||
|
@ -1305,9 +1269,12 @@ var PanelView = class extends this.AssociatedToNode {
|
|||
* of any of these elements changes, this function should be called to
|
||||
* refresh the calculated heights.
|
||||
*
|
||||
* This may trigger a synchronous layout.
|
||||
* @param allowSyncReflows
|
||||
* If set to true, the function takes a path that allows synchronous
|
||||
* reflows, but minimizes flickering. This is used for the main view
|
||||
* because we cannot use the workaround off-screen.
|
||||
*/
|
||||
descriptionHeightWorkaround() {
|
||||
async descriptionHeightWorkaround(allowSyncReflows = false) {
|
||||
if (!this.node.hasAttribute("descriptionheightworkaround")) {
|
||||
// This view does not require the workaround.
|
||||
return;
|
||||
|
@ -1317,34 +1284,41 @@ var PanelView = class extends this.AssociatedToNode {
|
|||
// First we reset any change we may have made previously. The first time
|
||||
// this is called, and in the best case scenario, this has no effect.
|
||||
let items = [];
|
||||
// Non-hidden <label> or <description> elements that also aren't empty
|
||||
// and also don't have a value attribute can be multiline (if their
|
||||
// text content is long enough).
|
||||
let isMultiline = ":not(:-moz-any([hidden],[value],:empty))";
|
||||
let selector = [
|
||||
"description" + isMultiline,
|
||||
"label" + isMultiline,
|
||||
"toolbarbutton[wrap]:not([hidden])",
|
||||
].join(",");
|
||||
for (let element of this.node.querySelectorAll(selector)) {
|
||||
// Ignore items in hidden containers.
|
||||
if (element.closest("[hidden]")) {
|
||||
continue;
|
||||
}
|
||||
// Take the label for toolbarbuttons; it only exists on those elements.
|
||||
element = element.labelElement || element;
|
||||
let collectItems = () => {
|
||||
// Non-hidden <label> or <description> elements that also aren't empty
|
||||
// and also don't have a value attribute can be multiline (if their
|
||||
// text content is long enough).
|
||||
let isMultiline = ":not(:-moz-any([hidden],[value],:empty))";
|
||||
let selector = [
|
||||
"description" + isMultiline,
|
||||
"label" + isMultiline,
|
||||
"toolbarbutton[wrap]:not([hidden])",
|
||||
].join(",");
|
||||
for (let element of this.node.querySelectorAll(selector)) {
|
||||
// Ignore items in hidden containers.
|
||||
if (element.closest("[hidden]")) {
|
||||
continue;
|
||||
}
|
||||
// Take the label for toolbarbuttons; it only exists on those elements.
|
||||
element = element.labelElement || element;
|
||||
|
||||
let bounds = element.getBoundingClientRect();
|
||||
let previous = gMultiLineElementsMap.get(element);
|
||||
// We don't need to (re-)apply the workaround for invisible elements or
|
||||
// on elements we've seen before and haven't changed in the meantime.
|
||||
if (!bounds.width || !bounds.height ||
|
||||
(previous && element.textContent == previous.textContent &&
|
||||
bounds.width == previous.bounds.width)) {
|
||||
continue;
|
||||
}
|
||||
let bounds = element.getBoundingClientRect();
|
||||
let previous = gMultiLineElementsMap.get(element);
|
||||
// We don't need to (re-)apply the workaround for invisible elements or
|
||||
// on elements we've seen before and haven't changed in the meantime.
|
||||
if (!bounds.width || !bounds.height ||
|
||||
(previous && element.textContent == previous.textContent &&
|
||||
bounds.width == previous.bounds.width)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
items.push({ element });
|
||||
items.push({ element });
|
||||
}
|
||||
};
|
||||
if (allowSyncReflows) {
|
||||
collectItems();
|
||||
} else {
|
||||
await this.window.promiseDocumentFlushed(collectItems);
|
||||
}
|
||||
|
||||
// Removing the 'height' property will only cause a layout flush in the next
|
||||
|
@ -1355,8 +1329,15 @@ var PanelView = class extends this.AssociatedToNode {
|
|||
|
||||
// We now read the computed style to store the height of any element that
|
||||
// may contain wrapping text.
|
||||
for (let item of items) {
|
||||
item.bounds = item.element.getBoundingClientRect();
|
||||
let measureItems = () => {
|
||||
for (let item of items) {
|
||||
item.bounds = item.element.getBoundingClientRect();
|
||||
}
|
||||
};
|
||||
if (allowSyncReflows) {
|
||||
measureItems();
|
||||
} else {
|
||||
await this.window.promiseDocumentFlushed(measureItems);
|
||||
}
|
||||
|
||||
// Now we can make all the necessary DOM changes at once.
|
||||
|
@ -1466,11 +1447,18 @@ var PanelView = class extends this.AssociatedToNode {
|
|||
* - The Right key functions the same as the Enter key, simulating a click
|
||||
* - The Left key triggers a navigation back to the previous view.
|
||||
*
|
||||
* Key navigation is only enabled while the view is active, meaning that this
|
||||
* method will return early if it is invoked during a sliding transition.
|
||||
*
|
||||
* @param {KeyEvent} event
|
||||
* @param {String} dir
|
||||
* Direction for arrow navigation, either "ltr" or "rtl".
|
||||
*/
|
||||
keyNavigation(event, dir) {
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
let buttons = this.buttons;
|
||||
if (!buttons || !buttons.length) {
|
||||
buttons = this.buttons = this.getNavigableElements();
|
||||
|
|
|
@ -410,7 +410,6 @@ const PanelUI = {
|
|||
multiView.setAttribute("id", "customizationui-widget-multiview");
|
||||
multiView.setAttribute("viewCacheId", "appMenu-viewCache");
|
||||
multiView.setAttribute("mainViewId", viewNode.id);
|
||||
multiView.setAttribute("ephemeral", true);
|
||||
tempPanel.appendChild(multiView);
|
||||
viewNode.classList.add("cui-widget-panelview");
|
||||
|
||||
|
|
|
@ -61,12 +61,13 @@ async function openPopup(panelIndex, viewIndex) {
|
|||
gPanelMultiViews[panelIndex].setAttribute("mainViewId",
|
||||
gPanelViews[viewIndex].id);
|
||||
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(gPanels[panelIndex],
|
||||
"popupshown");
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(gPanelViews[viewIndex],
|
||||
"ViewShown");
|
||||
PanelMultiView.openPopup(gPanels[panelIndex], gPanelAnchors[panelIndex],
|
||||
"bottomcenter topright");
|
||||
await promiseShown;
|
||||
|
||||
Assert.ok(PanelView.forNode(gPanelViews[viewIndex]).active);
|
||||
assertLabelVisible(viewIndex, true);
|
||||
}
|
||||
|
||||
|
@ -92,6 +93,7 @@ async function showSubView(panelIndex, viewIndex) {
|
|||
gPanelMultiViews[panelIndex].showSubView(gPanelViews[viewIndex]);
|
||||
await promiseShown;
|
||||
|
||||
Assert.ok(PanelView.forNode(gPanelViews[viewIndex]).active);
|
||||
assertLabelVisible(viewIndex, true);
|
||||
}
|
||||
|
||||
|
@ -104,6 +106,7 @@ async function goBack(panelIndex, viewIndex) {
|
|||
gPanelMultiViews[panelIndex].goBack();
|
||||
await promiseShown;
|
||||
|
||||
Assert.ok(PanelView.forNode(gPanelViews[viewIndex]).active);
|
||||
assertLabelVisible(viewIndex, true);
|
||||
}
|
||||
|
||||
|
@ -278,6 +281,38 @@ add_task(async function test_simple_event_sequence() {
|
|||
]);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that further navigation is suppressed until the new view is shown.
|
||||
*/
|
||||
add_task(async function test_navigation_suppression() {
|
||||
await openPopup(0, 0);
|
||||
|
||||
// Test re-entering the "showSubView" method.
|
||||
let promiseShown = BrowserTestUtils.waitForEvent(gPanelViews[1], "ViewShown");
|
||||
gPanelMultiViews[0].showSubView(gPanelViews[1]);
|
||||
Assert.ok(!PanelView.forNode(gPanelViews[0]).active,
|
||||
"The previous view should become inactive synchronously.");
|
||||
|
||||
// The following call will have no effect.
|
||||
gPanelMultiViews[0].showSubView(gPanelViews[2]);
|
||||
await promiseShown;
|
||||
|
||||
// Test re-entering the "goBack" method.
|
||||
promiseShown = BrowserTestUtils.waitForEvent(gPanelViews[0], "ViewShown");
|
||||
gPanelMultiViews[0].goBack();
|
||||
Assert.ok(!PanelView.forNode(gPanelViews[1]).active,
|
||||
"The previous view should become inactive synchronously.");
|
||||
|
||||
// The following call will have no effect.
|
||||
gPanelMultiViews[0].goBack();
|
||||
await promiseShown;
|
||||
|
||||
// Main view 0 should be displayed.
|
||||
assertLabelVisible(0, true);
|
||||
|
||||
await hidePopup(0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests reusing views that are already open in another panel. In this test, the
|
||||
* structure of the first panel will change dynamically:
|
||||
|
|
|
@ -316,7 +316,7 @@ class BasePopup {
|
|||
stylesheets: this.STYLESHEETS,
|
||||
});
|
||||
|
||||
browser.loadURI(popupURL);
|
||||
browser.loadURIWithFlags(popupURL, {triggeringPrincipal: this.extension.principal});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,9 @@ class ParentDevToolsPanel {
|
|||
},
|
||||
});
|
||||
|
||||
browser.loadURI(url);
|
||||
browser.loadURIWithFlags(url, {
|
||||
triggeringPrincipal: extension.principal,
|
||||
});
|
||||
}
|
||||
|
||||
destroyBrowserElement() {
|
||||
|
|
|
@ -176,7 +176,9 @@ class DevToolsPage extends HiddenExtensionPage {
|
|||
},
|
||||
});
|
||||
|
||||
this.browser.loadURI(this.url);
|
||||
this.browser.loadURIWithFlags(this.url, {
|
||||
triggeringPrincipal: this.extension.principal,
|
||||
});
|
||||
|
||||
await this.waitForTopLevelContext;
|
||||
}
|
||||
|
|
|
@ -136,20 +136,6 @@ this.sidebarAction = class extends ExtensionAPI {
|
|||
}
|
||||
}
|
||||
|
||||
sidebarUrl(panel) {
|
||||
let url = `${sidebarURL}?panel=${encodeURIComponent(panel)}`;
|
||||
|
||||
if (this.extension.remote) {
|
||||
url += "&remote=1";
|
||||
}
|
||||
|
||||
if (this.browserStyle) {
|
||||
url += "&browser-style=1";
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
createMenuItem(window, details) {
|
||||
let {document, SidebarUI} = window;
|
||||
|
||||
|
@ -161,7 +147,12 @@ this.sidebarAction = class extends ExtensionAPI {
|
|||
broadcaster.setAttribute("type", "checkbox");
|
||||
broadcaster.setAttribute("group", "sidebar");
|
||||
broadcaster.setAttribute("label", details.title);
|
||||
broadcaster.setAttribute("sidebarurl", this.sidebarUrl(details.panel));
|
||||
broadcaster.setAttribute("sidebarurl", sidebarURL);
|
||||
broadcaster.setAttribute("panel", details.panel);
|
||||
if (this.browserStyle) {
|
||||
broadcaster.setAttribute("browserStyle", "true");
|
||||
}
|
||||
broadcaster.setAttribute("extensionId", this.extension.id);
|
||||
let id = `ext-key-id-${this.id}`;
|
||||
broadcaster.setAttribute("key", id);
|
||||
|
||||
|
@ -227,10 +218,9 @@ this.sidebarAction = class extends ExtensionAPI {
|
|||
broadcaster.setAttribute("tooltiptext", title);
|
||||
broadcaster.setAttribute("label", title);
|
||||
|
||||
let url = this.sidebarUrl(tabData.panel);
|
||||
let urlChanged = url !== broadcaster.getAttribute("sidebarurl");
|
||||
let urlChanged = tabData.panel !== broadcaster.getAttribute("panel");
|
||||
if (urlChanged) {
|
||||
broadcaster.setAttribute("sidebarurl", url);
|
||||
broadcaster.setAttribute("panel", tabData.panel);
|
||||
}
|
||||
|
||||
this.setMenuIcon(menu, tabData);
|
||||
|
|
|
@ -507,10 +507,13 @@ this.tabs = class extends ExtensionAPI {
|
|||
return Promise.reject({message: `Illegal URL: ${url}`});
|
||||
}
|
||||
|
||||
let flags = updateProperties.loadReplace
|
||||
? Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY
|
||||
: Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
nativeTab.linkedBrowser.loadURIWithFlags(url, {flags});
|
||||
let options = {
|
||||
flags: updateProperties.loadReplace
|
||||
? Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY
|
||||
: Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
|
||||
triggeringPrincipal: context.principal,
|
||||
};
|
||||
nativeTab.linkedBrowser.loadURIWithFlags(url, options);
|
||||
}
|
||||
|
||||
if (updateProperties.active !== null) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
},
|
||||
{
|
||||
"namespace": "devtools",
|
||||
"permissions": ["devtools"],
|
||||
"permissions": ["manifest:devtools_page"],
|
||||
"allowedContexts": ["devtools", "devtools_only"],
|
||||
"defaultContexts": ["devtools", "devtools_only"]
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* openTabContextMenu closeTabContextMenu
|
||||
* openToolsMenu closeToolsMenu
|
||||
* imageBuffer imageBufferFromDataURI
|
||||
* getListStyleImage getPanelForNode
|
||||
* getListStyleImage getPanelForNode getPanelViewForNode
|
||||
* awaitExtensionPanel awaitPopupResize
|
||||
* promiseContentDimensions alterContent
|
||||
* promisePrefChangeObserved openContextMenuInFrame
|
||||
|
@ -201,6 +201,13 @@ function getPanelForNode(node) {
|
|||
return node;
|
||||
}
|
||||
|
||||
function getPanelViewForNode(node) {
|
||||
while (node && node.localName != "panelview") {
|
||||
node = node.parentNode;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
var awaitBrowserLoaded = browser => ContentTask.spawn(browser, null, () => {
|
||||
if (content.document.readyState !== "complete" ||
|
||||
content.document.documentURI === "about:blank") {
|
||||
|
@ -215,9 +222,20 @@ var awaitExtensionPanel = async function(extension, win = window, awaitLoad = tr
|
|||
win.document, "WebExtPopupLoaded", true,
|
||||
event => event.detail.extension.id === extension.id);
|
||||
|
||||
let panelview = getPanelViewForNode(browser);
|
||||
let viewShownPromise = null;
|
||||
if (panelview) {
|
||||
let view = PanelView.forNode(panelview);
|
||||
if (!view.active) {
|
||||
viewShownPromise = BrowserTestUtils.waitForEvent(panelview, "ViewShown");
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
promisePopupShown(getPanelForNode(browser)),
|
||||
|
||||
viewShownPromise,
|
||||
|
||||
awaitLoad && awaitBrowserLoaded(browser),
|
||||
]);
|
||||
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NewTabPrefsProvider"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm", {});
|
||||
return EventEmitter;
|
||||
});
|
||||
|
||||
// Supported prefs and data type
|
||||
const gPrefsMap = new Map([
|
||||
["browser.newtabpage.enabled", "bool"],
|
||||
["browser.newtabpage.enhanced", "bool"],
|
||||
["browser.newtabpage.introShown", "bool"],
|
||||
["browser.newtabpage.updateIntroShown", "bool"],
|
||||
["browser.newtabpage.pinned", "str"],
|
||||
["browser.newtabpage.blocked", "str"],
|
||||
["browser.search.hiddenOneOffs", "str"],
|
||||
]);
|
||||
|
||||
// prefs that are important for the newtab page
|
||||
const gNewtabPagePrefs = new Set([
|
||||
"browser.newtabpage.enabled",
|
||||
"browser.newtabpage.enhanced",
|
||||
"browser.newtabpage.pinned",
|
||||
"browser.newtabpage.blocked",
|
||||
"browser.newtabpage.introShown",
|
||||
"browser.newtabpage.updateIntroShown",
|
||||
"browser.search.hiddenOneOffs",
|
||||
]);
|
||||
|
||||
let PrefsProvider = function PrefsProvider() {
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
||||
PrefsProvider.prototype = {
|
||||
|
||||
observe(subject, topic, data) { // jshint ignore:line
|
||||
if (topic === "nsPref:changed") {
|
||||
if (gPrefsMap.has(data)) {
|
||||
switch (gPrefsMap.get(data)) {
|
||||
case "bool":
|
||||
this.emit(data, Services.prefs.getBoolPref(data, false));
|
||||
break;
|
||||
case "str":
|
||||
this.emit(data, Services.prefs.getStringPref(data, ""));
|
||||
break;
|
||||
case "localized":
|
||||
if (Services.prefs.getPrefType(data) == Ci.nsIPrefBranch.PREF_INVALID) {
|
||||
this.emit(data, "");
|
||||
} else {
|
||||
try {
|
||||
this.emit(data, Services.prefs.getComplexValue(data, Ci.nsIPrefLocalizedString));
|
||||
} catch (e) {
|
||||
this.emit(data, Services.prefs.getStringPref(data));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.emit(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Cu.reportError(new Error("NewTabPrefsProvider observing unknown topic"));
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Return the preferences that are important to the newtab page
|
||||
*/
|
||||
get newtabPagePrefs() {
|
||||
let results = {};
|
||||
for (let pref of gNewtabPagePrefs) {
|
||||
results[pref] = null;
|
||||
|
||||
if (Services.prefs.getPrefType(pref) != Ci.nsIPrefBranch.PREF_INVALID) {
|
||||
switch (gPrefsMap.get(pref)) {
|
||||
case "bool":
|
||||
results[pref] = Services.prefs.getBoolPref(pref);
|
||||
break;
|
||||
case "str":
|
||||
results[pref] = Services.prefs.getStringPref(pref);
|
||||
break;
|
||||
case "localized":
|
||||
try {
|
||||
results[pref] = Services.prefs.getComplexValue(pref, Ci.nsIPrefLocalizedString);
|
||||
} catch (e) {
|
||||
results[pref] = Services.prefs.getStringPref(pref);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
get prefsMap() {
|
||||
return gPrefsMap;
|
||||
},
|
||||
|
||||
init() {
|
||||
for (let pref of gPrefsMap.keys()) {
|
||||
Services.prefs.addObserver(pref, this);
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
for (let pref of gPrefsMap.keys()) {
|
||||
Services.prefs.removeObserver(pref, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton that serves as the default new tab pref provider for the grid.
|
||||
*/
|
||||
const gPrefs = new PrefsProvider();
|
||||
|
||||
let NewTabPrefsProvider = {
|
||||
prefs: gPrefs,
|
||||
newtabPagePrefSet: gNewtabPagePrefs,
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
/* exported NewTabRemoteResources */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NewTabRemoteResources"];
|
||||
|
||||
const NewTabRemoteResources = {
|
||||
MODE_CHANNEL_MAP: {
|
||||
production: {origin: "https://content.cdn.mozilla.net"},
|
||||
staging: {origin: "https://s3_proxy_tiles.stage.mozaws.net"},
|
||||
test: {origin: "https://example.com"},
|
||||
test2: {origin: "http://mochi.test:8888"},
|
||||
dev: {origin: "http://localhost:8888"}
|
||||
}
|
||||
};
|
|
@ -1,98 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NewTabSearchProvider"];
|
||||
|
||||
const CURRENT_ENGINE = "browser-search-engine-modified";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm", {});
|
||||
return EventEmitter;
|
||||
});
|
||||
|
||||
function SearchProvider() {
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
SearchProvider.prototype = {
|
||||
|
||||
observe(subject, topic, data) { // jshint unused:false
|
||||
// all other topics are not relevant to content searches and can be
|
||||
// ignored by NewTabSearchProvider
|
||||
if (data === "engine-current" && topic === CURRENT_ENGINE) {
|
||||
(async () => {
|
||||
try {
|
||||
let state = await ContentSearch.currentStateObj(true);
|
||||
let engine = state.currentEngine;
|
||||
this.emit(CURRENT_ENGINE, engine);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
})();
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
try {
|
||||
Services.obs.addObserver(this, CURRENT_ENGINE, true);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference
|
||||
]),
|
||||
|
||||
uninit() {
|
||||
try {
|
||||
Services.obs.removeObserver(this, CURRENT_ENGINE);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
get searchSuggestionUIStrings() {
|
||||
return ContentSearch.searchSuggestionUIStrings;
|
||||
},
|
||||
|
||||
removeFormHistory({browser}, suggestion) {
|
||||
ContentSearch.removeFormHistoryEntry({target: browser}, suggestion);
|
||||
},
|
||||
|
||||
manageEngines(browser) {
|
||||
const browserWin = browser.ownerGlobal;
|
||||
browserWin.openPreferences("paneSearch", { origin: "contentSearch" });
|
||||
},
|
||||
|
||||
async asyncGetState() {
|
||||
let state = await ContentSearch.currentStateObj(true);
|
||||
return state;
|
||||
},
|
||||
|
||||
async asyncPerformSearch({browser}, searchData) {
|
||||
ContentSearch.performSearch({target: browser}, searchData);
|
||||
await ContentSearch.addFormHistoryEntry({target: browser}, searchData.searchString);
|
||||
},
|
||||
|
||||
async asyncCycleEngine(engineName) {
|
||||
Services.search.currentEngine = Services.search.getEngineByName(engineName);
|
||||
let state = await ContentSearch.currentStateObj(true);
|
||||
let newEngine = state.currentEngine;
|
||||
this.emit(CURRENT_ENGINE, newEngine);
|
||||
},
|
||||
|
||||
async asyncGetSuggestions(engineName, searchString, target) {
|
||||
let suggestions = ContentSearch.getSuggestions(engineName, searchString, target.browser);
|
||||
return suggestions;
|
||||
},
|
||||
};
|
||||
|
||||
const NewTabSearchProvider = {
|
||||
search: new SearchProvider(),
|
||||
};
|
|
@ -1,286 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["NewTabWebChannel"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "NewTabRemoteResources",
|
||||
"resource:///modules/NewTabRemoteResources.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "WebChannel",
|
||||
"resource://gre/modules/WebChannel.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm", {});
|
||||
return EventEmitter;
|
||||
});
|
||||
|
||||
const CHAN_ID = "newtab";
|
||||
const PREF_ENABLED = "browser.newtabpage.remote";
|
||||
const PREF_MODE = "browser.newtabpage.remote.mode";
|
||||
|
||||
/**
|
||||
* NewTabWebChannel is the conduit for all communication with unprivileged newtab instances.
|
||||
*
|
||||
* It allows for the ability to broadcast to all newtab browsers.
|
||||
* If the browser.newtab.remote pref is false, the object will be in an uninitialized state.
|
||||
*
|
||||
* Mode choices:
|
||||
* 'production': pages from our production CDN
|
||||
* 'staging': pages from our staging CDN
|
||||
* 'test': intended for tests
|
||||
* 'test2': intended for tests
|
||||
* 'dev': intended for development
|
||||
*
|
||||
* An unknown mode will result in 'production' mode, which is the default
|
||||
*
|
||||
* Incoming messages are expected to be JSON-serialized and in the format:
|
||||
*
|
||||
* {
|
||||
* type: "REQUEST_SCREENSHOT",
|
||||
* data: {
|
||||
* url: "https://example.com"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Or:
|
||||
*
|
||||
* {
|
||||
* type: "REQUEST_SCREENSHOT",
|
||||
* }
|
||||
*
|
||||
* Outgoing messages are expected to be objects serializable by structured cloning, in a similar format:
|
||||
* {
|
||||
* type: "RECEIVE_SCREENSHOT",
|
||||
* data: {
|
||||
* "url": "https://example.com",
|
||||
* "image": "dataURi:....."
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
let NewTabWebChannelImpl = function NewTabWebChannelImpl() {
|
||||
EventEmitter.decorate(this);
|
||||
this._handlePrefChange = this._handlePrefChange.bind(this);
|
||||
this._incomingMessage = this._incomingMessage.bind(this);
|
||||
};
|
||||
|
||||
NewTabWebChannelImpl.prototype = {
|
||||
_prefs: {},
|
||||
_channel: null,
|
||||
|
||||
// a WeakMap containing browsers as keys and a weak ref to their principal
|
||||
// as value
|
||||
_principals: null,
|
||||
|
||||
// a Set containing weak refs to browsers
|
||||
_browsers: null,
|
||||
|
||||
/*
|
||||
* Returns current channel's ID
|
||||
*/
|
||||
get chanId() {
|
||||
return CHAN_ID;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns the number of browsers currently tracking
|
||||
*/
|
||||
get numBrowsers() {
|
||||
return this._getBrowserRefs().length;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns current channel's origin
|
||||
*/
|
||||
get origin() {
|
||||
if (!(this._prefs.mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
|
||||
this._prefs.mode = "production";
|
||||
}
|
||||
return NewTabRemoteResources.MODE_CHANNEL_MAP[this._prefs.mode].origin;
|
||||
},
|
||||
|
||||
/*
|
||||
* Unloads all browsers and principals
|
||||
*/
|
||||
_unloadAll() {
|
||||
if (this._principals != null) {
|
||||
this._principals = new WeakMap();
|
||||
}
|
||||
this._browsers = new Set();
|
||||
this.emit("targetUnloadAll");
|
||||
},
|
||||
|
||||
/*
|
||||
* Checks if a browser is known
|
||||
*
|
||||
* This will cause an iteration through all known browsers.
|
||||
* That's ok, we don't expect a lot of browsers
|
||||
*/
|
||||
_isBrowserKnown(browser) {
|
||||
for (let bRef of this._getBrowserRefs()) {
|
||||
let b = bRef.get();
|
||||
if (b && b.permanentKey === browser.permanentKey) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/*
|
||||
* Obtains all known browser refs
|
||||
*/
|
||||
_getBrowserRefs() {
|
||||
// Some code may try to emit messages after teardown.
|
||||
if (!this._browsers) {
|
||||
return [];
|
||||
}
|
||||
let refs = [];
|
||||
for (let bRef of this._browsers) {
|
||||
/*
|
||||
* even though we hold a weak ref to browser, it seems that browser
|
||||
* objects aren't gc'd immediately after a tab closes. They stick around
|
||||
* in memory, but thankfully they don't have a documentURI in that case
|
||||
*/
|
||||
let browser = bRef.get();
|
||||
if (browser && browser.documentURI) {
|
||||
refs.push(bRef);
|
||||
} else {
|
||||
// need to clean up principals because the browser object is not gc'ed
|
||||
// immediately
|
||||
this._principals.delete(browser);
|
||||
this._browsers.delete(bRef);
|
||||
this.emit("targetUnload");
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
},
|
||||
|
||||
/*
|
||||
* Receives a message from content.
|
||||
*
|
||||
* Keeps track of browsers for broadcast, relays messages to listeners.
|
||||
*/
|
||||
_incomingMessage(id, message, target) {
|
||||
if (this.chanId !== id) {
|
||||
Cu.reportError(new Error("NewTabWebChannel unexpected message destination"));
|
||||
}
|
||||
|
||||
/*
|
||||
* need to differentiate by browser, because event targets are created each
|
||||
* time a message is sent.
|
||||
*/
|
||||
if (!this._isBrowserKnown(target.browser)) {
|
||||
this._browsers.add(Cu.getWeakReference(target.browser));
|
||||
this._principals.set(target.browser, Cu.getWeakReference(target.principal));
|
||||
this.emit("targetAdd");
|
||||
}
|
||||
|
||||
try {
|
||||
let msg = JSON.parse(message);
|
||||
this.emit(msg.type, {data: msg.data, target});
|
||||
} catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sends a message to all known browsers
|
||||
*/
|
||||
broadcast(actionType, message) {
|
||||
for (let bRef of this._getBrowserRefs()) {
|
||||
let browser = bRef.get();
|
||||
try {
|
||||
let principal = this._principals.get(browser).get();
|
||||
if (principal && browser && browser.documentURI) {
|
||||
this._channel.send({type: actionType, data: message}, {browser, principal});
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(new Error("NewTabWebChannel WeakRef is dead"));
|
||||
this._principals.delete(browser);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sends a message to a specific target
|
||||
*/
|
||||
send(actionType, message, target) {
|
||||
try {
|
||||
this._channel.send({type: actionType, data: message}, target);
|
||||
} catch (e) {
|
||||
// Web Channel might be dead
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Pref change observer callback
|
||||
*/
|
||||
_handlePrefChange(prefName, newState, forceState) { // eslint-disable-line no-unused-vars
|
||||
switch (prefName) {
|
||||
case PREF_ENABLED:
|
||||
if (!this._prefs.enabled && newState) {
|
||||
// changing state from disabled to enabled
|
||||
this.setupState();
|
||||
} else if (this._prefs.enabled && !newState) {
|
||||
// changing state from enabled to disabled
|
||||
this.tearDownState();
|
||||
}
|
||||
break;
|
||||
case PREF_MODE:
|
||||
if (this._prefs.mode !== newState) {
|
||||
// changing modes
|
||||
this.tearDownState();
|
||||
this.setupState();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sets up the internal state
|
||||
*/
|
||||
setupState() {
|
||||
this._prefs.enabled = Services.prefs.getBoolPref(PREF_ENABLED, false);
|
||||
|
||||
let mode = Services.prefs.getStringPref(PREF_MODE, "production");
|
||||
if (!(mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
|
||||
mode = "production";
|
||||
}
|
||||
this._prefs.mode = mode;
|
||||
this._principals = new WeakMap();
|
||||
this._browsers = new Set();
|
||||
|
||||
if (this._prefs.enabled) {
|
||||
this._channel = new WebChannel(this.chanId, Services.io.newURI(this.origin));
|
||||
this._channel.listen(this._incomingMessage);
|
||||
}
|
||||
},
|
||||
|
||||
tearDownState() {
|
||||
if (this._channel) {
|
||||
this._channel.stopListening();
|
||||
}
|
||||
this._prefs = {};
|
||||
this._unloadAll();
|
||||
this._channel = null;
|
||||
this._principals = null;
|
||||
this._browsers = null;
|
||||
},
|
||||
|
||||
init() {
|
||||
this.setupState();
|
||||
NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handlePrefChange);
|
||||
NewTabPrefsProvider.prefs.on(PREF_MODE, this._handlePrefChange);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
this.tearDownState();
|
||||
NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handlePrefChange);
|
||||
NewTabPrefsProvider.prefs.off(PREF_MODE, this._handlePrefChange);
|
||||
}
|
||||
};
|
||||
|
||||
let NewTabWebChannel = new NewTabWebChannelImpl();
|
|
@ -13,13 +13,6 @@ XPCSHELL_TESTS_MANIFESTS += [
|
|||
'tests/xpcshell/xpcshell.ini',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'NewTabPrefsProvider.jsm',
|
||||
'NewTabRemoteResources.jsm',
|
||||
'NewTabSearchProvider.jsm',
|
||||
'NewTabWebChannel.jsm'
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAboutNewTabService.idl',
|
||||
]
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
add_task(async function test_observe() {
|
||||
let prefsMap = NewTabPrefsProvider.prefs.prefsMap;
|
||||
for (let prefName of prefsMap.keys()) {
|
||||
let prefValueType = prefsMap.get(prefName);
|
||||
|
||||
let beforeVal;
|
||||
let afterVal;
|
||||
|
||||
switch (prefValueType) {
|
||||
case "bool":
|
||||
beforeVal = false;
|
||||
afterVal = true;
|
||||
Preferences.set(prefName, beforeVal);
|
||||
break;
|
||||
case "localized":
|
||||
case "str":
|
||||
beforeVal = "";
|
||||
afterVal = "someStr";
|
||||
Preferences.set(prefName, beforeVal);
|
||||
break;
|
||||
}
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
let promise = new Promise(resolve => {
|
||||
NewTabPrefsProvider.prefs.once(prefName, (name, data) => { // jshint ignore:line
|
||||
resolve([name, data]);
|
||||
});
|
||||
});
|
||||
Preferences.set(prefName, afterVal);
|
||||
let [actualName, actualData] = await promise;
|
||||
equal(prefName, actualName, `emitter sent the correct pref: ${prefName}`);
|
||||
equal(afterVal, actualData, `emitter collected correct pref data for ${prefName}`);
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
}
|
||||
});
|
|
@ -1,74 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "NewTabSearchProvider",
|
||||
"resource:///modules/NewTabSearchProvider.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
// ensure a profile exists
|
||||
do_get_profile();
|
||||
|
||||
function hasProp(obj) {
|
||||
return function(aProp) {
|
||||
ok(obj.hasOwnProperty(aProp), `expect to have property ${aProp}`);
|
||||
};
|
||||
}
|
||||
|
||||
add_task(async function test_search() {
|
||||
ContentSearch.init();
|
||||
let observerPromise = new Promise(resolve => {
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
||||
if (aData === "init-complete" && aTopic === "browser-search-service") {
|
||||
Services.obs.removeObserver(observer, "browser-search-service");
|
||||
resolve();
|
||||
}
|
||||
}, "browser-search-service");
|
||||
});
|
||||
Services.search.init();
|
||||
await observerPromise;
|
||||
Assert.ok(Services.search.isInitialized);
|
||||
|
||||
// get initial state of search and check it has correct properties
|
||||
let state = await NewTabSearchProvider.search.asyncGetState();
|
||||
let stateProps = hasProp(state);
|
||||
["engines", "currentEngine"].forEach(stateProps);
|
||||
|
||||
// check that the current engine is correct and has correct properties
|
||||
let {currentEngine} = state;
|
||||
equal(currentEngine.name, Services.search.currentEngine.name, "Current engine has been correctly set");
|
||||
var engineProps = hasProp(currentEngine);
|
||||
["name", "placeholder", "iconBuffer"].forEach(engineProps);
|
||||
|
||||
// create dummy test engines to test observer
|
||||
Services.search.addEngineWithDetails("TestSearch1", "", "", "", "GET",
|
||||
"http://example.com/?q={searchTerms}");
|
||||
Services.search.addEngineWithDetails("TestSearch2", "", "", "", "GET",
|
||||
"http://example.com/?q={searchTerms}");
|
||||
|
||||
// set one of the dummy test engines to the default engine
|
||||
Services.search.defaultEngine = Services.search.getEngineByName("TestSearch1");
|
||||
|
||||
// test that the event emitter is working by setting a new current engine "TestSearch2"
|
||||
let engineName = "TestSearch2";
|
||||
NewTabSearchProvider.search.init();
|
||||
|
||||
// event emitter will fire when current engine is changed
|
||||
let promise = new Promise(resolve => {
|
||||
NewTabSearchProvider.search.once("browser-search-engine-modified", (name, data) => { // jshint ignore:line
|
||||
resolve([name, data.name]);
|
||||
});
|
||||
});
|
||||
|
||||
// set a new current engine
|
||||
Services.search.currentEngine = Services.search.getEngineByName(engineName);
|
||||
let expectedEngineName = Services.search.currentEngine.name;
|
||||
|
||||
// emitter should fire and return the new engine
|
||||
let [eventName, actualEngineName] = await promise;
|
||||
equal(eventName, "browser-search-engine-modified", `emitter sent the correct event ${eventName}`);
|
||||
equal(expectedEngineName, actualEngineName, `emitter set the correct engine ${expectedEngineName}`);
|
||||
NewTabSearchProvider.search.uninit();
|
||||
});
|
|
@ -4,5 +4,3 @@ firefox-appdir = browser
|
|||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_AboutNewTabService.js]
|
||||
[test_NewTabPrefsProvider.js]
|
||||
[test_NewTabSearchProvider.js]
|
||||
|
|
|
@ -146,7 +146,7 @@ add_task(async function testStayopenBookmarksClicks() {
|
|||
newTab = await promiseTabOpened;
|
||||
ok(true, "Bookmark middle-click opened new tab.");
|
||||
await BrowserTestUtils.removeTab(newTab);
|
||||
is(PanelUI.multiView.current.id, "PanelUI-bookmarks", "Should still show the bookmarks subview");
|
||||
ok(PanelView.forNode(BMview).active, "Should still show the bookmarks subview");
|
||||
ok(appMenu.open, "Menu should remain open.");
|
||||
|
||||
// Close the App Menu
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
<!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/preferences/connection.dtd">
|
||||
<!ENTITY % siteDataSettingsDTD SYSTEM
|
||||
"chrome://browser/locale/preferences/siteDataSettings.dtd" >
|
||||
<!ENTITY % clearSiteDataDTD SYSTEM
|
||||
"chrome://browser/locale/preferences/clearSiteData.dtd" >
|
||||
<!ENTITY % privacyDTD SYSTEM "chrome://browser/locale/preferences/privacy.dtd">
|
||||
<!ENTITY % searchDTD SYSTEM "chrome://browser/locale/preferences/search.dtd">
|
||||
<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
|
||||
|
@ -64,6 +66,7 @@
|
|||
%deviceManangerDTD;
|
||||
%connectionDTD;
|
||||
%siteDataSettingsDTD;
|
||||
%clearSiteDataDTD;
|
||||
%privacyDTD;
|
||||
%searchDTD;
|
||||
%syncBrandDTD;
|
||||
|
|
|
@ -408,7 +408,7 @@ var gPrivacyPane = {
|
|||
signonBundle.getString("loginsDescriptionAll2"),
|
||||
]);
|
||||
appendSearchKeywords("cookieExceptions", [
|
||||
bundlePrefs.getString("cookiepermissionstext"),
|
||||
bundlePrefs.getString("cookiepermissionstext1"),
|
||||
]);
|
||||
appendSearchKeywords("trackingProtectionExceptions", [
|
||||
bundlePrefs.getString("trackingprotectionpermissionstitle"),
|
||||
|
@ -454,7 +454,7 @@ var gPrivacyPane = {
|
|||
pkiBundle.getString("enable_fips"),
|
||||
]);
|
||||
appendSearchKeywords("siteDataSettings", [
|
||||
bundlePrefs.getString("siteDataSettings2.description"),
|
||||
bundlePrefs.getString("siteDataSettings3.description"),
|
||||
bundlePrefs.getString("removeAllCookies.label"),
|
||||
bundlePrefs.getString("removeSelectedCookies.label"),
|
||||
]);
|
||||
|
@ -881,8 +881,8 @@ var gPrivacyPane = {
|
|||
allowVisible: true,
|
||||
prefilledHost: "",
|
||||
permissionType: "cookie",
|
||||
windowTitle: bundlePreferences.getString("cookiepermissionstitle"),
|
||||
introText: bundlePreferences.getString("cookiepermissionstext")
|
||||
windowTitle: bundlePreferences.getString("cookiepermissionstitle1"),
|
||||
introText: bundlePreferences.getString("cookiepermissionstext1")
|
||||
};
|
||||
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
|
||||
null, params);
|
||||
|
@ -1405,7 +1405,7 @@ var gPrivacyPane = {
|
|||
let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
|
||||
let totalUsage = siteDataUsage + cacheUsage;
|
||||
let size = DownloadUtils.convertByteUnits(totalUsage);
|
||||
totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize1", size);
|
||||
totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize2", size);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -75,20 +75,11 @@
|
|||
<hbox>
|
||||
<menulist id="historyMode">
|
||||
<menupopup>
|
||||
<menuitem label="&historyHeader.remember.label;" value="remember" searchkeywords="&rememberDescription.label;"/>
|
||||
<menuitem label="&historyHeader.remember.label;" value="remember" searchkeywords="&rememberDescription1.label;"/>
|
||||
<menuitem label="&historyHeader.dontremember.label;" value="dontremember" searchkeywords="&dontrememberDescription.label;"/>
|
||||
<menuitem label="&historyHeader.custom.label;" value="custom" searchkeywords="&privateBrowsingPermanent2.label;
|
||||
&rememberHistory2.label;
|
||||
&rememberSearchForm.label;
|
||||
&acceptCookies3.label;
|
||||
&cookieExceptions.label;
|
||||
&acceptThirdParty3.pre.label;
|
||||
&acceptThirdParty.always.label;
|
||||
&acceptThirdParty.visited.label;
|
||||
&acceptThirdParty.never.label;
|
||||
&keepUntil2.label;
|
||||
&expire.label;
|
||||
&close.label;
|
||||
&clearOnClose.label;
|
||||
&clearOnCloseSettings.label;"/>
|
||||
</menupopup>
|
||||
|
@ -101,14 +92,14 @@
|
|||
<vbox id="historyRememberPane">
|
||||
<hbox align="center" flex="1">
|
||||
<vbox flex="1">
|
||||
<description>&rememberDescription.label;</description>
|
||||
<description class="description-with-side-element">&rememberDescription1.label;</description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<vbox id="historyDontRememberPane">
|
||||
<hbox align="center" flex="1">
|
||||
<vbox flex="1">
|
||||
<description>&dontrememberDescription.label;</description>
|
||||
<description class="description-with-side-element">&dontrememberDescription.label;</description>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
@ -172,86 +163,95 @@
|
|||
|
||||
<hbox data-subcategory="sitedata" align="baseline">
|
||||
<vbox flex="1">
|
||||
<description class="description-with-side-element" flex="1">
|
||||
<html:span id="totalSiteDataSize" class="tail-with-learn-more"></html:span>
|
||||
<label id="siteDataLearnMoreLink" class="learnMore text-link">&siteDataLearnMoreLink.label;</label>
|
||||
</description>
|
||||
<radiogroup id="acceptCookies"
|
||||
preference="network.cookie.cookieBehavior"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptCookies();">
|
||||
<description flex="1">
|
||||
<label id="totalSiteDataSize" class="tail-with-learn-more"></label>
|
||||
<label id="siteDataLearnMoreLink" class="learnMore text-link">&siteDataLearnMoreLink.label;</label>
|
||||
</description>
|
||||
<hbox id="cookiesBox">
|
||||
<radio label="&acceptCookies3.label;"
|
||||
value="0"
|
||||
accesskey="&acceptCookies3.accesskey;"
|
||||
<hbox id="cookiesBox">
|
||||
<radio label="&acceptCookies4.label;"
|
||||
value="0"
|
||||
accesskey="&acceptCookies4.accesskey;"
|
||||
flex="1" />
|
||||
</hbox>
|
||||
<hbox id="keepRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="keepUntil"
|
||||
control="keepCookiesUntil"
|
||||
accesskey="&keepUntil2.accesskey;">&keepUntil2.label;</label>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<menulist id="keepCookiesUntil"
|
||||
preference="network.cookie.lifetimePolicy">
|
||||
<menupopup>
|
||||
<menuitem label="&expire.label;" value="0"/>
|
||||
<menuitem label="&close.label;" value="2"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<hbox id="acceptThirdPartyRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="acceptThirdPartyLabel" control="acceptThirdPartyMenu"
|
||||
accesskey="&acceptThirdParty3.pre.accesskey;">&acceptThirdParty3.pre.label;</label>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<menulist id="acceptThirdPartyMenu" preference="network.cookie.cookieBehavior"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptThirdPartyCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptThirdPartyCookies();">
|
||||
<menupopup>
|
||||
<menuitem label="&acceptThirdParty.always.label;" value="always"/>
|
||||
<menuitem label="&acceptThirdParty.visited.label;" value="visited"/>
|
||||
<menuitem label="&acceptThirdParty.never.label;" value="never"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<radio label="&blockCookies.label;"
|
||||
value="2"
|
||||
accesskey="&blockCookies.accesskey;"
|
||||
flex="1" />
|
||||
</hbox>
|
||||
<hbox id="keepRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="keepUntil"
|
||||
control="keepCookiesUntil"
|
||||
accesskey="&keepUntil2.accesskey;">&keepUntil2.label;</label>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<menulist id="keepCookiesUntil"
|
||||
preference="network.cookie.lifetimePolicy">
|
||||
<menupopup>
|
||||
<menuitem label="&expire.label;" value="0"/>
|
||||
<menuitem label="&close.label;" value="2"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<hbox id="acceptThirdPartyRow"
|
||||
class="indent"
|
||||
align="center">
|
||||
<label id="acceptThirdPartyLabel" control="acceptThirdPartyMenu"
|
||||
accesskey="&acceptThirdParty3.pre.accesskey;">&acceptThirdParty3.pre.label;</label>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<menulist id="acceptThirdPartyMenu" preference="network.cookie.cookieBehavior"
|
||||
onsyncfrompreference="return gPrivacyPane.readAcceptThirdPartyCookies();"
|
||||
onsynctopreference="return gPrivacyPane.writeAcceptThirdPartyCookies();">
|
||||
<menupopup>
|
||||
<menuitem label="&acceptThirdParty.always.label;" value="always"/>
|
||||
<menuitem label="&acceptThirdParty.visited.label;" value="visited"/>
|
||||
<menuitem label="&acceptThirdParty.never.label;" value="never"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<radio label="&blockCookies.label;"
|
||||
value="2"
|
||||
accesskey="&blockCookies.accesskey;"
|
||||
flex="1" />
|
||||
</radiogroup>
|
||||
</radiogroup>
|
||||
</vbox>
|
||||
<vbox align="end">
|
||||
<button id="clearSiteDataButton"
|
||||
class="accessory-button"
|
||||
icon="clear"
|
||||
label="&clearSiteData1.label;" accesskey="&clearSiteData1.accesskey;"/>
|
||||
<button id="siteDataSettings"
|
||||
class="accessory-button"
|
||||
label="&siteDataSettings.label;"
|
||||
accesskey="&siteDataSettings.accesskey;"
|
||||
searchkeywords="&window.title;
|
||||
&hostCol.label;
|
||||
&statusCol.label;
|
||||
&usageCol.label;"/>
|
||||
<button id="cookieExceptions"
|
||||
class="accessory-button"
|
||||
label="&cookieExceptions.label;" accesskey="&cookieExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.cookie_exceptions"
|
||||
searchkeywords="&address2.label;
|
||||
&block.label;
|
||||
&session.label;
|
||||
&allow.label;
|
||||
&removepermission2.label;
|
||||
&removeallpermissions2.label;
|
||||
&button.cancel.label;
|
||||
&button.ok.label;"/>
|
||||
<vbox>
|
||||
<!-- Please don't remove the wrapping hbox/vbox/box for these elements. It's used to properly compute the search tooltip position. -->
|
||||
<hbox>
|
||||
<button id="clearSiteDataButton"
|
||||
class="accessory-button"
|
||||
icon="clear"
|
||||
searchkeywords="&clearSiteData.label;
|
||||
&clearCache.label;"
|
||||
label="&clearSiteData1.label;" accesskey="&clearSiteData1.accesskey;"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<button id="siteDataSettings"
|
||||
class="accessory-button"
|
||||
label="&siteDataSettings.label;"
|
||||
accesskey="&siteDataSettings.accesskey;"
|
||||
searchkeywords="&window1.title;
|
||||
&hostCol.label;
|
||||
&cookiesCol.label;
|
||||
&usageCol.label;"/>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<button id="cookieExceptions"
|
||||
class="accessory-button"
|
||||
label="&cookieExceptions.label;" accesskey="&cookieExceptions.accesskey;"
|
||||
preference="pref.privacy.disable_button.cookie_exceptions"
|
||||
searchkeywords="&address2.label;
|
||||
&block.label;
|
||||
&session.label;
|
||||
&allow.label;
|
||||
&removepermission2.label;
|
||||
&removeallpermissions2.label;
|
||||
&button.cancel.label;
|
||||
&button.ok.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
|
|
@ -32,6 +32,7 @@ skip-if = !updater
|
|||
[browser_search_subdialogs_within_preferences_6.js]
|
||||
[browser_search_subdialogs_within_preferences_7.js]
|
||||
[browser_search_subdialogs_within_preferences_8.js]
|
||||
[browser_search_subdialogs_within_preferences_site_data.js]
|
||||
[browser_bug795764_cachedisabled.js]
|
||||
[browser_bug1018066_resetScrollPosition.js]
|
||||
[browser_bug1020245_openPreferences_to_paneContent.js]
|
||||
|
|
|
@ -30,11 +30,3 @@ add_task(async function() {
|
|||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for searching for the "Settings - Site Data" subdialog.
|
||||
*/
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
await evaluateSearchResults("store site data on your computer", "siteDataGroup");
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* This file contains tests for the Preferences search bar.
|
||||
*/
|
||||
|
||||
// Enabling Searching functionatily. Will display search bar form this testcase forward.
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [["browser.preferences.search", true]]});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for searching for the "Settings - Site Data" subdialog.
|
||||
*/
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
await evaluateSearchResults("cookies", ["siteDataGroup", "historyGroup"]);
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
await evaluateSearchResults("site data", ["siteDataGroup", "historyGroup"]);
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
await evaluateSearchResults("cache", ["siteDataGroup", "historyGroup"]);
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
|
||||
await evaluateSearchResults("third-party", "siteDataGroup");
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
|
@ -90,7 +90,7 @@ add_task(async function() {
|
|||
.then(usage => {
|
||||
actual = totalSiteDataSizeLabel.textContent;
|
||||
expected = prefStrBundle.getFormattedString(
|
||||
"totalSiteDataSize1", DownloadUtils.convertByteUnits(usage + cacheSize));
|
||||
"totalSiteDataSize2", DownloadUtils.convertByteUnits(usage + cacheSize));
|
||||
is(actual, expected, "Should show the right total site data size");
|
||||
});
|
||||
|
||||
|
@ -109,7 +109,7 @@ add_task(async function() {
|
|||
.then(usage => {
|
||||
actual = totalSiteDataSizeLabel.textContent;
|
||||
expected = prefStrBundle.getFormattedString(
|
||||
"totalSiteDataSize1", DownloadUtils.convertByteUnits(usage + cacheSize));
|
||||
"totalSiteDataSize2", DownloadUtils.convertByteUnits(usage + cacheSize));
|
||||
is(actual, expected, "Should show the right total site data size");
|
||||
});
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ let gSiteDataSettings = {
|
|||
|
||||
let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
|
||||
let settingsDescription = document.getElementById("settingsDescription");
|
||||
settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings2.description", [brandShortName]);
|
||||
settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings3.description", [brandShortName]);
|
||||
|
||||
setEventListener("sitesList", "select", this.onSelect);
|
||||
setEventListener("hostCol", "click", this.onClickTreeCol);
|
||||
|
|
|
@ -29,7 +29,8 @@ add_UITour_task(async function test_highlight_library_and_show_library_subview()
|
|||
libraryBtn.dispatchEvent(new Event("command"));
|
||||
await highlightHiddenPromise;
|
||||
await ViewShownPromise;
|
||||
is(PanelUI.multiView.current.id, "appMenu-libraryView", "Should show the library subview");
|
||||
let libView = document.getElementById("appMenu-libraryView");
|
||||
ok(PanelView.forNode(libView).active, "Should show the library subview");
|
||||
is(appMenu.state, "open", "Should still open the app menu for the library subview");
|
||||
|
||||
// Clean up
|
||||
|
|
|
@ -22,8 +22,8 @@ acceptVeryLargeMinimumFont=Keep my changes anyway
|
|||
|
||||
trackingprotectionpermissionstext2=You have disabled Tracking Protection on these websites.
|
||||
trackingprotectionpermissionstitle=Exceptions - Tracking Protection
|
||||
cookiepermissionstext=You can specify which websites are always or never allowed to use cookies. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
|
||||
cookiepermissionstitle=Exceptions - Cookies
|
||||
cookiepermissionstext1=You can specify which websites are always or never allowed to use cookies and site data. Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
|
||||
cookiepermissionstitle1=Exceptions - Cookies and Site Data
|
||||
addonspermissionstext=You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
|
||||
addons_permissions_title2=Allowed Websites - Add-ons Installation
|
||||
popuppermissionstext=You can specify which websites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
|
||||
|
@ -166,19 +166,19 @@ removeSelectedCookies.accesskey=R
|
|||
|
||||
defaultUserContextLabel=None
|
||||
|
||||
# LOCALIZATION NOTE (totalSiteDataSize1, siteUsage, siteUsagePersistent):
|
||||
# LOCALIZATION NOTE (totalSiteDataSize2, siteUsage, siteUsagePersistent):
|
||||
# This is the total usage of site data, where we insert storage size and unit.
|
||||
# e.g., "The total usage is currently 200 MB"
|
||||
# %1$S = size
|
||||
# %2$S = unit (MB, KB, etc.)
|
||||
totalSiteDataSize1=Your stored site data and cache are currently using %1$S %2$S of disk space
|
||||
totalSiteDataSize2=Your stored cookies, site data and cache are currently using %1$S %2$S of disk space.
|
||||
siteUsage=%1$S %2$S
|
||||
siteUsagePersistent=%1$S %2$S (Persistent)
|
||||
loadingSiteDataSize1=Calculating site data and cache size…
|
||||
|
||||
acceptRemove=Remove
|
||||
# LOCALIZATION NOTE (siteDataSettings2.description): %S = brandShortName
|
||||
siteDataSettings2.description=The following websites store site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
|
||||
# LOCALIZATION NOTE (siteDataSettings3.description): %S = brandShortName
|
||||
siteDataSettings3.description=The following websites store cookies and site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
|
||||
# LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
|
||||
# removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
|
||||
# never displayed together and can share the same accesskey.
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
|
||||
<!ENTITY suggestionSettings2.label "Change preferences for search engine suggestions">
|
||||
|
||||
<!ENTITY acceptCookies3.label "Accept cookies and site data from websites">
|
||||
<!ENTITY acceptCookies3.accesskey "A">
|
||||
<!ENTITY acceptCookies4.label "Accept cookies and site data from websites (recommended)">
|
||||
<!ENTITY acceptCookies4.accesskey "A">
|
||||
|
||||
<!ENTITY blockCookies.label "Block cookies and site data (may cause websites to break)">
|
||||
<!ENTITY blockCookies.accesskey "B">
|
||||
|
@ -66,7 +66,7 @@
|
|||
<!ENTITY historyHeader.custom.label "Use custom settings for history">
|
||||
<!ENTITY historyHeader.post.label "">
|
||||
|
||||
<!ENTITY rememberDescription.label "&brandShortName; will remember your browsing, download, form and search history, and keep cookies from websites you visit.">
|
||||
<!ENTITY rememberDescription1.label "&brandShortName; will remember your browsing, download, form and search history.">
|
||||
|
||||
<!ENTITY dontrememberDescription.label "&brandShortName; will use the same settings as private browsing, and will not remember any history as you browse the Web.">
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
<!ENTITY window1.title "Settings - Cookies and Site Data">
|
||||
<!ENTITY hostCol.label "Site">
|
||||
<!ENTITY statusCol.label "Status">
|
||||
<!ENTITY cookiesCol.label "Cookies">
|
||||
<!ENTITY usageCol.label "Storage">
|
||||
<!ENTITY lastAccessedCol.label "Last Used">
|
||||
|
|
|
@ -85,6 +85,12 @@ button > hbox > label {
|
|||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
/* Add a bit of space to the end of descriptions to
|
||||
* leave margin with e.g. additional buttons on the side. */
|
||||
.description-with-side-element {
|
||||
margin-inline-end: 10px !important;
|
||||
}
|
||||
|
||||
.learnMore {
|
||||
margin-inline-start: 0px;
|
||||
font-weight: normal;
|
||||
|
@ -383,6 +389,10 @@ button > hbox > label {
|
|||
margin-top: 4px;
|
||||
}
|
||||
|
||||
#acceptCookies {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
/* Collapse the non-active vboxes in decks to use only the height the
|
||||
active vbox needs */
|
||||
#historyPane:not([selectedIndex="1"]) > #historyDontRememberPane,
|
||||
|
|
|
@ -339,7 +339,7 @@ sysinstall_cmd = install_cmd
|
|||
# overridden by the command line. (Besides, AB_CD is prettier).
|
||||
AB_CD = $(MOZ_UI_LOCALE)
|
||||
|
||||
include $(topsrcdir)/config/AB_rCD.mk
|
||||
include $(MOZILLA_DIR)/config/AB_rCD.mk
|
||||
|
||||
# Many locales directories want this definition.
|
||||
ACDEFINES += -DAB_CD=$(AB_CD)
|
||||
|
|
|
@ -9643,14 +9643,16 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
|||
// outside of Gecko.
|
||||
const int where = (aWindowTarget.IsEmpty() || targetDocShell)
|
||||
? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
|
||||
: nsIBrowserDOMWindow::OPEN_NEW;
|
||||
: nsIBrowserDOMWindow::OPEN_NEWWINDOW;
|
||||
|
||||
if (where == nsIBrowserDOMWindow::OPEN_NEW && isDocumentAuxSandboxed) {
|
||||
if (where == nsIBrowserDOMWindow::OPEN_NEWWINDOW && isDocumentAuxSandboxed) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(mLoadURIDelegate->LoadURI(aURI, where, aFlags,
|
||||
aTriggeringPrincipal))) {
|
||||
bool loadURIHandled = false;
|
||||
rv = mLoadURIDelegate->LoadURI(aURI, where, aFlags, aTriggeringPrincipal,
|
||||
&loadURIHandled);
|
||||
if (NS_SUCCEEDED(rv) && loadURIHandled) {
|
||||
// The request has been handled, nothing to do here.
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -16,5 +16,6 @@ support-files =
|
|||
[chrome/test_cssanimation_missing_keyframes.html]
|
||||
[chrome/test_generated_content_getAnimations.html]
|
||||
[chrome/test_running_on_compositor.html]
|
||||
skip-if = os == 'android' # bug 1442150
|
||||
[chrome/test_simulate_compute_values_failure.html]
|
||||
skip-if = !debug
|
||||
|
|
|
@ -516,7 +516,7 @@ nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
|||
}
|
||||
|
||||
if (!aDontSerializeRoot) {
|
||||
rv = SerializeNodeEnd(node, aStr);
|
||||
rv = SerializeNodeEnd(maybeFixedNode, aStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -867,6 +867,10 @@ HTMLFormElement::DoSecureToInsecureSubmitCheck(nsIURI* aActionURL,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(aActionURL)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> window = OwnerDoc()->GetWindow();
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -688,7 +688,8 @@ skip-if = android_version == '15' || android_version == '17' || android_version
|
|||
[test_autoplay_policy.html]
|
||||
skip-if = android_version == '23' # bug 1424903
|
||||
[test_autoplay_policy_activation.html]
|
||||
skip-if = android_version == '23' # bug 1424903
|
||||
#skip-if = android_version == '23' # bug 1424903
|
||||
skip-if = true # bug 1441424 - temporarily disabled to land bug 1193394
|
||||
[test_buffered.html]
|
||||
skip-if = android_version == '15' || android_version == '22' # bug 1308388, android(bug 1232305)
|
||||
[test_bug448534.html]
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsIImageLoadingContent.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsContentSecurityManager,
|
||||
|
@ -879,6 +880,12 @@ nsContentSecurityManager::IsOriginPotentiallyTrustworthy(nsIPrincipal* aPrincipa
|
|||
}
|
||||
}
|
||||
}
|
||||
// Maybe we have a .onion URL. Treat it as whitelisted as well if
|
||||
// `dom.securecontext.whitelist_onions` is `true`.
|
||||
if (nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(uri)) {
|
||||
*aIsTrustWorthy = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -395,6 +395,28 @@ nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackURL(nsIURI* aURL) {
|
|||
return host.EqualsLiteral("127.0.0.1") || host.EqualsLiteral("::1");
|
||||
}
|
||||
|
||||
/* Maybe we have a .onion URL. Treat it as whitelisted as well if
|
||||
* `dom.securecontext.whitelist_onions` is `true`.
|
||||
*/
|
||||
bool
|
||||
nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(nsIURI* aURL) {
|
||||
static bool sInited = false;
|
||||
static bool sWhiteListOnions = false;
|
||||
if (!sInited) {
|
||||
Preferences::AddBoolVarCache(&sWhiteListOnions,
|
||||
"dom.securecontext.whitelist_onions");
|
||||
sInited = true;
|
||||
}
|
||||
if (!sWhiteListOnions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString host;
|
||||
nsresult rv = aURL->GetHost(host);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
return StringEndsWith(host, NS_LITERAL_CSTRING(".onion"));
|
||||
}
|
||||
|
||||
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
|
||||
* logic. Called from non-static ShouldLoad().
|
||||
*/
|
||||
|
@ -725,6 +747,13 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// .onion URLs are encrypted and authenticated. Don't treat them as mixed
|
||||
// content if potentially trustworthy (i.e. whitelisted).
|
||||
if (isHttpScheme && IsPotentiallyTrustworthyOnion(innerContentLocation)) {
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The page might have set the CSP directive 'upgrade-insecure-requests'. In such
|
||||
// a case allow the http: load to succeed with the promise that the channel will
|
||||
// get upgraded to https before fetching any data from the netwerk.
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
// See:
|
||||
// https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy
|
||||
static bool IsPotentiallyTrustworthyLoopbackURL(nsIURI* aURL);
|
||||
static bool IsPotentiallyTrustworthyOnion(nsIURI* aURL);
|
||||
|
||||
/* Static version of ShouldLoad() that contains all the Mixed Content Blocker
|
||||
* logic. Called from non-static ShouldLoad().
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
file_contentserver.sjs
|
||||
file_about_newtab.html
|
||||
file_about_newtab_bad.html
|
||||
file_about_newtab_bad_csp.html
|
||||
file_about_newtab_bad_csp_signature
|
||||
file_about_newtab_good_signature
|
||||
file_about_newtab_bad_signature
|
||||
file_about_newtab_broken_signature
|
||||
file_about_newtab_sri.html
|
||||
file_about_newtab_sri_signature
|
||||
goodChain.pem
|
||||
head.js
|
||||
script.js
|
||||
style.css
|
||||
|
||||
[browser_verify_content_about_newtab.js]
|
||||
[browser_verify_content_about_newtab2.js]
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
const TESTS = [
|
||||
// { newtab (aboutURI) or regular load (url) : url,
|
||||
// testStrings : expected strings in the loaded page }
|
||||
{ "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "url" : URI_BAD_FILE_CACHED, "testStrings" : [BAD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_BAD_FILE_CACHED, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_SRI, "testStrings" : [
|
||||
STYLESHEET_WITHOUT_SRI_BLOCKED,
|
||||
STYLESHEET_WITH_SRI_LOADED,
|
||||
SCRIPT_WITHOUT_SRI_BLOCKED,
|
||||
SCRIPT_WITH_SRI_LOADED,
|
||||
]},
|
||||
{ "aboutURI" : URI_BAD_CSP, "testStrings" : [CSP_TEST_SUCCESS_STRING] },
|
||||
{ "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] },
|
||||
];
|
||||
|
||||
add_task(runTests);
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
const TESTS = [
|
||||
// { newtab (aboutURI) or regular load (url) : url,
|
||||
// testStrings : expected strings in the loaded page }
|
||||
{ "aboutURI" : URI_GOOD, "testStrings" : [GOOD_ABOUT_STRING] },
|
||||
{ "aboutURI" : URI_ERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_KEYERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_SIGERROR_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_NO_HEADER, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_SIG, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BROKEN_SIG, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_X5U, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_HTTP_X5U, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_FILE, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "aboutURI" : URI_BAD_ALL, "testStrings" : [ABOUT_BLANK] },
|
||||
{ "url" : URI_CLEANUP, "testStrings" : [CLEANUP_DONE] },
|
||||
];
|
||||
|
||||
add_task(runTests);
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1226928 -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testpage for bug 1226928</title>
|
||||
</head>
|
||||
<body>
|
||||
Just a fully good testpage for Bug 1226928<br/>
|
||||
</body>
|
||||
</html>
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1226928 -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testpage for bug 1226928</title>
|
||||
</head>
|
||||
<body>
|
||||
Just a bad testpage for Bug 1226928<br/>
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testpage for CSP violation (inline script)</title>
|
||||
</head>
|
||||
<body>
|
||||
CSP violation test succeeded.
|
||||
<script>
|
||||
// This inline script would override the success string if loaded.
|
||||
document.body.innerHTML = "CSP violation test failed.";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
oiypz3lb-IyJsmKNsnlp2zDrqncste8yONn9WUE6ksgJWMhSEQ9lp8vRqN0W3JPwJb6uSk16RI-tDv7uy0jxon5jL1BZpqlqIpvimg7FCQEedMKoHZwtE9an-e95sOTd
|
|
@ -1 +0,0 @@
|
|||
KirX94omQL7lKfWGhc777t8U29enDg0O0UcJLH3PRXcvWGO8KA6mmLS3yNCFnGiTjP3vNnVtm-sUkXr4ix8WTkKABkU4fEAi77sNOkLCKw40M9sDJOesmYInS_J2AuXX
|
|
@ -1 +0,0 @@
|
|||
MGUCMFwSs3o95ukwBWXN1WbLgnpJ_uHWFiQROPm9zjrSqzlfiSMyLwJwIZzldWo_pBJtOwIxAJIfhXIiMVfl5NkFEJUUMxzu6FuxOJl5DCpG2wHLy9AhayLUzm4X4SpwZ6QBPapdTg
|
|
@ -1 +0,0 @@
|
|||
HUndgHvxHNMiAe1SXoeyOOraUJCdxHqWkAYTu0Cq1KpAHcWZEVelNTvyXGbTLWj8btsmqNLAm08UlyK43q_2oO9DQfez3Fo8DhsKvm7TqgSXCkhUoxsYNanxWXhqw-Jw
|
|
@ -1,36 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=1235572 -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testpage for bug 1235572</title>
|
||||
<script>
|
||||
function loaded(resource) {
|
||||
document.getElementById("result").innerHTML += resource + " loaded\n";
|
||||
}
|
||||
function blocked(resource) {
|
||||
document.getElementById("result").innerHTML += resource + " blocked\n";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Testing script loading without SRI for Bug 1235572<br/>
|
||||
<div id="result"></div>
|
||||
|
||||
<!-- use css1 and css2 to make urls different to avoid the resource being cached-->
|
||||
<link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css1"
|
||||
onload="loaded('Stylesheet without SRI')"
|
||||
onerror="blocked('Stylesheet without SRI')">
|
||||
<link rel="stylesheet" href="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=css2"
|
||||
integrity="sha384-/6Tvxh7SX39y62qePcvYoi5Vrf0lK8Ix3wJFLCYKI5KNJ5wIlCR8UsFC1OXwmwgd"
|
||||
onload="loaded('Stylesheet with SRI')"
|
||||
onerror="blocked('Stylesheet with SRI')">
|
||||
<script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
|
||||
onload="loaded('Script without SRI')"
|
||||
onerror="blocked('Script without SRI')"></script>
|
||||
<script src="https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?resource=script"
|
||||
integrity="sha384-zDCkvKOHXk8mM6Nk07oOGXGME17PA4+ydFw+hq0r9kgF6ZDYFWK3fLGPEy7FoOAo"
|
||||
onload="loaded('Script with SRI')"
|
||||
onerror="blocked('Script with SRI')"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
yoIyAYiiEzdP1zpkRy3KaqdsjUy62Notku89cytwVwcH0x6fKsMCdM-df1wbk9N28CSTaIOW5kcSenFy5K3nU-zPIoqZDjQo6aSjF8hF6lrw1a1xbhfl9K3g4YJsuWsO
|
|
@ -1,260 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
// sjs for remote about:newtab (bug 1226928)
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.importGlobalProperties(["URLSearchParams"]);
|
||||
|
||||
const path = "browser/dom/security/test/contentverifier/";
|
||||
|
||||
const goodFileName = "file_about_newtab.html";
|
||||
const goodFileBase = path + goodFileName;
|
||||
const goodFile = FileUtils.getDir("TmpD", [], true);
|
||||
goodFile.append(goodFileName);
|
||||
const goodSignature = path + "file_about_newtab_good_signature";
|
||||
const goodX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
|
||||
|
||||
const scriptFileName = "script.js";
|
||||
const cssFileName = "style.css";
|
||||
const badFile = path + "file_about_newtab_bad.html";
|
||||
const brokenSignature = path + "file_about_newtab_broken_signature";
|
||||
const badSignature = path + "file_about_newtab_bad_signature";
|
||||
const badX5UString = "\"https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=bad\"";
|
||||
const httpX5UString = "\"http://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?x5u=default\"";
|
||||
|
||||
const sriFile = path + "file_about_newtab_sri.html";
|
||||
const sriSignature = path + "file_about_newtab_sri_signature";
|
||||
|
||||
const badCspFile = path + "file_about_newtab_bad_csp.html";
|
||||
const badCspSignature = path + "file_about_newtab_bad_csp_signature";
|
||||
|
||||
// This cert chain is copied from
|
||||
// security/manager/ssl/tests/unit/test_content_signing/
|
||||
// using the certificates
|
||||
// * content_signing_remote_newtab_ee.pem
|
||||
// * content_signing_int.pem
|
||||
// * content_signing_root.pem
|
||||
const goodCertChainPath = path + "goodChain.pem";
|
||||
|
||||
const tempFileNames = [goodFileName, scriptFileName, cssFileName];
|
||||
|
||||
// we copy the file to serve as newtab to a temp directory because
|
||||
// we modify it during tests.
|
||||
setupTestFiles();
|
||||
|
||||
function setupTestFiles() {
|
||||
for (let fileName of tempFileNames) {
|
||||
let tempFile = FileUtils.getDir("TmpD", [], true);
|
||||
tempFile.append(fileName);
|
||||
if (!tempFile.exists()) {
|
||||
let fileIn = getFileName(path + fileName, "CurWorkD");
|
||||
fileIn.copyTo(FileUtils.getDir("TmpD", [], true), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getFileName(filePath, dir) {
|
||||
// Since it's relative to the cwd of the test runner, we start there and
|
||||
// append to get to the actual path of the file.
|
||||
let testFile =
|
||||
Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get(dir, Components.interfaces.nsIFile);
|
||||
let dirs = filePath.split("/");
|
||||
for (let i = 0; i < dirs.length; i++) {
|
||||
testFile.append(dirs[i]);
|
||||
}
|
||||
return testFile;
|
||||
}
|
||||
|
||||
function loadFile(file) {
|
||||
// Load a file to return it.
|
||||
let testFileStream =
|
||||
Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
testFileStream.init(file, -1, 0, 0);
|
||||
return NetUtil.readInputStreamToString(testFileStream,
|
||||
testFileStream.available());
|
||||
}
|
||||
|
||||
function appendToFile(aFile, content) {
|
||||
try {
|
||||
let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_APPEND |
|
||||
FileUtils.MODE_WRONLY);
|
||||
file.write(content, content.length);
|
||||
file.close();
|
||||
} catch (e) {
|
||||
dump(">>> Error in appendToFile "+e);
|
||||
return "Error";
|
||||
}
|
||||
return "Done";
|
||||
}
|
||||
|
||||
function truncateFile(aFile, length) {
|
||||
let fileIn = loadFile(aFile);
|
||||
fileIn = fileIn.slice(0, -length);
|
||||
|
||||
try {
|
||||
let file = FileUtils.openFileOutputStream(aFile, FileUtils.MODE_WRONLY |
|
||||
FileUtils.MODE_TRUNCATE);
|
||||
file.write(fileIn, fileIn.length);
|
||||
file.close();
|
||||
} catch (e) {
|
||||
dump(">>> Error in truncateFile "+e);
|
||||
return "Error";
|
||||
}
|
||||
return "Done";
|
||||
}
|
||||
|
||||
function cleanupTestFiles() {
|
||||
for (let fileName of tempFileNames) {
|
||||
let tempFile = FileUtils.getDir("TmpD", [], true);
|
||||
tempFile.append(fileName);
|
||||
tempFile.remove(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handle requests of the following form:
|
||||
* sig=good&key=good&file=good&header=good&cached=no to serve pages with
|
||||
* content signatures
|
||||
*
|
||||
* it further handles invalidateFile=yep and validateFile=yep to change the
|
||||
* served file
|
||||
*/
|
||||
function handleRequest(request, response) {
|
||||
let params = new URLSearchParams(request.queryString);
|
||||
let x5uType = params.get("x5u");
|
||||
let signatureType = params.get("sig");
|
||||
let fileType = params.get("file");
|
||||
let headerType = params.get("header");
|
||||
let cached = params.get("cached");
|
||||
let invalidateFile = params.get("invalidateFile");
|
||||
let validateFile = params.get("validateFile");
|
||||
let resource = params.get("resource");
|
||||
let x5uParam = params.get("x5u");
|
||||
|
||||
if (params.get("cleanup")) {
|
||||
cleanupTestFiles();
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write("Done");
|
||||
return;
|
||||
}
|
||||
|
||||
if (resource) {
|
||||
if (resource == "script") {
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write(loadFile(getFileName(scriptFileName, "TmpD")));
|
||||
} else { // resource == "css1" || resource == "css2"
|
||||
response.setHeader("Content-Type", "text/css", false);
|
||||
response.write(loadFile(getFileName(cssFileName, "TmpD")));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if invalidateFile is set, this doesn't actually return a newtab page
|
||||
// but changes the served file to invalidate the signature
|
||||
// NOTE: make sure to make the file valid again afterwards!
|
||||
if (invalidateFile) {
|
||||
let r = "Done";
|
||||
for (let fileName of tempFileNames) {
|
||||
if (appendToFile(getFileName(fileName, "TmpD"), "!") != "Done") {
|
||||
r = "Error";
|
||||
}
|
||||
}
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(r);
|
||||
return;
|
||||
}
|
||||
|
||||
// if validateFile is set, this doesn't actually return a newtab page
|
||||
// but changes the served file to make the signature valid again
|
||||
if (validateFile) {
|
||||
let r = "Done";
|
||||
for (let fileName of tempFileNames) {
|
||||
if (truncateFile(getFileName(fileName, "TmpD"), 1) != "Done") {
|
||||
r = "Error";
|
||||
}
|
||||
}
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(r);
|
||||
return;
|
||||
}
|
||||
|
||||
// we have to return the certificate chain on request for the x5u parameter
|
||||
if (x5uParam && x5uParam == "default") {
|
||||
response.setHeader("Cache-Control", "max-age=216000", false);
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.write(loadFile(getFileName(goodCertChainPath, "CurWorkD")));
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid confusing cache behaviours
|
||||
if (!cached) {
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
} else {
|
||||
response.setHeader("Cache-Control", "max-age=3600", false);
|
||||
}
|
||||
|
||||
// send HTML to test allowed/blocked behaviours
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
|
||||
// set signature header and key for Content-Signature header
|
||||
/* By default a good content-signature header is returned. Any broken return
|
||||
* value has to be indicated in the url.
|
||||
*/
|
||||
let csHeader = "";
|
||||
let x5uString = goodX5UString;
|
||||
let signature = goodSignature;
|
||||
let file = goodFile;
|
||||
if (x5uType == "bad") {
|
||||
x5uString = badX5UString;
|
||||
} else if (x5uType == "http") {
|
||||
x5uString = httpX5UString;
|
||||
}
|
||||
if (signatureType == "bad") {
|
||||
signature = badSignature;
|
||||
} else if (signatureType == "broken") {
|
||||
signature = brokenSignature;
|
||||
} else if (signatureType == "sri") {
|
||||
signature = sriSignature;
|
||||
} else if (signatureType == "bad-csp") {
|
||||
signature = badCspSignature;
|
||||
}
|
||||
if (fileType == "bad") {
|
||||
file = getFileName(badFile, "CurWorkD");
|
||||
} else if (fileType == "sri") {
|
||||
file = getFileName(sriFile, "CurWorkD");
|
||||
} else if (fileType == "bad-csp") {
|
||||
file = getFileName(badCspFile, "CurWorkD");
|
||||
}
|
||||
|
||||
if (headerType == "good") {
|
||||
// a valid content-signature header
|
||||
csHeader = "x5u=" + x5uString + ";p384ecdsa=" +
|
||||
loadFile(getFileName(signature, "CurWorkD"));
|
||||
} else if (headerType == "error") {
|
||||
// this content-signature header is missing ; before p384ecdsa
|
||||
csHeader = "x5u=" + x5uString + "p384ecdsa=" +
|
||||
loadFile(getFileName(signature, "CurWorkD"));
|
||||
} else if (headerType == "errorInX5U") {
|
||||
// this content-signature header is missing the keyid directive
|
||||
csHeader = "x6u=" + x5uString + ";p384ecdsa=" +
|
||||
loadFile(getFileName(signature, "CurWorkD"));
|
||||
} else if (headerType == "errorInSignature") {
|
||||
// this content-signature header is missing the p384ecdsa directive
|
||||
csHeader = "x5u=" + x5uString + ";p385ecdsa=" +
|
||||
loadFile(getFileName(signature, "CurWorkD"));
|
||||
}
|
||||
|
||||
if (csHeader) {
|
||||
response.setHeader("Content-Signature", csHeader, false);
|
||||
}
|
||||
let result = loadFile(file);
|
||||
|
||||
response.write(result);
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICUzCCAT2gAwIBAgIUJ1BtYqWRwUsVaZCGPp9eTHIC04QwCwYJKoZIhvcNAQEL
|
||||
MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
|
||||
MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
|
||||
nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
|
||||
dKpuqc6jTjBMMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDUGA1UdEQQuMCyCKnJlbW90
|
||||
ZW5ld3RhYi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzALBgkqhkiG9w0B
|
||||
AQsDggEBALiLck6k50ok9ahVq45P3feY1PeUXcIYZkJd8aPDYM+0kfg5+JyJBykA
|
||||
mtHWPE1QQjs7VRMfaLfu04E4UJMI2V1AON1qtgR9BQLctW85KFACg2omfiCKwJh0
|
||||
5Q8cxBFx9BpNMayqLJwHttB6oluxZFTB8CL/hfpbYpHz1bMEDCVSRP588YBrc8mV
|
||||
OLqzQK+k3ewwGvfD6SvXmTny37MxqwxdTPFJNnpqzKAsQIvz8Skic9BkA1NFk0Oq
|
||||
lsKKoiibbOCmwS9XY/laAkBaC3winuhciYAC0ImAopZ4PBCU0AOHGrNbhZXWYQxt
|
||||
uHBj34FqvIRCqgM06JCEwN0ULgix4kI=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC0TCCAbugAwIBAgIUPcKbBQpKwTzrrlqzM+d3z5DWiNUwCwYJKoZIhvcNAQEL
|
||||
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
|
||||
MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
|
||||
nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
|
||||
wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
|
||||
4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
|
||||
yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
|
||||
j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
|
||||
BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADDPjITgz8joxLRW
|
||||
wpLxELKSgO/KQ6iAXztjMHq9ovT7Fy0fqBnQ1mMVFr+sBXLgtUCM45aip6PjhUXc
|
||||
zs5Dq5STg+kz7qtmAjEQvOPcyictbgdu/K7+uMhXQhlzhOgyW88Uk5vrAezNTc/e
|
||||
TvSmWp1FcgVAfaeMN/90nzD1KIHoUt7zqZIz9ub8jXPVzQNZq4vh33smZhmbdTdV
|
||||
DaHUyef5cR1VTEGB+L1qzUIQqpHmD4UkMNP1nYedWfauiQhRt6Ql3rJSCRuEvsOA
|
||||
iBTJlwai/EFwfyfHkOV2GNgv+A5wHHEjBtF5c4PCxQEL5Vw+mfZHLsDVqF3279ZY
|
||||
lQ6jQ9g=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICzTCCAbegAwIBAgIUKRLJoCmk0A6PHrNc8CxFn//4BYcwCwYJKoZIhvcNAQEL
|
||||
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
|
||||
MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
|
||||
Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
|
||||
7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
|
||||
qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
|
||||
HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
|
||||
uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyUwIzAMBgNVHRMEBTADAQH/MBMGA1Ud
|
||||
JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAABgMK6EyVIXTjD5qaxPO
|
||||
DWz6yREACmAQBcowKWvfhwgi27DPSXyFGDbzTPEo+7RrIcXJkVAhLouGT51fCwTZ
|
||||
zb6Sgf6ztX7VSppY9AT4utvlZKP1xQ5WhIYsMtdHCHLHIkRjeWyoBEfUx50UXNLK
|
||||
Snl+A02GKYWiX+TLLg2DPN2s7v/mm8NLMQNgUlL7KakB2FHFyPa8otPpL4llg7UJ
|
||||
iBTVQ0c3JoiVbwZaY1Z8QinfMXUrTK9egUC4BAcId1dE8glzA5RRlw1fTLWpGApt
|
||||
hUmbDnl9N2a9NhGX323ypNzIATexafipzWe7bc4u/+bFdrUqnKUoEka73pZBdHdA
|
||||
FQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* Test Content-Signature for remote about:newtab
|
||||
* - Bug 1226928 - allow about:newtab to load remote content
|
||||
*
|
||||
* This tests content-signature verification on remote about:newtab in the
|
||||
* following cases (see TESTS, all failed loads display about:blank fallback):
|
||||
* - good case (signature should verify and correct page is displayed)
|
||||
* - reload of newtab when the siganture was invalidated after the last correct
|
||||
* load
|
||||
* - malformed content-signature header
|
||||
* - malformed keyid directive
|
||||
* - malformed p384ecdsa directive
|
||||
* - wrong signature (this is not a siganture for the delivered document)
|
||||
* - invalid signature (this is not even a signature)
|
||||
* - loading a file that doesn't fit the key or signature
|
||||
* - cache poisoning (load a malicious remote page not in newtab, subsequent
|
||||
* newtab load has to load the fallback)
|
||||
*/
|
||||
|
||||
const ABOUT_NEWTAB_URI = "about:newtab";
|
||||
|
||||
const BASE = "https://example.com/browser/dom/security/test/contentverifier/file_contentserver.sjs?";
|
||||
const URI_GOOD = BASE + "sig=good&x5u=good&file=good&header=good";
|
||||
|
||||
const INVALIDATE_FILE = BASE + "invalidateFile=yep";
|
||||
const VALIDATE_FILE = BASE + "validateFile=yep";
|
||||
|
||||
const URI_HEADER_BASE = BASE + "sig=good&x5u=good&file=good&header=";
|
||||
const URI_ERROR_HEADER = URI_HEADER_BASE + "error";
|
||||
const URI_KEYERROR_HEADER = URI_HEADER_BASE + "errorInX5U";
|
||||
const URI_SIGERROR_HEADER = URI_HEADER_BASE + "errorInSignature";
|
||||
const URI_NO_HEADER = URI_HEADER_BASE + "noHeader";
|
||||
|
||||
const URI_BAD_SIG = BASE + "sig=bad&x5u=good&file=good&header=good";
|
||||
const URI_BROKEN_SIG = BASE + "sig=broken&x5u=good&file=good&header=good";
|
||||
const URI_BAD_X5U = BASE + "sig=good&x5u=bad&file=good&header=good";
|
||||
const URI_HTTP_X5U = BASE + "sig=good&x5u=http&file=good&header=good";
|
||||
const URI_BAD_FILE = BASE + "sig=good&x5u=good&file=bad&header=good";
|
||||
const URI_BAD_ALL = BASE + "sig=bad&x5u=bad&file=bad&header=bad";
|
||||
const URI_BAD_CSP = BASE + "sig=bad-csp&x5u=good&file=bad-csp&header=good";
|
||||
|
||||
const URI_BAD_FILE_CACHED = BASE + "sig=good&x5u=good&file=bad&header=good&cached=true";
|
||||
|
||||
const GOOD_ABOUT_STRING = "Just a fully good testpage for Bug 1226928";
|
||||
const BAD_ABOUT_STRING = "Just a bad testpage for Bug 1226928";
|
||||
const ABOUT_BLANK = "<head></head><body></body>";
|
||||
|
||||
const URI_CLEANUP = BASE + "cleanup=true";
|
||||
const CLEANUP_DONE = "Done";
|
||||
|
||||
const URI_SRI = BASE + "sig=sri&x5u=good&file=sri&header=good";
|
||||
const STYLESHEET_WITHOUT_SRI_BLOCKED = "Stylesheet without SRI blocked";
|
||||
const STYLESHEET_WITH_SRI_BLOCKED = "Stylesheet with SRI blocked";
|
||||
const STYLESHEET_WITH_SRI_LOADED = "Stylesheet with SRI loaded";
|
||||
const SCRIPT_WITHOUT_SRI_BLOCKED = "Script without SRI blocked";
|
||||
const SCRIPT_WITH_SRI_BLOCKED = "Script with SRI blocked";
|
||||
const SCRIPT_WITH_SRI_LOADED = "Script with SRI loaded";
|
||||
|
||||
const CSP_TEST_SUCCESS_STRING = "CSP violation test succeeded.";
|
||||
|
||||
// Needs to sync with pref "security.signed_content.CSP.default".
|
||||
const SIGNED_CONTENT_CSP = `{"csp-policies":[{"report-only":false,"script-src":["https://example.com","'unsafe-inline'"],"style-src":["https://example.com"]}]}`;
|
||||
|
||||
var browser = null;
|
||||
var aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
|
||||
.getService(Ci.nsIAboutNewTabService);
|
||||
|
||||
function pushPrefs(...aPrefs) {
|
||||
return SpecialPowers.pushPrefEnv({"set": aPrefs});
|
||||
}
|
||||
|
||||
/*
|
||||
* run tests with input from TESTS
|
||||
*/
|
||||
async function doTest(aExpectedStrings, reload, aUrl, aNewTabPref) {
|
||||
// set about:newtab location for this test if it's a newtab test
|
||||
if (aNewTabPref) {
|
||||
aboutNewTabService.newTabURL = aNewTabPref;
|
||||
}
|
||||
|
||||
// set prefs
|
||||
await pushPrefs(
|
||||
["browser.newtabpage.remote.content-signing-test", true],
|
||||
["browser.newtabpage.remote", true],
|
||||
["security.content.signature.root_hash",
|
||||
"CC:BE:04:87:74:B2:98:24:4A:C6:7A:71:BC:6F:DB:D6:C0:48:17:29:57:51:96:47:38:CC:24:C8:E4:F9:DD:CB"]);
|
||||
|
||||
if (aNewTabPref === URI_BAD_CSP) {
|
||||
// Use stricter CSP to test CSP violation.
|
||||
await pushPrefs(["security.signed_content.CSP.default", "script-src 'self'; style-src 'self'"]);
|
||||
} else {
|
||||
// Use weaker CSP to test normal content.
|
||||
await pushPrefs(["security.signed_content.CSP.default", "script-src 'self' 'unsafe-inline'; style-src 'self'"]);
|
||||
}
|
||||
|
||||
// start the test
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: aUrl,
|
||||
},
|
||||
async function(browser) {
|
||||
// check if everything's set correct for testing
|
||||
ok(Services.prefs.getBoolPref(
|
||||
"browser.newtabpage.remote.content-signing-test"),
|
||||
"sanity check: remote newtab signing test should be used");
|
||||
ok(Services.prefs.getBoolPref("browser.newtabpage.remote"),
|
||||
"sanity check: remote newtab should be used");
|
||||
// we only check this if we really do a newtab test
|
||||
if (aNewTabPref) {
|
||||
ok(aboutNewTabService.overridden,
|
||||
"sanity check: default URL for about:newtab should be overriden");
|
||||
is(aboutNewTabService.newTabURL, aNewTabPref,
|
||||
"sanity check: default URL for about:newtab should return the new URL");
|
||||
}
|
||||
|
||||
// Every valid remote newtab page must have built-in CSP.
|
||||
let shouldHaveCSP = ((aUrl === ABOUT_NEWTAB_URI) &&
|
||||
(aNewTabPref === URI_GOOD || aNewTabPref === URI_SRI));
|
||||
|
||||
if (shouldHaveCSP) {
|
||||
is(browser.contentDocument.nodePrincipal.cspJSON, SIGNED_CONTENT_CSP,
|
||||
"Valid remote newtab page must have built-in CSP.");
|
||||
}
|
||||
|
||||
await ContentTask.spawn(
|
||||
browser, aExpectedStrings, async function(aExpectedStrings) {
|
||||
for (let expectedString of aExpectedStrings) {
|
||||
ok(content.document.documentElement.innerHTML.includes(expectedString),
|
||||
"Expect the following value in the result\n" + expectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
}
|
||||
});
|
||||
|
||||
// for good test cases we check if a reload fails if the remote page
|
||||
// changed from valid to invalid in the meantime
|
||||
if (reload) {
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: INVALIDATE_FILE,
|
||||
},
|
||||
async function(browser2) {
|
||||
await ContentTask.spawn(browser2, null, async function() {
|
||||
ok(content.document.documentElement.innerHTML.includes("Done"),
|
||||
"Expect the following value in the result\n" + "Done" +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
browser.reload();
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
let expectedStrings = [ABOUT_BLANK];
|
||||
if (aNewTabPref == URI_SRI) {
|
||||
expectedStrings = [
|
||||
STYLESHEET_WITHOUT_SRI_BLOCKED,
|
||||
STYLESHEET_WITH_SRI_BLOCKED,
|
||||
SCRIPT_WITHOUT_SRI_BLOCKED,
|
||||
SCRIPT_WITH_SRI_BLOCKED
|
||||
];
|
||||
}
|
||||
await ContentTask.spawn(browser, expectedStrings,
|
||||
async function(expectedStrings) {
|
||||
for (let expectedString of expectedStrings) {
|
||||
ok(content.document.documentElement.innerHTML.includes(expectedString),
|
||||
"Expect the following value in the result\n" + expectedString +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: VALIDATE_FILE,
|
||||
},
|
||||
async function(browser2) {
|
||||
await ContentTask.spawn(browser2, null, async function() {
|
||||
ok(content.document.documentElement.innerHTML.includes("Done"),
|
||||
"Expect the following value in the result\n" + "Done" +
|
||||
"\nand got " + content.document.documentElement.innerHTML);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
// run tests from TESTS
|
||||
for (let i = 0; i < TESTS.length; i++) {
|
||||
let testCase = TESTS[i];
|
||||
let url = "", aNewTabPref = "";
|
||||
let reload = false;
|
||||
var aExpectedStrings = testCase.testStrings;
|
||||
if (testCase.aboutURI) {
|
||||
url = ABOUT_NEWTAB_URI;
|
||||
aNewTabPref = testCase.aboutURI;
|
||||
if (aNewTabPref == URI_GOOD || aNewTabPref == URI_SRI) {
|
||||
reload = true;
|
||||
}
|
||||
} else {
|
||||
url = testCase.url;
|
||||
}
|
||||
|
||||
await doTest(aExpectedStrings, reload, url, aNewTabPref);
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
var load=true;
|
Двоичные данные
dom/security/test/contentverifier/signature.der
Двоичные данные
dom/security/test/contentverifier/signature.der
Двоичный файл не отображается.
|
@ -1,9 +0,0 @@
|
|||
-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQAIg==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDAzX2TrGOr0WE92AbAl+nqnpqh25pKCLYNMTV2hJHztrkVPWOp8w0mh
|
||||
scIodK8RMpagBwYFK4EEACKhZANiAATiTcWYbt0Wg63dO7OXvpptNG0ryxv+v+Js
|
||||
JJ5Upr3pFus5fZyKxzP9NPzB+oFhL/xw3jMx7X5/vBGaQ2sJSiNlHVkqZgzYF6JQ
|
||||
4yUyiqTY7v67CyfUPA1BJg/nxOS9m3o=
|
||||
-----END EC PRIVATE KEY-----
|
|
@ -1,3 +0,0 @@
|
|||
#red-text {
|
||||
color: red;
|
||||
}
|
|
@ -34,10 +34,18 @@ add_task(async function test_isOriginPotentiallyTrustworthy() {
|
|||
["http://example.net/", true],
|
||||
["ws://example.org/", true],
|
||||
["chrome://example.net/content/messenger.xul", false],
|
||||
["http://1234567890abcdef.onion/", false],
|
||||
]) {
|
||||
let uri = NetUtil.newURI(uriSpec);
|
||||
let principal = gScriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
Assert.equal(gContentSecurityManager.isOriginPotentiallyTrustworthy(principal),
|
||||
expectedResult);
|
||||
}
|
||||
// And now let's test whether .onion sites are properly treated when
|
||||
// whitelisted, see bug 1382359.
|
||||
prefs.setBoolPref("dom.securecontext.whitelist_onions", true);
|
||||
let uri = NetUtil.newURI("http://1234567890abcdef.onion/");
|
||||
let principal = gScriptSecurityManager.createCodebasePrincipal(uri, {});
|
||||
Assert.equal(gContentSecurityManager.isOriginPotentiallyTrustworthy(principal),
|
||||
true);
|
||||
});
|
||||
|
|
|
@ -175,7 +175,7 @@ class StringifyContext
|
|||
static bool Str(JSContext* cx, const Value& v, StringifyContext* scx);
|
||||
|
||||
static bool
|
||||
WriteIndent(JSContext* cx, StringifyContext* scx, uint32_t limit)
|
||||
WriteIndent(StringifyContext* scx, uint32_t limit)
|
||||
{
|
||||
if (!scx->gap.empty()) {
|
||||
if (!scx->sb.append('\n'))
|
||||
|
@ -423,7 +423,7 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
|||
return false;
|
||||
wroteMember = true;
|
||||
|
||||
if (!WriteIndent(cx, scx, scx->depth))
|
||||
if (!WriteIndent(scx, scx->depth))
|
||||
return false;
|
||||
|
||||
JSString* s = IdToString(cx, id);
|
||||
|
@ -439,7 +439,7 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
|||
}
|
||||
}
|
||||
|
||||
if (wroteMember && !WriteIndent(cx, scx, scx->depth - 1))
|
||||
if (wroteMember && !WriteIndent(scx, scx->depth - 1))
|
||||
return false;
|
||||
|
||||
return scx->sb.append('}');
|
||||
|
@ -475,7 +475,7 @@ JA(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
|||
/* Steps 7-10. */
|
||||
if (length != 0) {
|
||||
/* Steps 4, 10b(i). */
|
||||
if (!WriteIndent(cx, scx, scx->depth))
|
||||
if (!WriteIndent(scx, scx->depth))
|
||||
return false;
|
||||
|
||||
/* Steps 7-10. */
|
||||
|
@ -527,13 +527,13 @@ JA(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
|||
if (i < length - 1) {
|
||||
if (!scx->sb.append(','))
|
||||
return false;
|
||||
if (!WriteIndent(cx, scx, scx->depth))
|
||||
if (!WriteIndent(scx, scx->depth))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 10(b)(iii). */
|
||||
if (!WriteIndent(cx, scx, scx->depth - 1))
|
||||
if (!WriteIndent(scx, scx->depth - 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -549,7 +549,7 @@ class js::OrderedHashTableRef : public gc::BufferableRef
|
|||
|
||||
template <typename ObjectT>
|
||||
inline static MOZ_MUST_USE bool
|
||||
WriteBarrierPostImpl(JSRuntime* rt, ObjectT* obj, const Value& keyValue)
|
||||
WriteBarrierPostImpl(ObjectT* obj, const Value& keyValue)
|
||||
{
|
||||
if (MOZ_LIKELY(!keyValue.isObject()))
|
||||
return true;
|
||||
|
@ -577,15 +577,15 @@ WriteBarrierPostImpl(JSRuntime* rt, ObjectT* obj, const Value& keyValue)
|
|||
}
|
||||
|
||||
inline static MOZ_MUST_USE bool
|
||||
WriteBarrierPost(JSRuntime* rt, MapObject* map, const Value& key)
|
||||
WriteBarrierPost(MapObject* map, const Value& key)
|
||||
{
|
||||
return WriteBarrierPostImpl(rt, map, key);
|
||||
return WriteBarrierPostImpl(map, key);
|
||||
}
|
||||
|
||||
inline static MOZ_MUST_USE bool
|
||||
WriteBarrierPost(JSRuntime* rt, SetObject* set, const Value& key)
|
||||
WriteBarrierPost(SetObject* set, const Value& key)
|
||||
{
|
||||
return WriteBarrierPostImpl(rt, set, key);
|
||||
return WriteBarrierPostImpl(set, key);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -618,7 +618,7 @@ MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v)
|
|||
if (!key.setValue(cx, k))
|
||||
return false;
|
||||
|
||||
if (!WriteBarrierPost(cx->runtime(), &obj->as<MapObject>(), key.value()) ||
|
||||
if (!WriteBarrierPost(&obj->as<MapObject>(), key.value()) ||
|
||||
!map->put(key, v))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -831,7 +831,7 @@ MapObject::set_impl(JSContext* cx, const CallArgs& args)
|
|||
|
||||
ValueMap& map = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
if (!WriteBarrierPost(cx->runtime(), &args.thisv().toObject().as<MapObject>(), key.value()) ||
|
||||
if (!WriteBarrierPost(&args.thisv().toObject().as<MapObject>(), key.value()) ||
|
||||
!map.put(key, args.get(1)))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -1302,7 +1302,7 @@ SetObject::add(JSContext* cx, HandleObject obj, HandleValue k)
|
|||
if (!key.setValue(cx, k))
|
||||
return false;
|
||||
|
||||
if (!WriteBarrierPost(cx->runtime(), &obj->as<SetObject>(), key.value()) ||
|
||||
if (!WriteBarrierPost(&obj->as<SetObject>(), key.value()) ||
|
||||
!set->put(key))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -1408,7 +1408,7 @@ SetObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
if (!key.setValue(cx, keyVal))
|
||||
return false;
|
||||
if (!WriteBarrierPost(cx->runtime(), obj, keyVal) ||
|
||||
if (!WriteBarrierPost(obj, keyVal) ||
|
||||
!set->put(key))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -1525,7 +1525,7 @@ SetObject::add_impl(JSContext* cx, const CallArgs& args)
|
|||
|
||||
ValueSet& set = extract(args);
|
||||
ARG0_KEY(cx, args, key);
|
||||
if (!WriteBarrierPost(cx->runtime(), &args.thisv().toObject().as<SetObject>(), key.value()) ||
|
||||
if (!WriteBarrierPost(&args.thisv().toObject().as<SetObject>(), key.value()) ||
|
||||
!set.put(key))
|
||||
{
|
||||
ReportOutOfMemory(cx);
|
||||
|
|
|
@ -2880,7 +2880,7 @@ AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenOb
|
|||
|
||||
// Steps 7-8.
|
||||
Rooted<AsyncGeneratorRequest*> request(
|
||||
cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
|
||||
cx, AsyncGeneratorObject::peekRequest(asyncGenObj));
|
||||
if (!request)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -550,8 +550,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
|
|||
return searchAndCache(bce, name);
|
||||
}
|
||||
|
||||
Maybe<NameLocation> locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
|
||||
EmitterScope* target);
|
||||
Maybe<NameLocation> locationBoundInScope(JSAtom* name, EmitterScope* target);
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -829,8 +828,7 @@ BytecodeEmitter::EmitterScope::searchAndCache(BytecodeEmitter* bce, JSAtom* name
|
|||
}
|
||||
|
||||
Maybe<NameLocation>
|
||||
BytecodeEmitter::EmitterScope::locationBoundInScope(BytecodeEmitter* bce, JSAtom* name,
|
||||
EmitterScope* target)
|
||||
BytecodeEmitter::EmitterScope::locationBoundInScope(JSAtom* name, EmitterScope* target)
|
||||
{
|
||||
// The target scope must be an intra-frame enclosing scope of this
|
||||
// one. Count the number of extra hops to reach it.
|
||||
|
@ -1669,7 +1667,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
}
|
||||
|
||||
private:
|
||||
bool emitCatchEnd(bool hasNext) {
|
||||
bool emitCatchEnd() {
|
||||
MOZ_ASSERT(state_ == Catch);
|
||||
|
||||
if (!controlInfo_)
|
||||
|
@ -1708,7 +1706,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(state_ == Catch);
|
||||
if (!emitCatchEnd(false))
|
||||
if (!emitCatchEnd())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1770,7 +1768,7 @@ class MOZ_STACK_CLASS TryEmitter
|
|||
bool emitEnd() {
|
||||
if (state_ == Catch) {
|
||||
MOZ_ASSERT(!hasFinally());
|
||||
if (!emitCatchEnd(false))
|
||||
if (!emitCatchEnd())
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(state_ == Finally);
|
||||
|
@ -2229,7 +2227,7 @@ BytecodeEmitter::lookupName(JSAtom* name)
|
|||
Maybe<NameLocation>
|
||||
BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
|
||||
{
|
||||
return innermostEmitterScope->locationBoundInScope(this, name, target);
|
||||
return innermostEmitterScope->locationBoundInScope(name, target);
|
||||
}
|
||||
|
||||
Maybe<NameLocation>
|
||||
|
@ -2238,7 +2236,7 @@ BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope*
|
|||
EmitterScope* funScope = source;
|
||||
while (!funScope->scope(this)->is<FunctionScope>())
|
||||
funScope = funScope->enclosingInFrame();
|
||||
return source->locationBoundInScope(this, name, funScope);
|
||||
return source->locationBoundInScope(name, funScope);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -8992,7 +8990,7 @@ BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitSelfHostedForceInterpreter(ParseNode* pn)
|
||||
BytecodeEmitter::emitSelfHostedForceInterpreter()
|
||||
{
|
||||
if (!emit1(JSOP_FORCEINTERPRETER))
|
||||
return false;
|
||||
|
@ -9125,7 +9123,7 @@ BytecodeEmitter::isRestParameter(ParseNode* pn)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitCallee(ParseNode* callee, ParseNode* call, bool spread, bool* callop)
|
||||
BytecodeEmitter::emitCallee(ParseNode* callee, ParseNode* call, bool* callop)
|
||||
{
|
||||
switch (callee->getKind()) {
|
||||
case ParseNodeKind::Name:
|
||||
|
@ -9210,7 +9208,7 @@ BytecodeEmitter::emitPipeline(ParseNode* pn)
|
|||
|
||||
do {
|
||||
bool callop = true;
|
||||
if (!emitCallee(callee, pn, false, &callop))
|
||||
if (!emitCallee(callee, pn, &callop))
|
||||
return false;
|
||||
|
||||
// Emit room for |this|
|
||||
|
@ -9274,7 +9272,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
|
|||
if (pn2->name() == cx->names().resumeGenerator)
|
||||
return emitSelfHostedResumeGenerator(pn);
|
||||
if (pn2->name() == cx->names().forceInterpreter)
|
||||
return emitSelfHostedForceInterpreter(pn);
|
||||
return emitSelfHostedForceInterpreter();
|
||||
if (pn2->name() == cx->names().allowContentIter)
|
||||
return emitSelfHostedAllowContentIter(pn);
|
||||
if (pn2->name() == cx->names().defineDataPropertyIntrinsic && pn->pn_count == 4)
|
||||
|
@ -9286,7 +9284,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
|
|||
// Fall through
|
||||
}
|
||||
|
||||
if (!emitCallee(pn2, pn, spread, &callop))
|
||||
if (!emitCallee(pn2, pn, &callop))
|
||||
return false;
|
||||
|
||||
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
|
||||
|
|
|
@ -794,7 +794,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
|
||||
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedForceInterpreter();
|
||||
MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitSelfHostedGetPropertySuper(ParseNode* pn);
|
||||
|
@ -836,7 +836,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
EmitElemOption opts = EmitElemOption::Get);
|
||||
MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
|
||||
|
||||
MOZ_MUST_USE bool emitCallee(ParseNode* callee, ParseNode* call, bool spread, bool* callop);
|
||||
MOZ_MUST_USE bool emitCallee(ParseNode* callee, ParseNode* call, bool* callop);
|
||||
|
||||
MOZ_MUST_USE bool emitPipeline(ParseNode* pn);
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind)
|
|||
MOZ_ASSERT(!cx->isNurseryAllocSuppressed());
|
||||
MOZ_ASSERT(!IsAtomsCompartment(cx->compartment()));
|
||||
|
||||
Cell* cell = cx->nursery().allocateString(cx, cx->zone(), thingSize, kind);
|
||||
Cell* cell = cx->nursery().allocateString(cx->zone(), thingSize, kind);
|
||||
if (cell)
|
||||
return static_cast<JSString*>(cell);
|
||||
|
||||
|
@ -152,7 +152,7 @@ GCRuntime::tryNewNurseryString(JSContext* cx, size_t thingSize, AllocKind kind)
|
|||
|
||||
// Exceeding gcMaxBytes while tenuring can disable the Nursery.
|
||||
if (cx->nursery().isEnabled()) {
|
||||
cell = cx->nursery().allocateString(cx, cx->zone(), thingSize, kind);
|
||||
cell = cx->nursery().allocateString(cx->zone(), thingSize, kind);
|
||||
MOZ_ASSERT(cell);
|
||||
return static_cast<JSString*>(cell);
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind, size_t thingSize)
|
|||
// Get the next available free list and allocate out of it. This may
|
||||
// acquire a new arena, which will lock the chunk list. If there are no
|
||||
// chunks available it may also allocate new memory directly.
|
||||
t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind, thingSize));
|
||||
t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
|
||||
|
||||
if (MOZ_UNLIKELY(!t && allowGC && !cx->helperThread())) {
|
||||
// We have no memory available for a new chunk; perform an
|
||||
|
@ -362,18 +362,18 @@ GCRuntime::startBackgroundAllocTaskIfIdle()
|
|||
}
|
||||
|
||||
/* static */ TenuredCell*
|
||||
GCRuntime::refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind, size_t thingSize)
|
||||
GCRuntime::refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind)
|
||||
{
|
||||
cx->arenas()->checkEmptyFreeList(thingKind);
|
||||
|
||||
if (!cx->helperThread())
|
||||
return refillFreeListFromActiveCooperatingThread(cx, thingKind, thingSize);
|
||||
return refillFreeListFromActiveCooperatingThread(cx, thingKind);
|
||||
|
||||
return refillFreeListFromHelperThread(cx, thingKind);
|
||||
}
|
||||
|
||||
/* static */ TenuredCell*
|
||||
GCRuntime::refillFreeListFromActiveCooperatingThread(JSContext* cx, AllocKind thingKind, size_t thingSize)
|
||||
GCRuntime::refillFreeListFromActiveCooperatingThread(JSContext* cx, AllocKind thingKind)
|
||||
{
|
||||
// It should not be possible to allocate on the active thread while we are
|
||||
// inside a GC.
|
||||
|
@ -690,7 +690,7 @@ Chunk::init(JSRuntime* rt)
|
|||
* Decommit the arenas. We do this after poisoning so that if the OS does
|
||||
* not have to recycle the pages, we still get the benefit of poisoning.
|
||||
*/
|
||||
decommitAllArenas(rt);
|
||||
decommitAllArenas();
|
||||
|
||||
/* Initialize the chunk info. */
|
||||
info.init();
|
||||
|
@ -699,7 +699,7 @@ Chunk::init(JSRuntime* rt)
|
|||
/* The rest of info fields are initialized in pickChunk. */
|
||||
}
|
||||
|
||||
void Chunk::decommitAllArenas(JSRuntime* rt)
|
||||
void Chunk::decommitAllArenas()
|
||||
{
|
||||
decommittedArenas.clear(true);
|
||||
MarkPagesUnused(&arenas[0], ArenasPerChunk * ArenaSize);
|
||||
|
|
|
@ -316,7 +316,7 @@ class ArenaLists
|
|||
js::SliceBudget& sliceBudget, gcstats::Statistics& stats);
|
||||
|
||||
void queueForegroundObjectsForSweep(FreeOp* fop);
|
||||
void queueForegroundThingsForSweep(FreeOp* fop);
|
||||
void queueForegroundThingsForSweep();
|
||||
|
||||
void releaseForegroundSweptEmptyArenas();
|
||||
|
||||
|
@ -334,8 +334,8 @@ class ArenaLists
|
|||
private:
|
||||
inline void queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase);
|
||||
inline void queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase);
|
||||
inline void queueForForegroundSweep(FreeOp* fop, AllocKind thingKind);
|
||||
inline void queueForBackgroundSweep(FreeOp* fop, AllocKind thingKind);
|
||||
inline void queueForForegroundSweep(AllocKind thingKind);
|
||||
inline void queueForBackgroundSweep(AllocKind thingKind);
|
||||
|
||||
TenuredCell* allocateFromArena(JS::Zone* zone, AllocKind thingKind,
|
||||
ShouldCheckThresholds checkThresholds);
|
||||
|
|
|
@ -784,7 +784,7 @@ GCRuntime::expireEmptyChunkPool(const AutoLockGC& lock)
|
|||
}
|
||||
|
||||
static void
|
||||
FreeChunkPool(JSRuntime* rt, ChunkPool& pool)
|
||||
FreeChunkPool(ChunkPool& pool)
|
||||
{
|
||||
for (ChunkPool::Iter iter(pool); !iter.done();) {
|
||||
Chunk* chunk = iter.get();
|
||||
|
@ -797,9 +797,9 @@ FreeChunkPool(JSRuntime* rt, ChunkPool& pool)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::freeEmptyChunks(JSRuntime* rt, const AutoLockGC& lock)
|
||||
GCRuntime::freeEmptyChunks(const AutoLockGC& lock)
|
||||
{
|
||||
FreeChunkPool(rt, emptyChunks(lock));
|
||||
FreeChunkPool(emptyChunks(lock));
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -818,7 +818,7 @@ GCRuntime::prepareToFreeChunk(ChunkInfo& info)
|
|||
}
|
||||
|
||||
inline void
|
||||
GCRuntime::updateOnArenaFree(const ChunkInfo& info)
|
||||
GCRuntime::updateOnArenaFree()
|
||||
{
|
||||
++numArenasFreeCommitted;
|
||||
}
|
||||
|
@ -831,11 +831,11 @@ Chunk::addArenaToFreeList(JSRuntime* rt, Arena* arena)
|
|||
info.freeArenasHead = arena;
|
||||
++info.numArenasFreeCommitted;
|
||||
++info.numArenasFree;
|
||||
rt->gc.updateOnArenaFree(info);
|
||||
rt->gc.updateOnArenaFree();
|
||||
}
|
||||
|
||||
void
|
||||
Chunk::addArenaToDecommittedList(JSRuntime* rt, const Arena* arena)
|
||||
Chunk::addArenaToDecommittedList(const Arena* arena)
|
||||
{
|
||||
++info.numArenasFree;
|
||||
decommittedArenas.set(Chunk::arenaIndex(arena->address()));
|
||||
|
@ -873,7 +873,7 @@ Chunk::decommitOneFreeArena(JSRuntime* rt, AutoLockGC& lock)
|
|||
}
|
||||
|
||||
if (ok)
|
||||
addArenaToDecommittedList(rt, arena);
|
||||
addArenaToDecommittedList(arena);
|
||||
else
|
||||
addArenaToFreeList(rt, arena);
|
||||
updateChunkListAfterFree(rt, lock);
|
||||
|
@ -917,7 +917,7 @@ Chunk::updateChunkListAfterFree(JSRuntime* rt, const AutoLockGC& lock)
|
|||
} else {
|
||||
MOZ_ASSERT(unused());
|
||||
rt->gc.availableChunks(lock).remove(this);
|
||||
decommitAllArenas(rt);
|
||||
decommitAllArenas();
|
||||
MOZ_ASSERT(info.numArenasFreeCommitted == 0);
|
||||
rt->gc.recycleChunk(this, lock);
|
||||
}
|
||||
|
@ -1276,9 +1276,9 @@ GCRuntime::finish()
|
|||
|
||||
groups().clear();
|
||||
|
||||
FreeChunkPool(rt, fullChunks_.ref());
|
||||
FreeChunkPool(rt, availableChunks_.ref());
|
||||
FreeChunkPool(rt, emptyChunks_.ref());
|
||||
FreeChunkPool(fullChunks_.ref());
|
||||
FreeChunkPool(availableChunks_.ref());
|
||||
FreeChunkPool(emptyChunks_.ref());
|
||||
|
||||
FinishTrace();
|
||||
|
||||
|
@ -2468,8 +2468,7 @@ Zone::prepareForCompacting()
|
|||
void
|
||||
GCRuntime::sweepTypesAfterCompacting(Zone* zone)
|
||||
{
|
||||
FreeOp* fop = rt->defaultFreeOp();
|
||||
zone->beginSweepTypes(fop, rt->gc.releaseObservedTypes && !zone->isPreservingCode());
|
||||
zone->beginSweepTypes(rt->gc.releaseObservedTypes && !zone->isPreservingCode());
|
||||
|
||||
AutoClearTypeInferenceStateOnOOM oom(zone);
|
||||
|
||||
|
@ -2493,17 +2492,17 @@ GCRuntime::sweepZoneAfterCompacting(Zone* zone)
|
|||
cache->sweep();
|
||||
|
||||
if (jit::JitZone* jitZone = zone->jitZone())
|
||||
jitZone->sweep(fop);
|
||||
jitZone->sweep();
|
||||
|
||||
for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
|
||||
c->objectGroups.sweep(fop);
|
||||
c->objectGroups.sweep();
|
||||
c->sweepRegExps();
|
||||
c->sweepSavedStacks();
|
||||
c->sweepVarNames();
|
||||
c->sweepGlobalObject();
|
||||
c->sweepSelfHostingScriptSource();
|
||||
c->sweepDebugEnvironments();
|
||||
c->sweepJitCompartment(fop);
|
||||
c->sweepJitCompartment();
|
||||
c->sweepNativeIterators();
|
||||
c->sweepTemplateObjects();
|
||||
}
|
||||
|
@ -2519,7 +2518,7 @@ UpdateCellPointers(MovingTracer* trc, T* cell)
|
|||
|
||||
template <typename T>
|
||||
static void
|
||||
UpdateArenaPointersTyped(MovingTracer* trc, Arena* arena, JS::TraceKind traceKind)
|
||||
UpdateArenaPointersTyped(MovingTracer* trc, Arena* arena)
|
||||
{
|
||||
for (ArenaCellIterUnderGC i(arena); !i.done(); i.next())
|
||||
UpdateCellPointers(trc, reinterpret_cast<T*>(i.getCell()));
|
||||
|
@ -2536,7 +2535,7 @@ UpdateArenaPointers(MovingTracer* trc, Arena* arena)
|
|||
switch (kind) {
|
||||
#define EXPAND_CASE(allocKind, traceKind, type, sizedType, bgFinal, nursery) \
|
||||
case AllocKind::allocKind: \
|
||||
UpdateArenaPointersTyped<type>(trc, arena, JS::TraceKind::traceKind); \
|
||||
UpdateArenaPointersTyped<type>(trc, arena); \
|
||||
return;
|
||||
FOR_EACH_ALLOCKIND(EXPAND_CASE)
|
||||
#undef EXPAND_CASE
|
||||
|
@ -2723,7 +2722,7 @@ GCRuntime::updateTypeDescrObjects(MovingTracer* trc, Zone* zone)
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount)
|
||||
GCRuntime::updateCellPointers(Zone* zone, AllocKinds kinds, size_t bgTaskCount)
|
||||
{
|
||||
AllocKinds fgKinds = bgTaskCount == 0 ? kinds : ForegroundUpdateKinds(kinds);
|
||||
AllocKinds bgKinds = kinds - fgKinds;
|
||||
|
@ -2815,13 +2814,13 @@ GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone)
|
|||
{
|
||||
size_t bgTaskCount = CellUpdateBackgroundTaskCount();
|
||||
|
||||
updateCellPointers(trc, zone, UpdatePhaseMisc, bgTaskCount);
|
||||
updateCellPointers(zone, UpdatePhaseMisc, bgTaskCount);
|
||||
|
||||
// Update TypeDescrs before all other objects as typed objects access these
|
||||
// objects when we trace them.
|
||||
updateTypeDescrObjects(trc, zone);
|
||||
|
||||
updateCellPointers(trc, zone, UpdatePhaseObjects, bgTaskCount);
|
||||
updateCellPointers(zone, UpdatePhaseObjects, bgTaskCount);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3048,11 +3047,11 @@ ArenaLists::queueForForegroundSweep(FreeOp* fop, const FinalizePhase& phase)
|
|||
{
|
||||
gcstats::AutoPhase ap(fop->runtime()->gc.stats(), phase.statsPhase);
|
||||
for (auto kind : phase.kinds)
|
||||
queueForForegroundSweep(fop, kind);
|
||||
queueForForegroundSweep(kind);
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::queueForForegroundSweep(FreeOp* fop, AllocKind thingKind)
|
||||
ArenaLists::queueForForegroundSweep(AllocKind thingKind)
|
||||
{
|
||||
MOZ_ASSERT(!IsBackgroundFinalized(thingKind));
|
||||
MOZ_ASSERT(backgroundFinalizeState(thingKind) == BFS_DONE);
|
||||
|
@ -3067,11 +3066,11 @@ ArenaLists::queueForBackgroundSweep(FreeOp* fop, const FinalizePhase& phase)
|
|||
{
|
||||
gcstats::AutoPhase ap(fop->runtime()->gc.stats(), phase.statsPhase);
|
||||
for (auto kind : phase.kinds)
|
||||
queueForBackgroundSweep(fop, kind);
|
||||
queueForBackgroundSweep(kind);
|
||||
}
|
||||
|
||||
inline void
|
||||
ArenaLists::queueForBackgroundSweep(FreeOp* fop, AllocKind thingKind)
|
||||
ArenaLists::queueForBackgroundSweep(AllocKind thingKind)
|
||||
{
|
||||
MOZ_ASSERT(IsBackgroundFinalized(thingKind));
|
||||
|
||||
|
@ -3143,7 +3142,7 @@ ArenaLists::releaseForegroundSweptEmptyArenas()
|
|||
}
|
||||
|
||||
void
|
||||
ArenaLists::queueForegroundThingsForSweep(FreeOp* fop)
|
||||
ArenaLists::queueForegroundThingsForSweep()
|
||||
{
|
||||
gcShapeArenasToUpdate = arenaListsToSweep(AllocKind::SHAPE);
|
||||
gcAccessorShapeArenasToUpdate = arenaListsToSweep(AllocKind::ACCESSOR_SHAPE);
|
||||
|
@ -3456,7 +3455,7 @@ js::gc::BackgroundDecommitTask::run()
|
|||
ChunkPool toFree = runtime()->gc.expireEmptyChunkPool(lock);
|
||||
if (toFree.count()) {
|
||||
AutoUnlockGC unlock(lock);
|
||||
FreeChunkPool(runtime(), toFree);
|
||||
FreeChunkPool(toFree);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3726,7 +3725,7 @@ UniqueIdGCPolicy::needsSweep(Cell** cell, uint64_t*)
|
|||
}
|
||||
|
||||
void
|
||||
JS::Zone::sweepUniqueIds(js::FreeOp* fop)
|
||||
JS::Zone::sweepUniqueIds()
|
||||
{
|
||||
uniqueIds().sweep();
|
||||
}
|
||||
|
@ -5363,7 +5362,7 @@ static void
|
|||
SweepObjectGroups(JSRuntime* runtime)
|
||||
{
|
||||
for (SweepGroupCompartmentsIter c(runtime); !c.done(); c.next())
|
||||
c->objectGroups.sweep(runtime->defaultFreeOp());
|
||||
c->objectGroups.sweep();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -5432,9 +5431,8 @@ SweepWeakMaps(JSRuntime* runtime)
|
|||
static void
|
||||
SweepUniqueIds(JSRuntime* runtime)
|
||||
{
|
||||
FreeOp fop(nullptr);
|
||||
for (SweepGroupZonesIter zone(runtime); !zone.done(); zone.next())
|
||||
zone->sweepUniqueIds(&fop);
|
||||
zone->sweepUniqueIds();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5494,11 +5492,11 @@ GCRuntime::sweepJitDataOnMainThread(FreeOp* fop)
|
|||
js::CancelOffThreadIonCompile(rt, JS::Zone::Sweep);
|
||||
|
||||
for (SweepGroupCompartmentsIter c(rt); !c.done(); c.next())
|
||||
c->sweepJitCompartment(fop);
|
||||
c->sweepJitCompartment();
|
||||
|
||||
for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
if (jit::JitZone* jitZone = zone->jitZone())
|
||||
jitZone->sweep(fop);
|
||||
jitZone->sweep();
|
||||
}
|
||||
|
||||
// Bug 1071218: the following method has not yet been refactored to
|
||||
|
@ -5519,7 +5517,7 @@ GCRuntime::sweepJitDataOnMainThread(FreeOp* fop)
|
|||
gcstats::AutoPhase ap1(stats(), gcstats::PhaseKind::SWEEP_TYPES);
|
||||
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::SWEEP_TYPES_BEGIN);
|
||||
for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next())
|
||||
zone->beginSweepTypes(fop, releaseObservedTypes && !zone->isPreservingCode());
|
||||
zone->beginSweepTypes(releaseObservedTypes && !zone->isPreservingCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5689,7 +5687,7 @@ GCRuntime::beginSweepingSweepGroup(FreeOp* fop, SliceBudget& budget)
|
|||
for (unsigned i = 0; i < ArrayLength(BackgroundFinalizePhases); ++i)
|
||||
zone->arenas.queueForBackgroundSweep(fop, BackgroundFinalizePhases[i]);
|
||||
|
||||
zone->arenas.queueForegroundThingsForSweep(fop);
|
||||
zone->arenas.queueForegroundThingsForSweep();
|
||||
}
|
||||
|
||||
sweepCache = nullptr;
|
||||
|
@ -6651,13 +6649,13 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
|||
}
|
||||
|
||||
void
|
||||
GCRuntime::endCompactPhase(JS::gcreason::Reason reason)
|
||||
GCRuntime::endCompactPhase()
|
||||
{
|
||||
startedCompacting = false;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::finishCollection(JS::gcreason::Reason reason)
|
||||
GCRuntime::finishCollection()
|
||||
{
|
||||
assertBackgroundSweepingFinished();
|
||||
MOZ_ASSERT(marker.isDrained());
|
||||
|
@ -7116,7 +7114,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
if (compactPhase(reason, budget, session) == NotFinished)
|
||||
break;
|
||||
|
||||
endCompactPhase(reason);
|
||||
endCompactPhase();
|
||||
}
|
||||
|
||||
startDecommit();
|
||||
|
@ -7135,7 +7133,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
decommitTask.join();
|
||||
}
|
||||
|
||||
finishCollection(reason);
|
||||
finishCollection();
|
||||
incrementalState = State::NotActive;
|
||||
break;
|
||||
}
|
||||
|
@ -7721,7 +7719,7 @@ GCRuntime::onOutOfMallocMemory(const AutoLockGC& lock)
|
|||
releaseHeldRelocatedArenasWithoutUnlocking(lock);
|
||||
|
||||
// Throw away any excess chunks we have lying around.
|
||||
freeEmptyChunks(rt, lock);
|
||||
freeEmptyChunks(lock);
|
||||
|
||||
// Immediately decommit as many arenas as possible in the hopes that this
|
||||
// might let the OS scrape together enough pages to satisfy the failing
|
||||
|
@ -8470,7 +8468,7 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)
|
|||
c->checkWrapperMapAfterMovingGC();
|
||||
c->checkScriptMapsAfterMovingGC();
|
||||
if (c->debugEnvs)
|
||||
c->debugEnvs->checkHashTablesAfterMovingGC(rt);
|
||||
c->debugEnvs->checkHashTablesAfterMovingGC();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -426,7 +426,7 @@ class GCRuntime
|
|||
}
|
||||
|
||||
inline void updateOnFreeArenaAlloc(const ChunkInfo& info);
|
||||
inline void updateOnArenaFree(const ChunkInfo& info);
|
||||
inline void updateOnArenaFree();
|
||||
|
||||
ChunkPool& fullChunks(const AutoLockGC& lock) { return fullChunks_.ref(); }
|
||||
ChunkPool& availableChunks(const AutoLockGC& lock) { return availableChunks_.ref(); }
|
||||
|
@ -510,10 +510,9 @@ class GCRuntime
|
|||
MOZ_MUST_USE bool gcIfNeededAtAllocation(JSContext* cx);
|
||||
template <typename T>
|
||||
static void checkIncrementalZoneState(JSContext* cx, T* t);
|
||||
static TenuredCell* refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind,
|
||||
size_t thingSize);
|
||||
static TenuredCell* refillFreeListFromActiveCooperatingThread(JSContext* cx, AllocKind thingKind,
|
||||
size_t thingSize);
|
||||
static TenuredCell* refillFreeListFromAnyThread(JSContext* cx, AllocKind thingKind);
|
||||
static TenuredCell* refillFreeListFromActiveCooperatingThread(JSContext* cx,
|
||||
AllocKind thingKind);
|
||||
static TenuredCell* refillFreeListFromHelperThread(JSContext* cx, AllocKind thingKind);
|
||||
|
||||
/*
|
||||
|
@ -522,7 +521,7 @@ class GCRuntime
|
|||
*/
|
||||
friend class BackgroundDecommitTask;
|
||||
ChunkPool expireEmptyChunkPool(const AutoLockGC& lock);
|
||||
void freeEmptyChunks(JSRuntime* rt, const AutoLockGC& lock);
|
||||
void freeEmptyChunks(const AutoLockGC& lock);
|
||||
void prepareToFreeChunk(ChunkInfo& info);
|
||||
|
||||
friend class BackgroundAllocTask;
|
||||
|
@ -612,13 +611,13 @@ class GCRuntime
|
|||
void beginCompactPhase();
|
||||
IncrementalProgress compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
||||
AutoTraceSession& session);
|
||||
void endCompactPhase(JS::gcreason::Reason reason);
|
||||
void endCompactPhase();
|
||||
void sweepTypesAfterCompacting(Zone* zone);
|
||||
void sweepZoneAfterCompacting(Zone* zone);
|
||||
MOZ_MUST_USE bool relocateArenas(Zone* zone, JS::gcreason::Reason reason,
|
||||
Arena*& relocatedListOut, SliceBudget& sliceBudget);
|
||||
void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
|
||||
void updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount);
|
||||
void updateCellPointers(Zone* zone, AllocKinds kinds, size_t bgTaskCount);
|
||||
void updateAllCellPointers(MovingTracer* trc, Zone* zone);
|
||||
void updateZonePointersToRelocatedCells(Zone* zone);
|
||||
void updateRuntimePointersToRelocatedCells(AutoTraceSession& session);
|
||||
|
@ -626,7 +625,7 @@ class GCRuntime
|
|||
void unprotectHeldRelocatedArenas();
|
||||
void releaseRelocatedArenas(Arena* arenaList);
|
||||
void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLockGC& lock);
|
||||
void finishCollection(JS::gcreason::Reason reason);
|
||||
void finishCollection();
|
||||
|
||||
void computeNonIncrementalMarkingForValidation(AutoTraceSession& session);
|
||||
void validateIncrementalMarking();
|
||||
|
|
|
@ -766,14 +766,14 @@ struct Chunk
|
|||
void init(JSRuntime* rt);
|
||||
|
||||
private:
|
||||
void decommitAllArenas(JSRuntime* rt);
|
||||
void decommitAllArenas();
|
||||
|
||||
/* Search for a decommitted arena to allocate. */
|
||||
unsigned findDecommittedArenaOffset();
|
||||
Arena* fetchNextDecommittedArena();
|
||||
|
||||
void addArenaToFreeList(JSRuntime* rt, Arena* arena);
|
||||
void addArenaToDecommittedList(JSRuntime* rt, const Arena* arena);
|
||||
void addArenaToDecommittedList(const Arena* arena);
|
||||
|
||||
void updateChunkListAfterAlloc(JSRuntime* rt, const AutoLockGC& lock);
|
||||
void updateChunkListAfterFree(JSRuntime* rt, const AutoLockGC& lock);
|
||||
|
|
|
@ -3049,7 +3049,7 @@ js::TenuringTracer::moveToTenuredSlow(JSObject* src)
|
|||
if (src->isNative()) {
|
||||
NativeObject* ndst = &dst->as<NativeObject>();
|
||||
NativeObject* nsrc = &src->as<NativeObject>();
|
||||
tenuredSize += moveSlotsToTenured(ndst, nsrc, dstKind);
|
||||
tenuredSize += moveSlotsToTenured(ndst, nsrc);
|
||||
tenuredSize += moveElementsToTenured(ndst, nsrc, dstKind);
|
||||
|
||||
// There is a pointer into a dictionary mode object from the head of its
|
||||
|
@ -3094,7 +3094,7 @@ js::TenuringTracer::movePlainObjectToTenured(PlainObject* src)
|
|||
js_memcpy(dst, src, srcSize);
|
||||
|
||||
// Move the slots and elements.
|
||||
tenuredSize += moveSlotsToTenured(dst, src, dstKind);
|
||||
tenuredSize += moveSlotsToTenured(dst, src);
|
||||
tenuredSize += moveElementsToTenured(dst, src, dstKind);
|
||||
|
||||
MOZ_ASSERT(!dst->getClass()->extObjectMovedOp());
|
||||
|
@ -3108,7 +3108,7 @@ js::TenuringTracer::movePlainObjectToTenured(PlainObject* src)
|
|||
}
|
||||
|
||||
size_t
|
||||
js::TenuringTracer::moveSlotsToTenured(NativeObject* dst, NativeObject* src, AllocKind dstKind)
|
||||
js::TenuringTracer::moveSlotsToTenured(NativeObject* dst, NativeObject* src)
|
||||
{
|
||||
/* Fixed slots have already been copied over. */
|
||||
if (!src->hasDynamicSlots())
|
||||
|
|
|
@ -326,7 +326,7 @@ js::Nursery::allocateObject(JSContext* cx, size_t size, size_t nDynamicSlots, co
|
|||
}
|
||||
|
||||
Cell*
|
||||
js::Nursery::allocateString(JSContext* cx, Zone* zone, size_t size, AllocKind kind)
|
||||
js::Nursery::allocateString(Zone* zone, size_t size, AllocKind kind)
|
||||
{
|
||||
/* Ensure there's enough space to replace the contents with a RelocationOverlay. */
|
||||
MOZ_ASSERT(size >= sizeof(RelocationOverlay));
|
||||
|
@ -880,7 +880,7 @@ js::Nursery::doCollection(JS::gcreason::Reason reason,
|
|||
|
||||
// Update any slot or element pointers whose destination has been tenured.
|
||||
startProfile(ProfileKey::UpdateJitActivations);
|
||||
js::jit::UpdateJitActivationsForMinorGC(rt, &mover);
|
||||
js::jit::UpdateJitActivationsForMinorGC(rt);
|
||||
forwardedBuffers.finish();
|
||||
endProfile(ProfileKey::UpdateJitActivations);
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ class TenuringTracer : public JSTracer
|
|||
JSString* moveToTenured(JSString* src);
|
||||
|
||||
size_t moveElementsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
|
||||
size_t moveSlotsToTenured(NativeObject* dst, NativeObject* src, gc::AllocKind dstKind);
|
||||
size_t moveSlotsToTenured(NativeObject* dst, NativeObject* src);
|
||||
size_t moveStringToTenured(JSString* dst, JSString* src, gc::AllocKind dstKind);
|
||||
|
||||
void traceSlots(JS::Value* vp, JS::Value* end);
|
||||
|
@ -200,7 +200,7 @@ class Nursery
|
|||
* Allocate and return a pointer to a new string. Returns nullptr if the
|
||||
* Nursery is full.
|
||||
*/
|
||||
gc::Cell* allocateString(JSContext* cx, JS::Zone* zone, size_t size, gc::AllocKind kind);
|
||||
gc::Cell* allocateString(JS::Zone* zone, size_t size, gc::AllocKind kind);
|
||||
|
||||
/*
|
||||
* String zones are stored just before the string in nursery memory.
|
||||
|
|
|
@ -112,10 +112,10 @@ Zone::setNeedsIncrementalBarrier(bool needs)
|
|||
}
|
||||
|
||||
void
|
||||
Zone::beginSweepTypes(FreeOp* fop, bool releaseTypes)
|
||||
Zone::beginSweepTypes(bool releaseTypes)
|
||||
{
|
||||
AutoClearTypeInferenceStateOnOOM oom(this);
|
||||
types.beginSweep(fop, releaseTypes, oom);
|
||||
types.beginSweep(releaseTypes, oom);
|
||||
}
|
||||
|
||||
Zone::DebuggerVector*
|
||||
|
|
|
@ -192,7 +192,7 @@ struct Zone : public JS::shadow::Zone,
|
|||
}
|
||||
void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
|
||||
|
||||
void beginSweepTypes(js::FreeOp* fop, bool releaseTypes);
|
||||
void beginSweepTypes(bool releaseTypes);
|
||||
|
||||
bool hasMarkedCompartments();
|
||||
|
||||
|
@ -265,7 +265,7 @@ struct Zone : public JS::shadow::Zone,
|
|||
#endif
|
||||
|
||||
void sweepBreakpoints(js::FreeOp* fop);
|
||||
void sweepUniqueIds(js::FreeOp* fop);
|
||||
void sweepUniqueIds();
|
||||
void sweepWeakMaps();
|
||||
void sweepCompartments(js::FreeOp* fop, bool keepAtleastOne, bool lastGC);
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
function warmup(fun, input, expected) {
|
||||
assertEq(input.length, expected.length);
|
||||
for (var i = 0; i < 30; i++) {
|
||||
for (var j = 0; j < input.length; j++) {
|
||||
lhs = input[j][0];
|
||||
rhs = input[j][1];
|
||||
assertEq(fun(lhs,rhs), expected[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var strictCompare = function(a,b) { return a === b; }
|
||||
warmup(strictCompare, [[1,1], [3,3], [3,strictCompare],[strictCompare, {}], [3.2, 1],
|
||||
[0, -0]],
|
||||
[true, true, false, false, false,
|
||||
true]);
|
|
@ -18,9 +18,9 @@ var code = `(module
|
|||
try {
|
||||
wasmFullPass(code, Math.fround(13.37), {}, 13.37);
|
||||
} catch (e) {
|
||||
// ASAN will fail these tests because its stack frames are much bigger than
|
||||
// usual ones and the parser will bail out during its recursive descent.
|
||||
// Some configurations, like e.g. ASAN, will fail these tests because its
|
||||
// stack frames are much bigger than usual ones and the parser will bail
|
||||
// out during its recursive descent.
|
||||
// Ignore those errors specifically.
|
||||
assertEq(e.message.includes('out of memory'), true);
|
||||
assertEq(getBuildConfiguration().asan, true);
|
||||
}
|
||||
|
|
|
@ -627,8 +627,8 @@ IsPrologueBailout(const SnapshotIterator& iter, const ExceptionBailoutInfo* excI
|
|||
// +===============+
|
||||
//
|
||||
static bool
|
||||
InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
||||
HandleFunction fun, HandleScript script, IonScript* ionScript,
|
||||
InitFromBailout(JSContext* cx, jsbytecode* callerPC,
|
||||
HandleFunction fun, HandleScript script,
|
||||
SnapshotIterator& iter, bool invalidate, BaselineStackBuilder& builder,
|
||||
MutableHandle<GCVector<Value>> startFrameFormals, MutableHandleFunction nextCallee,
|
||||
jsbytecode** callPC, const ExceptionBailoutInfo* excInfo)
|
||||
|
@ -1665,7 +1665,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation,
|
|||
|
||||
jsbytecode* callPC = nullptr;
|
||||
RootedFunction nextCallee(cx, nullptr);
|
||||
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
|
||||
if (!InitFromBailout(cx, callerPC, fun, scr,
|
||||
snapIter, invalidate, builder, &startFrameFormals,
|
||||
&nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
|
||||
{
|
||||
|
|
|
@ -234,7 +234,7 @@ BaselineCompiler::compile()
|
|||
|
||||
// Copy IC entries
|
||||
if (icEntries_.length())
|
||||
baselineScript->copyICEntries(script, &icEntries_[0], masm);
|
||||
baselineScript->copyICEntries(script, &icEntries_[0]);
|
||||
|
||||
// Adopt fallback stubs from the compiler into the baseline script.
|
||||
baselineScript->adoptFallbackStubs(&stubSpace_);
|
||||
|
@ -260,7 +260,7 @@ BaselineCompiler::compile()
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
// Initialize the tracelogger instrumentation.
|
||||
baselineScript->initTraceLogger(cx->runtime(), script, traceLoggerToggleOffsets_);
|
||||
baselineScript->initTraceLogger(script, traceLoggerToggleOffsets_);
|
||||
#endif
|
||||
|
||||
uint32_t* bytecodeMap = baselineScript->bytecodeTypeMap();
|
||||
|
@ -290,7 +290,7 @@ BaselineCompiler::compile()
|
|||
entry.init(code, code->raw(), code->rawEnd(), script, str);
|
||||
|
||||
JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
||||
if (!globalTable->addEntry(entry, cx->runtime())) {
|
||||
if (!globalTable->addEntry(entry)) {
|
||||
entry.destroy();
|
||||
ReportOutOfMemory(cx);
|
||||
return Method_Error;
|
||||
|
@ -4636,21 +4636,19 @@ BaselineCompiler::emit_JSOP_DEBUGAFTERYIELD()
|
|||
return callVM(DebugAfterYieldInfo);
|
||||
}
|
||||
|
||||
typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, BaselineFrame*, jsbytecode*);
|
||||
typedef bool (*FinalSuspendFn)(JSContext*, HandleObject, jsbytecode*);
|
||||
static const VMFunction FinalSuspendInfo =
|
||||
FunctionInfo<FinalSuspendFn>(jit::FinalSuspend, "FinalSuspend");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_FINALYIELDRVAL()
|
||||
{
|
||||
// Store generator in R0, BaselineFrame pointer in R1.
|
||||
// Store generator in R0.
|
||||
frame.popRegsAndSync(1);
|
||||
masm.unboxObject(R0, R0.scratchReg());
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(ImmPtr(pc));
|
||||
pushArg(R1.scratchReg());
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(FinalSuspendInfo))
|
||||
|
|
|
@ -642,7 +642,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
|||
static void
|
||||
SkipInterpreterFrameEntries(const Debugger::ExecutionObservableSet& obs,
|
||||
const ActivationIterator& activation,
|
||||
DebugModeOSREntryVector& entries, size_t* start)
|
||||
size_t* start)
|
||||
{
|
||||
size_t entryIndex = *start;
|
||||
|
||||
|
@ -912,7 +912,7 @@ jit::RecompileOnStackBaselineScriptsForDebugMode(JSContext* cx,
|
|||
if (iter->isJit())
|
||||
PatchBaselineFramesForDebugMode(cx, target, obs, iter, entries, &processed);
|
||||
else if (iter->isInterpreter())
|
||||
SkipInterpreterFrameEntries(obs, iter, entries, &processed);
|
||||
SkipInterpreterFrameEntries(obs, iter, &processed);
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(processed == entries.length());
|
||||
|
|
|
@ -85,8 +85,7 @@ struct IonOsrTempData
|
|||
};
|
||||
|
||||
static IonOsrTempData*
|
||||
PrepareOsrTempData(JSContext* cx, ICWarmUpCounter_Fallback* stub, BaselineFrame* frame,
|
||||
HandleScript script, jsbytecode* pc, void* jitcode)
|
||||
PrepareOsrTempData(JSContext* cx, BaselineFrame* frame, void* jitcode)
|
||||
{
|
||||
size_t numLocalsAndStackVals = frame->numValueSlots();
|
||||
|
||||
|
@ -163,7 +162,7 @@ DoWarmUpCounterFallbackOSR(JSContext* cx, BaselineFrame* frame, ICWarmUpCounter_
|
|||
|
||||
// Prepare the temporary heap copy of the fake InterpreterFrame and actual args list.
|
||||
JitSpew(JitSpew_BaselineOSR, "Got jitcode. Preparing for OSR into ion.");
|
||||
IonOsrTempData* info = PrepareOsrTempData(cx, stub, frame, script, pc, jitcode);
|
||||
IonOsrTempData* info = PrepareOsrTempData(cx, frame, jitcode);
|
||||
if (!info)
|
||||
return false;
|
||||
*infoPtr = info;
|
||||
|
@ -1635,7 +1634,7 @@ ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
// This is the resume point used when bailout rewrites call stack to undo
|
||||
// Ion inlined frames. The return address pushed onto reconstructed stack
|
||||
// will point here.
|
||||
assumeStubFrame(masm);
|
||||
assumeStubFrame();
|
||||
bailoutReturnOffset_.bind(masm.currentOffset());
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -2327,7 +2326,7 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
|||
// Only bother to try optimizing JSOP_CALL with CacheIR if the chain is still
|
||||
// allowed to attach stubs.
|
||||
if (canAttachStub) {
|
||||
CallIRGenerator gen(cx, script, pc, op, stub, stub->state().mode(), argc,
|
||||
CallIRGenerator gen(cx, script, pc, op, stub->state().mode(), argc,
|
||||
callee, callArgs.thisv(),
|
||||
HandleValueArray::fromMarkedLocation(argc, vp+2));
|
||||
if (gen.tryAttachStub()) {
|
||||
|
@ -2844,7 +2843,7 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
// This is the resume point used when bailout rewrites call stack to undo
|
||||
// Ion inlined frames. The return address pushed onto reconstructed stack
|
||||
// will point here.
|
||||
assumeStubFrame(masm);
|
||||
assumeStubFrame();
|
||||
bailoutReturnOffset_.bind(masm.currentOffset());
|
||||
|
||||
// Load passed-in ThisV into R1 just in case it's needed. Need to do this before
|
||||
|
|
|
@ -300,7 +300,7 @@ CanEnterBaselineJIT(JSContext* cx, HandleScript script, InterpreterFrame* osrFra
|
|||
}
|
||||
|
||||
MethodStatus
|
||||
jit::CanEnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp, bool newType)
|
||||
jit::CanEnterBaselineAtBranch(JSContext* cx, InterpreterFrame* fp)
|
||||
{
|
||||
if (!CheckFrame(fp))
|
||||
return Method_CantCompile;
|
||||
|
@ -744,7 +744,7 @@ BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yie
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm)
|
||||
BaselineScript::copyICEntries(JSScript* script, const BaselineICEntry* entries)
|
||||
{
|
||||
// Fix up the return offset in the IC entries and copy them in.
|
||||
// Also write out the IC entry ptrs in any fallback stubs that were added.
|
||||
|
@ -949,8 +949,7 @@ BaselineScript::toggleDebugTraps(JSScript* script, jsbytecode* pc)
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
BaselineScript::initTraceLogger(JSRuntime* runtime, JSScript* script,
|
||||
const Vector<CodeOffset>& offsets)
|
||||
BaselineScript::initTraceLogger(JSScript* script, const Vector<CodeOffset>& offsets)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_ = TraceLogTextIdEnabled(TraceLogger_Scripts);
|
||||
|
@ -971,7 +970,7 @@ BaselineScript::initTraceLogger(JSRuntime* runtime, JSScript* script,
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleTraceLoggerScripts(JSRuntime* runtime, JSScript* script, bool enable)
|
||||
BaselineScript::toggleTraceLoggerScripts(JSScript* script, bool enable)
|
||||
{
|
||||
DebugOnly<bool> engineEnabled = TraceLogTextIdEnabled(TraceLogger_Engine);
|
||||
MOZ_ASSERT(enable == !traceLoggerScriptsEnabled_);
|
||||
|
@ -1165,7 +1164,7 @@ jit::ToggleBaselineTraceLoggerScripts(JSRuntime* runtime, bool enable)
|
|||
for (auto script = zone->cellIter<JSScript>(); !script.done(); script.next()) {
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleTraceLoggerScripts(runtime, script, enable);
|
||||
script->baselineScript()->toggleTraceLoggerScripts(script, enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче