Merge branch 'mozilla-central'

This commit is contained in:
Jacek Caban 2016-03-04 06:38:14 +01:00
commit 8d90872877
469 changed files with 7295 additions and 4315 deletions

View File

@ -14,9 +14,8 @@ using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell), mActivated(false)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell), mActivated(false)
{
}

View File

@ -19,8 +19,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
bool mActivated;

View File

@ -470,17 +470,15 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// We only create root accessibles for the true root, otherwise create a
// doc accessible.
nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
RefPtr<DocAccessible> docAcc = isRootDoc ?
new RootAccessibleWrap(aDocument, rootElm, presShell) :
new DocAccessibleWrap(aDocument, rootElm, presShell);
new RootAccessibleWrap(aDocument, presShell) :
new DocAccessibleWrap(aDocument, presShell);
// Cache the document accessible into document cache.
mDocAccessibleCache.Put(aDocument, docAcc);
// Initialize the document accessible.
docAcc->Init();
docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument));
// Bind the document to the tree.
if (isRootDoc) {

View File

@ -76,9 +76,8 @@ static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
// Constructor/desctructor
DocAccessible::
DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(aRootContent, this),
DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(nullptr, this),
// XXX aaronl should we use an algorithm for the initial cache size?
mAccessibleCache(kDefaultCacheLength),
mNodeToAccessibleMap(kDefaultCacheLength),
@ -1465,7 +1464,7 @@ DocAccessible::DoInitialUpdate()
// miss the notification (since content tree change notifications are ignored
// prior to initial update). Make sure the content element is valid.
nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
if (mContent != contentElm) {
if (contentElm) {
mContent = contentElm;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}

View File

@ -50,8 +50,7 @@ class DocAccessible : public HyperTextAccessibleWrap,
public:
DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
// nsIScrollPositionListener
virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {}

View File

@ -59,9 +59,8 @@ NS_IMPL_ISUPPORTS_INHERITED0(RootAccessible, DocAccessible)
// Constructor/destructor
RootAccessible::
RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessibleWrap(aDocument, aRootContent, aPresShell)
RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessibleWrap(aDocument, aPresShell)
{
mType = eRootType;
}

View File

@ -22,8 +22,7 @@ class RootAccessible : public DocAccessibleWrap,
NS_DECL_ISUPPORTS_INHERITED
public:
RootAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;

View File

@ -344,7 +344,7 @@ this.AccessFu = { // jshint ignore:line
{
// Ignore notifications that aren't from a BrowserOrApp
let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
if (!frameLoader.ownerIsBrowserOrAppFrame) {
if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
return;
}
this._handleMessageManager(frameLoader.messageManager);

View File

@ -14,8 +14,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
};

View File

@ -10,9 +10,8 @@
using namespace mozilla::a11y;
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell)
{
}

View File

@ -18,8 +18,7 @@ namespace a11y {
class RootAccessibleWrap : public RootAccessible
{
public:
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~RootAccessibleWrap();
Class GetNativeType ();

View File

@ -16,9 +16,8 @@
using namespace mozilla::a11y;
RootAccessibleWrap::
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
RootAccessible(aDocument, aRootContent, aPresShell)
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
RootAccessible(aDocument, aPresShell)
{
}

View File

@ -20,8 +20,6 @@
src="../value.js"></script>
<script type="application/javascript">
/**
* Do tests.
*/
@ -132,6 +130,29 @@
}
}
function changeSelectValue(aID, aKey, aValue)
{
this.eventSeq = [new invokerChecker(EVENT_TEXT_VALUE_CHANGE, aID)];
this.invoke = function changeSelectValue_invoke()
{
getNode(aID).focus();
synthesizeKey(aKey, {}, window);
}
this.finalCheck = function changeSelectValue_finalCheck()
{
is(getAccessible(aID).value, aValue, "Wrong value for " + prettyName(aID));
}
this.getID = function changeSelectValue_getID()
{
return `${prettyName(aID)} closed select value change on '${aKey}'' key press`;
}
}
//enableLogging("DOMEvents");
//gA11yEventDumpToConsole = true;
function doTests()
{
// Test initial values
@ -155,6 +176,9 @@
gQueue.push(new changeProgressValue("progress", "50"));
gQueue.push(new changeRangeValue("range"));
gQueue.push(new changeSelectValue("select", "VK_DOWN", "2nd"));
gQueue.push(new changeSelectValue("select", "3", "3rd"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -221,5 +245,10 @@
<!-- input@type="range" -->
<input type="range" id="range" min="0" max="10" value="6">
<select id="select">
<option>1st</option>
<option>2nd</option>
<option>3rd</option>
</select>
</body>
</html>

View File

@ -25,9 +25,8 @@ using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
DocAccessibleWrap::
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
DocAccessible(aDocument, aRootContent, aPresShell), mHWND(nullptr)
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
DocAccessible(aDocument, aPresShell), mHWND(nullptr)
{
}

View File

@ -15,8 +15,7 @@ namespace a11y {
class DocAccessibleWrap : public DocAccessible
{
public:
DocAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~DocAccessibleWrap();
DECL_IUNKNOWN_INHERITED

View File

@ -15,9 +15,8 @@ using namespace mozilla::a11y;
// Constructor/desctructor
RootAccessibleWrap::
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell) :
RootAccessible(aDocument, aRootContent, aPresShell)
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
RootAccessible(aDocument, aPresShell)
{
}

View File

@ -14,8 +14,7 @@ namespace a11y {
class RootAccessibleWrap : public RootAccessible
{
public:
RootAccessibleWrap(nsIDocument* aDocument, nsIContent* aRootContent,
nsIPresShell* aPresShell);
RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
virtual ~RootAccessibleWrap();
// RootAccessible

View File

@ -67,8 +67,9 @@ var internal = ns();
// menu
var lastContextProcessId = null;
var uuidModule = require('./util/uuid');
function uuid() {
return require('./util/uuid').uuid().toString();
return uuidModule.uuid().toString();
}
function getScheme(spec) {

View File

@ -57,7 +57,7 @@ AppRunner.prototype = {
// get a ref to the app <iframe>
frameLoader.QueryInterface(Ci.nsIFrameLoader);
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.ownerIsBrowserOrAppFrame) {
if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
return;
}

View File

@ -144,7 +144,7 @@ this.AboutServiceWorkers = {
!message.principal.origin ||
!message.principal.originAttributes ||
!message.principal.originAttributes.appId ||
(message.principal.originAttributes.inBrowser == null)) {
(message.principal.originAttributes.inIsolatedMozBrowser == null)) {
self.sendError(message.id, "MissingPrincipal");
return;
}

View File

@ -177,7 +177,7 @@ var ErrorPage = {
observe: function errorPageObserve(aSubject, aTopic, aData) {
let frameLoader = aSubject.QueryInterface(Ci.nsIFrameLoader);
// Ignore notifications that aren't from a BrowserOrApp
if (!frameLoader.ownerIsBrowserOrAppFrame) {
if (!frameLoader.ownerIsMozBrowserOrAppFrame) {
return;
}
this._listenError(frameLoader);

View File

@ -1377,6 +1377,9 @@ pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3
// activates the remote-hosted newtab page
pref("browser.newtabpage.remote", false);
// Toggles endpoints allowed for remote newtab communications
pref("browser.newtabpage.remote.mode", "production");
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);
@ -1655,3 +1658,6 @@ pref("media.webspeech.synth.enabled", true);
pref("browser.esedbreader.loglevel", "Error");
pref("browser.laterrun.enabled", false);
// Enable browser frames for use on desktop. Only exposed to chrome callers.
pref("dom.mozBrowserFramesEnabled", true);

View File

@ -1379,44 +1379,37 @@ var BookmarkingUI = {
aHeaderItem.nextSibling.remove();
}
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
let onItemCommand = function (aEvent) {
let item = aEvent.target;
openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
};
let onItemCommand = function (aEvent) {
let item = aEvent.target;
openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
};
let fragment = document.createDocumentFragment();
let row;
while ((row = aResultSet.getNextRow())) {
let uri = row.getResultByIndex(1);
let title = row.getResultByIndex(2);
let icon = row.getResultByIndex(6);
let fragment = document.createDocumentFragment();
let root = PlacesUtils.history.executeQuery(query, options).root;
root.containerOpen = true;
for (let i = 0; i < root.childCount; i++) {
let node = root.getChild(i);
let uri = node.uri;
let title = node.title;
let icon = node.icon;
let item =
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"menuitem");
item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri);
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
extraCSSClass);
item.addEventListener("command", onItemCommand);
if (icon) {
let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL);
}
fragment.appendChild(item);
}
aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling);
},
handleError: function (aError) {
Cu.reportError("Error while attempting to show recent bookmarks: " + aError);
},
handleCompletion: function (aReason) {
},
});
let item =
document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"menuitem");
item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri);
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
extraCSSClass);
item.addEventListener("command", onItemCommand);
if (icon) {
let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL);
}
fragment.appendChild(item);
}
root.containerOpen = false;
aHeaderItem.parentNode.insertBefore(fragment, aHeaderItem.nextSibling);
},
/**

View File

@ -252,7 +252,8 @@ ContentSearchUIController.prototype = {
let searchText = this.input;
let searchTerms;
if (this._table.hidden ||
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader") {
aEvent.originalTarget.id == "contentSearchDefaultEngineHeader" ||
aEvent instanceof KeyboardEvent) {
searchTerms = searchText.value;
}
else {

View File

@ -290,7 +290,6 @@ skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe versio
[browser_bug1070778.js]
[browser_accesskeys.js]
[browser_canonizeURL.js]
skip-if = e10s # Bug 1094510 - test hits the network in e10s mode only
[browser_clipboard.js]
[browser_contentAreaClick.js]
[browser_contextmenu.js]

View File

@ -1,8 +1,3 @@
function test() {
waitForExplicitFinish();
testNext();
}
var pairs = [
["example", "http://www.example.net/"],
["ex-ample", "http://www.ex-ample.net/"],
@ -20,37 +15,56 @@ var pairs = [
["ex ample", Services.search.defaultEngine.getSubmission("ex ample", null, "keyword").uri.spec],
];
function testNext() {
if (!pairs.length) {
finish();
return;
}
add_task(function*() {
for (let [inputValue, expectedURL] of pairs) {
let focusEventPromise = BrowserTestUtils.waitForEvent(gURLBar, "focus");
let messagePromise = BrowserTestUtils.waitForMessage(gBrowser.selectedBrowser.messageManager,
"browser_canonizeURL:start");
let [inputValue, expectedURL] = pairs.shift();
let stoppedLoadPromise = ContentTask.spawn(gBrowser.selectedBrowser, [inputValue, expectedURL],
function([inputValue, expectedURL]) {
return new Promise(resolve => {
let wpl = {
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
if (!aRequest || !(aRequest instanceof Ci.nsIChannel)) {
return;
}
aRequest.QueryInterface(Ci.nsIChannel);
is(aRequest.originalURI.spec, expectedURL,
"entering '" + inputValue + "' loads expected URL");
gBrowser.addProgressListener({
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
is(aRequest.originalURI.spec, expectedURL,
"entering '" + inputValue + "' loads expected URL");
webProgress.removeProgressListener(filter);
filter.removeProgressListener(wpl);
docShell.QueryInterface(Ci.nsIWebNavigation);
docShell.stop(docShell.STOP_ALL);
resolve();
}
},
};
let filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
filter.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
gBrowser.removeProgressListener(this);
gBrowser.stop();
executeSoon(testNext);
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
// We're sending this off to trigger the start of the this test, when all the
// listeners are in place:
sendAsyncMessage("browser_canonizeURL:start");
});
}
}
});
);
gBrowser.selectedBrowser.focus();
gURLBar.focus();
yield Promise.all([focusEventPromise, messagePromise]);
gURLBar.addEventListener("focus", function onFocus() {
gURLBar.removeEventListener("focus", onFocus);
gURLBar.inputField.value = inputValue.slice(0, -1);
EventUtils.synthesizeKey(inputValue.slice(-1) , {});
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true });
});
gBrowser.selectedBrowser.focus();
gURLBar.focus();
}
yield stoppedLoadPromise;
}
});

View File

@ -105,7 +105,7 @@
when-connection="secure secure-ev"/>
</vbox>
<vbox id="identity-popup-securityView-body">
<vbox id="identity-popup-securityView-body" flex="1">
<!-- (EV) Certificate Information -->
<description id="identity-popup-content-verified-by"
when-connection="secure-ev">&identity.connectionVerified1;</description>
@ -168,7 +168,9 @@
label="&identity.enableMixedContentBlocking.label;"
accesskey="&identity.enableMixedContentBlocking.accesskey;"
oncommand="gIdentityHandler.enableMixedContentProtection()"/>
</vbox>
<vbox id="identity-popup-securityView-footer">
<!-- More Security Information -->
<button label="&identity.moreInfoLinkText2;"
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>

View File

@ -346,11 +346,47 @@ DistributionCustomizer.prototype = {
Cu.reportError(e);
}
var usedPreferences = [];
if (sections["Preferences-" + this._locale]) {
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._locale))) {
try {
let value = this._ini.getString("Preferences-" + this._locale, key);
if (value) {
Preferences.set(key, parseValue(value));
}
usedPreferences.push(key);
} catch (e) { /* ignore bad prefs and move on */ }
}
}
if (sections["Preferences-" + this._language]) {
for (let key of enumerate(this._ini.getKeys("Preferences-" + this._language))) {
if (usedPreferences.indexOf(key) > -1) {
continue;
}
try {
let value = this._ini.getString("Preferences-" + this._language, key);
if (value) {
Preferences.set(key, parseValue(value));
}
usedPreferences.push(key);
} catch (e) { /* ignore bad prefs and move on */ }
}
}
if (sections["Preferences"]) {
for (let key of enumerate(this._ini.getKeys("Preferences"))) {
if (usedPreferences.indexOf(key) > -1) {
continue;
}
try {
let value = parseValue(this._ini.getString("Preferences", key));
Preferences.set(key, value);
let value = this._ini.getString("Preferences", key);
if (value) {
value = value.replace(/%LOCALE%/g, this._locale);
value = value.replace(/%LANGUAGE%/g, this._language);
Preferences.set(key, parseValue(value));
}
} catch (e) { /* ignore bad prefs and move on */ }
}
}
@ -363,8 +399,9 @@ DistributionCustomizer.prototype = {
if (sections["LocalizablePreferences-" + this._locale]) {
for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
try {
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._locale, key));
if (value !== undefined) {
let value = this._ini.getString("LocalizablePreferences-" + this._locale, key);
if (value) {
value = parseValue(value);
localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
}
@ -379,8 +416,9 @@ DistributionCustomizer.prototype = {
continue;
}
try {
let value = parseValue(this._ini.getString("LocalizablePreferences-" + this._language, key));
if (value !== undefined) {
let value = this._ini.getString("LocalizablePreferences-" + this._language, key);
if (value) {
value = parseValue(value);
localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
}
@ -395,13 +433,14 @@ DistributionCustomizer.prototype = {
continue;
}
try {
let value = parseValue(this._ini.getString("LocalizablePreferences", key));
if (value !== undefined) {
let value = this._ini.getString("LocalizablePreferences", key);
if (value) {
value = parseValue(value);
value = value.replace(/%LOCALE%/g, this._locale);
value = value.replace(/%LANGUAGE%/g, this._language);
localizedStr.data = "data:text/plain," + key + "=" + value;
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
}
defaults._prefBranch.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} catch (e) { /* ignore bad prefs and move on */ }
}
}

View File

@ -125,6 +125,19 @@ global.makeWidgetId = id => {
return id.replace(/[^a-z0-9_-]/g, "_");
};
function promisePopupShown(popup) {
return new Promise(resolve => {
if (popup.state == "open") {
resolve();
} else {
popup.addEventListener("popupshown", function onPopupShown(event) {
popup.removeEventListener("popupshown", onPopupShown);
resolve();
});
}
});
}
class BasePopup {
constructor(extension, viewNode, popupURL) {
let popupURI = Services.io.newURI(popupURL, null, extension.baseURI);
@ -254,6 +267,10 @@ class BasePopup {
// Resizes the browser to match the preferred size of the content.
resizeBrowser() {
if (!this.browser) {
return;
}
let width, height;
try {
let w = {}, h = {};
@ -310,7 +327,12 @@ global.PanelPopup = class PanelPopup extends BasePopup {
}
closePopup() {
this.viewNode.hidePopup();
promisePopupShown(this.viewNode).then(() => {
// Make sure we're not already destroyed.
if (this.viewNode) {
this.viewNode.hidePopup();
}
});
}
};

View File

@ -3,6 +3,8 @@
"use strict";
function* testInArea(area) {
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head></html>`;
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"background": {
@ -14,17 +16,22 @@ function* testInArea(area) {
},
files: {
"popup-a.html": `<script src="popup-a.js"></script>`,
"popup-a.html": scriptPage("popup-a.js"),
"popup-a.js": function() {
browser.runtime.sendMessage("from-popup-a");
browser.runtime.onMessage.addListener(msg => {
if (msg == "close-popup") {
window.close();
}
});
},
"data/popup-b.html": `<script src="popup-b.js"></script>`,
"data/popup-b.html": scriptPage("popup-b.js"),
"data/popup-b.js": function() {
browser.runtime.sendMessage("from-popup-b");
},
"data/background.html": `<script src="background.js"></script>`,
"data/background.html": scriptPage("background.js"),
"data/background.js": function() {
let sendClick;
@ -51,26 +58,36 @@ function* testInArea(area) {
},
() => {
browser.browserAction.setPopup({popup: "/popup-a.html"});
sendClick({expectEvent: false, expectPopup: "a"});
sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
},
() => {
browser.test.sendMessage("next-test", {expectClosed: true});
},
];
let expect = {};
sendClick = ({expectEvent, expectPopup}) => {
expect = {event: expectEvent, popup: expectPopup};
sendClick = ({expectEvent, expectPopup, runNextTest}) => {
expect = {event: expectEvent, popup: expectPopup, runNextTest};
browser.test.sendMessage("send-click");
};
browser.runtime.onMessage.addListener(msg => {
if (expect.popup) {
if (msg == "close-popup") {
return;
} else if (expect.popup) {
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
"expected popup opened");
} else {
browser.test.fail("unexpected popup");
browser.test.fail(`unexpected popup: ${msg}`);
}
expect.popup = null;
browser.test.sendMessage("next-test");
if (expect.runNextTest) {
expect.runNextTest = false;
tests.shift()();
} else {
browser.test.sendMessage("next-test");
}
});
browser.browserAction.onClicked.addListener(() => {
@ -85,6 +102,11 @@ function* testInArea(area) {
});
browser.test.onMessage.addListener((msg) => {
if (msg == "close-popup") {
browser.runtime.sendMessage("close-popup");
return;
}
if (msg != "next-test") {
browser.test.fail("Expecting 'next-test' message");
}
@ -107,13 +129,23 @@ function* testInArea(area) {
});
let widget;
extension.onMessage("next-test", Task.async(function* () {
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
if (!widget) {
widget = getBrowserActionWidget(extension);
CustomizableUI.addWidgetToArea(widget.id, area);
}
if (expecting.expectClosed) {
let panel = getBrowserActionPopup(extension);
ok(panel, "Expect panel to exist");
yield promisePopupShown(panel);
yield closeBrowserAction(extension);
extension.sendMessage("close-popup");
yield promisePopupHidden(panel);
ok(true, "Panel is closed");
} else {
yield closeBrowserAction(extension);
}
extension.sendMessage("next-test");
}));

View File

@ -19,6 +19,11 @@ add_task(function* testPageActionPopup() {
"popup-a.html": scriptPage("popup-a.js"),
"popup-a.js": function() {
browser.runtime.sendMessage("from-popup-a");
browser.runtime.onMessage.addListener(msg => {
if (msg == "close-popup") {
window.close();
}
});
},
"data/popup-b.html": scriptPage("popup-b.js"),
@ -55,26 +60,36 @@ add_task(function* testPageActionPopup() {
},
() => {
browser.pageAction.setPopup({tabId, popup: "/popup-a.html"});
sendClick({expectEvent: false, expectPopup: "a"});
sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
},
() => {
browser.test.sendMessage("next-test", {expectClosed: true});
},
];
let expect = {};
sendClick = ({expectEvent, expectPopup}) => {
expect = {event: expectEvent, popup: expectPopup};
sendClick = ({expectEvent, expectPopup, runNextTest}) => {
expect = {event: expectEvent, popup: expectPopup, runNextTest};
browser.test.sendMessage("send-click");
};
browser.runtime.onMessage.addListener(msg => {
if (expect.popup) {
if (msg == "close-popup") {
return;
} else if (expect.popup) {
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
"expected popup opened");
} else {
browser.test.fail("unexpected popup");
browser.test.fail(`unexpected popup: ${msg}`);
}
expect.popup = null;
browser.test.sendMessage("next-test");
if (expect.runNextTest) {
expect.runNextTest = false;
tests.shift()();
} else {
browser.test.sendMessage("next-test");
}
});
browser.pageAction.onClicked.addListener(() => {
@ -89,6 +104,11 @@ add_task(function* testPageActionPopup() {
});
browser.test.onMessage.addListener((msg) => {
if (msg == "close-popup") {
browser.runtime.sendMessage("close-popup");
return;
}
if (msg != "next-test") {
browser.test.fail("Expecting 'next-test' message");
}
@ -118,12 +138,22 @@ add_task(function* testPageActionPopup() {
clickPageAction(extension);
});
extension.onMessage("next-test", Task.async(function* () {
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
let panel = document.getElementById(panelId);
if (panel) {
if (expecting.expectClosed) {
ok(panel, "Expect panel to exist");
yield promisePopupShown(panel);
extension.sendMessage("close-popup");
yield promisePopupHidden(panel);
ok(true, `Panel is closed`);
} else if (panel) {
yield promisePopupShown(panel);
panel.hidePopup();
}
if (panel) {
panel = document.getElementById(panelId);
is(panel, null, "panel successfully removed from document after hiding");
}

View File

@ -138,6 +138,9 @@ add_task(function* testWebNavigationFrames() {
is(getAllFramesDetails.length, collectedDetails.length,
"number of frames found should equal the number onCompleted events collected");
is(getAllFramesDetails[0].frameId, 0, "the root frame has the expected frameId");
is(getAllFramesDetails[0].parentFrameId, -1, "the root frame has the expected parentFrameId");
// ordered by frameId
let sortByFrameId = (el1, el2) => {
let val1 = el1 ? el1.frameId : -1;

View File

@ -7,7 +7,7 @@
* clickBrowserAction clickPageAction
* getBrowserActionPopup getPageActionPopup
* closeBrowserAction closePageAction
* promisePopupShown
* promisePopupShown promisePopupHidden
*/
var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
@ -59,6 +59,16 @@ function promisePopupShown(popup) {
});
}
function promisePopupHidden(popup) {
return new Promise(resolve => {
let onPopupHidden = event => {
popup.removeEventListener("popuphidden", onPopupHidden);
resolve();
};
popup.addEventListener("popuphidden", onPopupHidden);
});
}
function getBrowserActionWidget(extension) {
return CustomizableUI.getWidget(makeWidgetId(extension.id) + "-browser-action");
}
@ -68,6 +78,8 @@ function getBrowserActionPopup(extension, win = window) {
if (group.areaType == CustomizableUI.TYPE_TOOLBAR) {
return win.document.getElementById("customizationui-widget-panel");
} else {
return win.PanelUI.panel;
}
return null;
}

View File

@ -18,6 +18,7 @@ XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
// Supported prefs and data type
const gPrefsMap = new Map([
["browser.newtabpage.remote", "bool"],
["browser.newtabpage.remote.mode", "str"],
["browser.newtabpage.enabled", "bool"],
["browser.newtabpage.enhanced", "bool"],
["browser.newtabpage.pinned", "str"],

View File

@ -0,0 +1,13 @@
/* exported MODE_CHANNEL_MAP */
"use strict";
this.EXPORTED_SYMBOLS = ["MODE_CHANNEL_MAP"];
const MODE_CHANNEL_MAP = {
"production": {origin: "https://content.cdn.mozilla.net"},
"staging": {origin: "https://content-cdn.stage.mozaws.net"},
"test": {origin: "https://example.com"},
"test2": {origin: "http://mochi.test:8888"},
"dev": {origin: "http://localhost:8888"}
};

View File

@ -5,7 +5,7 @@
*/
/* globals XPCOMUtils, NewTabPrefsProvider, Services,
Locale, UpdateUtils
Locale, UpdateUtils, MODE_CHANNEL_MAP
*/
"use strict";
@ -20,11 +20,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
"resource://gre/modules/Locale.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MODE_CHANNEL_MAP",
"resource:///modules/NewTabRemoteResources.jsm");
const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
const REMOTE_NEWTAB_URL = "https://newtab.cdn.mozilla.net/" +
"v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
const REMOTE_NEWTAB_PATH = "/v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
const ABOUT_URL = "about:newtab";
@ -37,6 +38,9 @@ const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
// The preference that tells what locale the user selected
const PREF_SELECTED_LOCALE = "general.useragent.locale";
// The preference that tells what remote mode is enabled.
const PREF_REMOTE_MODE = "browser.newtabpage.remote.mode";
const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]);
const REMOTE_NEWTAB_VERSION = "0";
@ -44,6 +48,8 @@ const REMOTE_NEWTAB_VERSION = "0";
function AboutNewTabService() {
NewTabPrefsProvider.prefs.on(PREF_REMOTE_ENABLED, this._handleToggleEvent.bind(this));
this._updateRemoteMaybe = this._updateRemoteMaybe.bind(this);
// trigger remote change if needed, according to pref
this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED));
}
@ -124,14 +130,18 @@ AboutNewTabService.prototype = {
this._remoteURL = this.generateRemoteURL();
NewTabPrefsProvider.prefs.on(
PREF_SELECTED_LOCALE,
this._updateRemoteMaybe.bind(this));
this._updateRemoteMaybe);
NewTabPrefsProvider.prefs.on(
PREF_MATCH_OS_LOCALE,
this._updateRemoteMaybe.bind(this));
this._updateRemoteMaybe);
NewTabPrefsProvider.prefs.on(
PREF_REMOTE_MODE,
this._updateRemoteMaybe);
this._remoteEnabled = true;
} else {
NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateRemoteMaybe);
NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateRemoteMaybe);
NewTabPrefsProvider.prefs.off(PREF_REMOTE_MODE, this._updateRemoteMaybe);
this._remoteEnabled = false;
}
this._newTabURL = ABOUT_URL;
@ -139,15 +149,19 @@ AboutNewTabService.prototype = {
},
/*
* Generate a default url based on locale and update channel
* Generate a default url based on remote mode, version, locale and update channel
*/
generateRemoteURL() {
let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
let url = REMOTE_NEWTAB_URL
let path = REMOTE_NEWTAB_PATH
.replace("%VERSION%", REMOTE_NEWTAB_VERSION)
.replace("%LOCALE%", Locale.getLocale())
.replace("%CHANNEL%", releaseName);
return url;
let mode = Services.prefs.getCharPref(PREF_REMOTE_MODE, "production");
if (!(mode in MODE_CHANNEL_MAP)) {
mode = "production";
}
return MODE_CHANNEL_MAP[mode].origin + path;
},
/*

View File

@ -12,6 +12,7 @@ XPCSHELL_TESTS_MANIFESTS += [
EXTRA_JS_MODULES += [
'NewTabPrefsProvider.jsm',
'NewTabRemoteResources.jsm',
'NewTabURL.jsm',
'PlacesProvider.jsm'
]

View File

@ -105,13 +105,16 @@ add_task(function* test_updates() {
Preferences.set("browser.newtabpage.remote", true);
aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off
let notificationPromise;
let expectedHref = "https://newtab.cdn.mozilla.net" +
`/v${aboutNewTabService.remoteVersion}` +
let productionModeBaseUrl = "https://content.cdn.mozilla.net";
let testModeBaseUrl = "https://example.com";
let expectedPath = `/v${aboutNewTabService.remoteVersion}` +
`/${aboutNewTabService.remoteReleaseName}` +
"/en-GB" +
"/index.html";
let expectedHref = productionModeBaseUrl + expectedPath;
Preferences.set("intl.locale.matchOS", true);
Preferences.set("general.useragent.locale", "en-GB");
Preferences.set("browser.newtabpage.remote.mode", "production");
NewTabPrefsProvider.prefs.init();
// test update checks for prefs
@ -123,7 +126,19 @@ add_task(function* test_updates() {
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "Remote href changes back to default");
Preferences.set("general.useragent.locale", "en-US");
yield notificationPromise;
// test update fires when mode is changed
expectedPath = expectedPath.replace("/en-GB/", "/en-US/");
notificationPromise = nextChangeNotificationPromise(
testModeBaseUrl + expectedPath, "Remote href changes back to origin of test mode");
Preferences.set("browser.newtabpage.remote.mode", "test");
yield notificationPromise;
// test invalid mode ends up pointing to production url
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "Remote href changes back to production default");
Preferences.set("browser.newtabpage.remote.mode", "invalid");
yield notificationPromise;
// test update fires on override and reset

View File

@ -46,7 +46,6 @@ skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be th
[browser_library_search.js]
[browser_library_views_liveupdate.js]
[browser_markPageAsFollowedLink.js]
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly (test does EventUtils.sendMouseEvent...)
[browser_sidebarpanels_click.js]
skip-if = true # temporarily disabled for breaking the treeview - bug 658744
[browser_sort_in_library.js]

View File

@ -1,7 +1,3 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Tests that visits across frames are correctly represented in the database.
*/
@ -11,76 +7,61 @@ const PAGE_URL = BASE_URL + "/framedPage.html";
const LEFT_URL = BASE_URL + "/frameLeft.html";
const RIGHT_URL = BASE_URL + "/frameRight.html";
var gTabLoaded = false;
var gLeftFrameVisited = false;
add_task(function* test() {
// We must wait for both frames to be loaded and the visits to be registered.
let deferredLeftFrameVisit = PromiseUtils.defer();
let deferredRightFrameVisit = PromiseUtils.defer();
var observer = {
observe: function(aSubject, aTopic, aData)
{
let url = aSubject.QueryInterface(Ci.nsIURI).spec;
if (url == LEFT_URL ) {
is(getTransitionForUrl(url), null,
"Embed visits should not get a database entry.");
gLeftFrameVisited = true;
maybeClickLink();
}
else if (url == RIGHT_URL ) {
is(getTransitionForUrl(url), PlacesUtils.history.TRANSITION_FRAMED_LINK,
"User activated visits should get a FRAMED_LINK transition.");
finish();
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
Services.obs.addObserver(observer, "uri-visit-saved", false);
Services.obs.addObserver(function observe(subject) {
Task.spawn(function* () {
let url = subject.QueryInterface(Ci.nsIURI).spec;
if (url == LEFT_URL ) {
is((yield getTransitionForUrl(url)), null,
"Embed visits should not get a database entry.");
deferredLeftFrameVisit.resolve();
}
else if (url == RIGHT_URL ) {
is((yield getTransitionForUrl(url)),
PlacesUtils.history.TRANSITION_FRAMED_LINK,
"User activated visits should get a FRAMED_LINK transition.");
Services.obs.removeObserver(observe, "uri-visit-saved");
deferredRightFrameVisit.resolve();
}
});
}, "uri-visit-saved", false);
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab(PAGE_URL);
let frameCount = 0;
gBrowser.selectedBrowser.addEventListener("DOMContentLoaded",
function (event)
{
// Wait for all the frames.
if (frameCount++ < 2)
return;
gBrowser.selectedBrowser.removeEventListener("DOMContentLoaded", arguments.callee, false)
gTabLoaded = true;
maybeClickLink();
}, false
);
}
// Open a tab and wait for all the subframes to load.
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE_URL);
function maybeClickLink() {
if (gTabLoaded && gLeftFrameVisited) {
// Click on the link in the left frame to cause a page load in the
// right frame.
EventUtils.sendMouseEvent({type: "click"}, "clickme", content.frames[0]);
// Wait for the left frame visit to be registered.
info("Waiting left frame visit");
yield deferredLeftFrameVisit.promise;
// Click on the link in the left frame to cause a page load in the
// right frame.
info("Clicking link");
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
content.frames[0].document.getElementById("clickme").click();
});
// Wait for the right frame visit to be registered.
info("Waiting right frame visit");
yield deferredRightFrameVisit.promise;
yield BrowserTestUtils.removeTab(tab);
});
function* getTransitionForUrl(url) {
// Ensure all the transactions completed.
yield PlacesTestUtils.promiseAsyncUpdates();
let db = yield PlacesUtils.promiseDBConnection();
let rows = yield db.execute(`
SELECT visit_type
FROM moz_historyvisits
WHERE place_id = (SELECT id FROM moz_places WHERE url = :url)`,
{ url });
if (rows.length) {
return rows[0].getResultByName("visit_type");
}
return null;
}
function getTransitionForUrl(aUrl)
{
let dbConn = PlacesUtils.history
.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
let stmt = dbConn.createStatement(
"SELECT visit_type FROM moz_historyvisits WHERE place_id = " +
"(SELECT id FROM moz_places WHERE url = :page_url)");
stmt.params.page_url = aUrl;
try {
if (!stmt.executeStep()) {
return null;
}
return stmt.row.visit_type;
}
finally {
stmt.finalize();
}
}
registerCleanupFunction(function ()
{
gBrowser.removeTab(gBrowser.selectedTab);
Services.obs.removeObserver(observer, "uri-visit-saved");
})

View File

@ -145,6 +145,10 @@ var SessionHistoryInternal = {
entry.originalURI = shEntry.originalURI.spec;
}
if (shEntry.loadReplace) {
entry.loadReplace = shEntry.loadReplace;
}
if (shEntry.srcdocData)
entry.srcdocData = shEntry.srcdocData;
@ -316,6 +320,9 @@ var SessionHistoryInternal = {
if (entry.originalURI) {
shEntry.originalURI = Utils.makeURI(entry.originalURI);
}
if (entry.loadReplace) {
shEntry.loadReplace = entry.loadReplace;
}
if (entry.isSrcdocEntry)
shEntry.srcdocData = entry.srcdocData;
if (entry.baseURI)

View File

@ -13,6 +13,28 @@ distribution.test.string.noquotes=Test String
distribution.test.int=777
distribution.test.bool.true=true
distribution.test.bool.false=false
distribution.test.empty=
distribution.test.pref.locale="%LOCALE%"
distribution.test.pref.language.reset="Preference Set"
distribution.test.pref.locale.reset="Preference Set"
distribution.test.pref.locale.set="Preference Set"
distribution.test.pref.language.set="Preference Set"
[Preferences-en]
distribution.test.pref.language.en="en"
distribution.test.pref.language.reset=
distribution.test.pref.language.set="Language Set"
distribution.test.pref.locale.set="Language Set"
[Preferences-en-US]
distribution.test.pref.locale.en-US="en-US"
distribution.test.pref.locale.reset=
distribution.test.pref.locale.set="Locale Set"
[Preferences-de]
distribution.test.pref.language.de="de"
[LocalizablePreferences]
distribution.test.locale="%LOCALE%"
@ -33,4 +55,4 @@ distribution.test.locale.reset=
distribution.test.locale.set="Locale Set"
[LocalizablePreferences-de]
distribution.test.locale.de="de"
distribution.test.language.de="de"

View File

@ -71,10 +71,30 @@ add_task(function* () {
Assert.equal(Services.prefs.getIntPref("distribution.test.int"), 777);
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.true"), true);
Assert.equal(Services.prefs.getBoolPref("distribution.test.bool.false"), false);
Assert.throws(() => Services.prefs.getCharPref("distribution.test.empty"));
Assert.throws(() => Services.prefs.getIntPref("distribution.test.empty"));
Assert.throws(() => Services.prefs.getBoolPref("distribution.test.empty"));
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale"), "en-US");
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.en"), "en");
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.en-US"), "en-US");
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.de"));
// This value was never set because of the empty language specific pref
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.language.reset"));
// This value was never set because of the empty locale specific pref
Assert.throws(() => Services.prefs.getCharPref("distribution.test.pref.locale.reset"));
// This value was overridden by a locale specific setting
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Locale Set");
// This value was overridden by a language specific setting
Assert.equal(Services.prefs.getCharPref("distribution.test.pref.language.set"), "Language Set");
// Language should not override locale
Assert.notEqual(Services.prefs.getCharPref("distribution.test.pref.locale.set"), "Language Set");
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale", Ci.nsIPrefLocalizedString).data, "en-US");
Assert.equal(Services.prefs.getComplexValue("distribution.test.language.en", Ci.nsIPrefLocalizedString).data, "en");
Assert.equal(Services.prefs.getComplexValue("distribution.test.locale.en-US", Ci.nsIPrefLocalizedString).data, "en-US");
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.locale.de", Ci.nsIPrefLocalizedString));
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.de", Ci.nsIPrefLocalizedString));
// This value was never set because of the empty language specific pref
Assert.throws(() => Services.prefs.getComplexValue("distribution.test.language.reset", Ci.nsIPrefLocalizedString));
// This value was never set because of the empty locale specific pref

View File

@ -61,6 +61,15 @@ var ContentClick = {
// Note: We don't need the sidebar code here.
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
if (!PrivateBrowsingUtils.isWindowPrivate(window))
PlacesUIUtils.markPageAsFollowedLink(json.href);
} catch (ex) { /* Skip invalid URIs. */ }
// This part is based on handleLinkClick.
var where = window.whereToOpenLink(json);
if (where == "current")
@ -73,14 +82,5 @@ var ContentClick = {
referrerPolicy: json.referrerPolicy,
noReferrer: json.noReferrer };
window.openLinkIn(json.href, where, params);
// Mark the page as a user followed link. This is done so that history can
// distinguish automatic embed visits from user activated ones. For example
// pages loaded in frames are embed visits and lost with the session, while
// visits across frames should be preserved.
try {
if (!PrivateBrowsingUtils.isWindowPrivate(window))
PlacesUIUtils.markPageAsFollowedLink(json.href);
} catch (ex) { /* Skip invalid URIs. */ }
}
};

View File

@ -17,6 +17,15 @@
@hudButtonFocused@
}
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
border-bottom-right-radius: 3.5px;
}
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 3.5px;
}
#tracking-action-block,
#tracking-action-unblock,
#tracking-action-unblock-private,

View File

@ -83,15 +83,9 @@
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews {
background: var(--panel-arrowcontent-background);
border-bottom-right-radius: 3.5px;
padding: 0;
}
#identity-popup-multiView > .panel-viewcontainer > .panel-viewstack > .panel-subviews:-moz-locale-dir(rtl) {
border-bottom-right-radius: 0;
border-bottom-left-radius: 3.5px;
}
.identity-popup-section:not(:first-child) {
border-top: 1px solid var(--panel-separator-color);
}
@ -100,14 +94,19 @@
#identity-popup-security-content,
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.5em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
background-repeat: no-repeat;
background-position: 1em 1em;
background-size: 24px auto;
}
#identity-popup-security-content,
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.5em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
}
#identity-popup-securityView:-moz-locale-dir(rtl),
#identity-popup-security-content:-moz-locale-dir(rtl),
#identity-popup-permissions-content:-moz-locale-dir(rtl),
@ -208,7 +207,6 @@
}
#identity-popup-securityView {
padding-bottom: 2em;
overflow: hidden;
}
@ -252,7 +250,14 @@
color: Graytext;
}
#identity-popup-securityView-header,
#identity-popup-securityView-body {
-moz-margin-start: calc(2em + 24px);
-moz-margin-end: 1em;
}
#identity-popup-securityView-header {
margin-top: 0.5em;
border-bottom: 1px solid var(--panel-separator-color);
padding-bottom: 1em;
}
@ -261,6 +266,30 @@
-moz-padding-end: 1em;
}
#identity-popup-securityView-footer {
margin-top: 1em;
background-color: hsla(210,4%,10%,.07);
}
#identity-popup-securityView-footer > button {
-moz-appearance: none;
margin: 0;
border: none;
border-top: 1px solid #ccc;
padding: 8px 20px;
color: ButtonText;
background-color: transparent;
}
#identity-popup-securityView-footer > button:hover,
#identity-popup-securityView-footer > button:focus {
background-color: hsla(210,4%,10%,.07);
}
#identity-popup-securityView-footer > button:hover:active {
background-color: hsla(210,4%,10%,.12);
}
#identity-popup-content-verifier ~ description {
margin-top: 1em;
color: Graytext;

View File

@ -36,7 +36,7 @@ PrincipalOriginAttributes::InheritFromDocShellToDoc(const DocShellOriginAttribut
const nsIURI* aURI)
{
mAppId = aAttrs.mAppId;
mInBrowser = aAttrs.mInBrowser;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
// addonId is computed from the principal URI and never propagated
mUserContextId = aAttrs.mUserContextId;
@ -51,7 +51,7 @@ void
PrincipalOriginAttributes::InheritFromNecko(const NeckoOriginAttributes& aAttrs)
{
mAppId = aAttrs.mAppId;
mInBrowser = aAttrs.mInBrowser;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
// addonId is computed from the principal URI and never propagated
mUserContextId = aAttrs.mUserContextId;
@ -62,7 +62,7 @@ void
DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAttributes& aAttrs)
{
mAppId = aAttrs.mAppId;
mInBrowser = aAttrs.mInBrowser;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
// addonId is computed from the principal URI and never propagated
mUserContextId = aAttrs.mUserContextId;
@ -77,7 +77,7 @@ void
NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs)
{
mAppId = aAttrs.mAppId;
mInBrowser = aAttrs.mInBrowser;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
// addonId is computed from the principal URI and never propagated
mUserContextId = aAttrs.mUserContextId;
@ -91,7 +91,7 @@ void
NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs)
{
mAppId = aAttrs.mAppId;
mInBrowser = aAttrs.mInBrowser;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
// addonId is computed from the principal URI and never propagated
mUserContextId = aAttrs.mUserContextId;
@ -119,7 +119,7 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
params->Set(NS_LITERAL_STRING("appId"), value);
}
if (mInBrowser) {
if (mInIsolatedMozBrowser) {
params->Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
}
@ -191,7 +191,7 @@ public:
return false;
}
mOriginAttributes->mInBrowser = true;
mOriginAttributes->mInIsolatedMozBrowser = true;
return true;
}
@ -469,7 +469,7 @@ BasePrincipal::GetIsSystemPrincipal(bool* aResult)
NS_IMETHODIMP
BasePrincipal::GetJarPrefix(nsACString& aJarPrefix)
{
mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInBrowser, aJarPrefix);
mozilla::GetJarPrefix(mOriginAttributes.mAppId, mOriginAttributes.mInIsolatedMozBrowser, aJarPrefix);
return NS_OK;
}
@ -523,9 +523,9 @@ BasePrincipal::GetUserContextId(uint32_t* aUserContextId)
}
NS_IMETHODIMP
BasePrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
BasePrincipal::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
{
*aIsInBrowserElement = IsInBrowserElement();
*aIsInIsolatedMozBrowserElement = IsInIsolatedMozBrowserElement();
return NS_OK;
}

View File

@ -30,7 +30,7 @@ public:
bool operator==(const OriginAttributes& aOther) const
{
return mAppId == aOther.mAppId &&
mInBrowser == aOther.mInBrowser &&
mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser &&
mAddonId == aOther.mAddonId &&
mUserContextId == aOther.mUserContextId &&
mSignedPkg == aOther.mSignedPkg;
@ -75,10 +75,10 @@ class PrincipalOriginAttributes : public OriginAttributes
{
public:
PrincipalOriginAttributes() {}
PrincipalOriginAttributes(uint32_t aAppId, bool aInBrowser)
PrincipalOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
{
mAppId = aAppId;
mInBrowser = aInBrowser;
mInIsolatedMozBrowser = aInIsolatedMozBrowser;
}
// Inheriting OriginAttributes from docshell to document when user navigates.
@ -97,10 +97,10 @@ class DocShellOriginAttributes : public OriginAttributes
{
public:
DocShellOriginAttributes() {}
DocShellOriginAttributes(uint32_t aAppId, bool aInBrowser)
DocShellOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
{
mAppId = aAppId;
mInBrowser = aInBrowser;
mInIsolatedMozBrowser = aInIsolatedMozBrowser;
}
// Inheriting OriginAttributes from document to child docshell when an
@ -116,10 +116,10 @@ class NeckoOriginAttributes : public OriginAttributes
{
public:
NeckoOriginAttributes() {}
NeckoOriginAttributes(uint32_t aAppId, bool aInBrowser)
NeckoOriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser)
{
mAppId = aAppId;
mInBrowser = aInBrowser;
mInIsolatedMozBrowser = aInIsolatedMozBrowser;
}
// Inheriting OriginAttributes from document to necko when a network request
@ -159,7 +159,7 @@ public:
return false;
}
if (mInBrowser.WasPassed() && mInBrowser.Value() != aAttrs.mInBrowser) {
if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) {
return false;
}
@ -215,7 +215,7 @@ public:
NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
NS_IMETHOD GetAppStatus(uint16_t* aAppStatus) final;
NS_IMETHOD GetAppId(uint32_t* aAppStatus) final;
NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement) final;
NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) final;
NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
@ -231,7 +231,7 @@ public:
const PrincipalOriginAttributes& OriginAttributesRef() { return mOriginAttributes; }
uint32_t AppId() const { return mOriginAttributes.mAppId; }
uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
bool IsInBrowserElement() const { return mOriginAttributes.mInBrowser; }
bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
enum PrincipalKind {
eNullPrincipal,

View File

@ -303,10 +303,13 @@ interface nsIPrincipal : nsISerializable
[infallible] readonly attribute unsigned long userContextId;
/**
* Returns true iff the principal is inside a browser element. (<iframe
* mozbrowser mozapp> does not count as a browser element.)
* Returns true iff the principal is inside an isolated mozbrowser element.
* <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
* mozbrowser elements. <iframe mozbrowser noisolation> does not count as
* isolated since isolation is disabled. Isolation can only be disabled if
* the containing document is chrome.
*/
[infallible] readonly attribute boolean isInBrowserElement;
[infallible] readonly attribute boolean isInIsolatedMozBrowserElement;
/**
* Returns true if this principal has an unknown appId. This shouldn't

View File

@ -260,13 +260,25 @@ uint16_t
nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
{
uint32_t appId = aPrin->GetAppId();
bool inMozBrowser = aPrin->GetIsInBrowserElement();
// After bug 1238160, the principal no longer knows how to answer "is this a
// browser element", which is really what this code path wants. Currently,
// desktop is the only platform where we intend to disable isolation on a
// browser frame, so non-desktop should be able to assume that
// inIsolatedMozBrowser is true for all mozbrowser frames. Additionally,
// apps are no longer used on desktop, so appId is always NO_APP_ID. We use
// a release assertion in nsFrameLoader::OwnerIsIsolatedMozBrowserFrame so
// that platforms with apps can assume inIsolatedMozBrowser is true for all
// mozbrowser frames.
bool inIsolatedMozBrowser = aPrin->GetIsInIsolatedMozBrowserElement();
NS_WARN_IF_FALSE(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Asking for app status on a principal with an unknown app id");
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
// and they are not inside a mozbrowser.
if (appId == nsIScriptSecurityManager::NO_APP_ID ||
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID || inMozBrowser)
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID ||
inIsolatedMozBrowser)
{
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
@ -291,7 +303,7 @@ nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
// The app could contain a cross-origin iframe - make sure that the content
// is actually same-origin with the app.
MOZ_ASSERT(inMozBrowser == false, "Checked this above");
MOZ_ASSERT(inIsolatedMozBrowser == false, "Checked this above");
PrincipalOriginAttributes attrs(appId, false);
nsCOMPtr<nsIPrincipal> appPrin = BasePrincipal::CreateCodebasePrincipal(appURI, attrs);
NS_ENSURE_TRUE(appPrin, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
@ -590,7 +602,7 @@ static nsresult
DenyAccessIfURIHasFlags(nsIURI* aURI, uint32_t aURIFlags)
{
NS_PRECONDITION(aURI, "Must have URI!");
bool uriHasFlags;
nsresult rv =
NS_URIChainHasFlags(aURI, aURIFlags, &uriHasFlags);
@ -724,7 +736,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
"must have a URI!");
return NS_ERROR_UNEXPECTED;
}
// Automatic loads are not allowed from certain protocols.
if (aFlags & nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT) {
nsresult rv =
@ -958,7 +970,7 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
console->LogStringMessage(message.get());
}
}
return NS_OK;
}
@ -1170,13 +1182,13 @@ nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray,
NS_IMETHODIMP
nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
uint32_t aAppId,
bool aInMozBrowser,
bool aInIsolatedMozBrowser,
nsIPrincipal** aPrincipal)
{
NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
NS_ERROR_INVALID_ARG);
PrincipalOriginAttributes attrs(aAppId, aInMozBrowser);
PrincipalOriginAttributes attrs(aAppId, aInIsolatedMozBrowser);
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
prin.forget(aPrincipal);
return *aPrincipal ? NS_OK : NS_ERROR_FAILURE;
@ -1566,7 +1578,7 @@ nsScriptSecurityManager::InitPrefs()
namespace mozilla {
void
GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
GetJarPrefix(uint32_t aAppId, bool aInIsolatedMozBrowser, nsACString& aJarPrefix)
{
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
@ -1577,14 +1589,14 @@ GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
aJarPrefix.Truncate();
// Fallback.
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInIsolatedMozBrowser) {
return;
}
// aJarPrefix = appId + "+" + { 't', 'f' } + "+";
aJarPrefix.AppendInt(aAppId);
aJarPrefix.Append('+');
aJarPrefix.Append(aInMozBrowser ? 't' : 'f');
aJarPrefix.Append(aInIsolatedMozBrowser ? 't' : 'f');
aJarPrefix.Append('+');
return;
@ -1594,12 +1606,12 @@ GetJarPrefix(uint32_t aAppId, bool aInMozBrowser, nsACString& aJarPrefix)
NS_IMETHODIMP
nsScriptSecurityManager::GetJarPrefix(uint32_t aAppId,
bool aInMozBrowser,
bool aInIsolatedMozBrowser,
nsACString& aJarPrefix)
{
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mozilla::GetJarPrefix(aAppId, aInMozBrowser, aJarPrefix);
mozilla::GetJarPrefix(aAppId, aInIsolatedMozBrowser, aJarPrefix);
return NS_OK;
}
@ -1694,4 +1706,3 @@ nsScriptSecurityManager::PolicyAllowsScript(nsIURI* aURI, bool *aRv)
return NS_OK;
}

View File

@ -151,7 +151,7 @@ namespace mozilla {
void
GetJarPrefix(uint32_t aAppid,
bool aInMozBrowser,
bool aInIsolatedMozBrowser,
nsACString& aJarPrefix);
} // namespace mozilla

View File

@ -24,13 +24,13 @@ TEST(PrincipalOriginAttributes, Suffix_default)
TestSuffix(attrs);
}
TEST(PrincipalOriginAttributes, Suffix_appId_inBrowser)
TEST(PrincipalOriginAttributes, Suffix_appId_inIsolatedMozBrowser)
{
PrincipalOriginAttributes attrs(1, true);
TestSuffix(attrs);
}
TEST(PrincipalOriginAttributes, Suffix_maxAppId_inBrowser)
TEST(PrincipalOriginAttributes, Suffix_maxAppId_inIsolatedMozBrowser)
{
PrincipalOriginAttributes attrs(4294967295, true);
TestSuffix(attrs);

View File

@ -33,6 +33,8 @@ SimpleTest.waitForExplicitFinish();
* valid, the iframe will not be considered as a mozapp.
* - browser: say if the iframe should be a mozbrowser. This is implicit when
* app is set.
* - isolated: if origin isolation is enabled with browser frames. Defaults to
* true if unset.
* - test: an array of tests to run for this test case:
* - eo-unique: the extendedOrigin of the prinicpal must be unique in the
* current list.
@ -230,7 +232,7 @@ var gData = [
},
test: [ "child-has-different-eo", "child-has-same-appstatus", "child-has-same-appid" ],
},
// browser containing an iframe is part of the browser
// browser containing an iframe that is part of the browser
{
src: "http://example.org/",
isapp: false,
@ -238,7 +240,50 @@ var gData = [
child: {
src: "http://example.org/chrome/",
isapp: false,
inBrowser: true,
inIsolatedMozBrowser: true,
},
test: [ "child-has-same-eo" ],
},
// iframe containing a browser with isolation disabled
// (only chrome documents can disable isolation)
{
src: "http://example.org/",
isapp: false,
browser: false,
child: {
src: "http://example.org/chrome/",
isapp: false,
browser: true,
isolated: false,
inIsolatedMozBrowser: true,
},
test: [ "child-has-different-eo" ],
},
// browser with isolation disabled containing an iframe that is part of the browser
{
src: "http://example.org/",
isapp: false,
browser: true,
isolated: false,
child: {
src: "http://example.org/chrome/",
isapp: false,
inIsolatedMozBrowser: false,
},
test: [ "child-has-same-eo" ],
},
// iframe with isolation enabled containing an iframe with isolation disabled
// (isolated only has an effect on browsers)
{
src: "http://example.org/",
isapp: false,
browser: false,
isolated: true,
child: {
src: "http://example.org/chrome/",
isapp: false,
browser: false,
isolated: false,
},
test: [ "child-has-same-eo" ],
},
@ -280,12 +325,15 @@ function checkIFrame(aFrame, data) {
"principals from non-installed app should have NO_APP_ID");
}
if (!data.isapp && !data.browser) {
if (!data.isapp && !data.browser ||
(data.browser && data.isolated === false)) {
is(principal.jarPrefix, "",
'jarPrefix should return an empty string for non-app and non-browsers principals');
"jarPrefix should return an empty string for non-app, non-browsers, " +
"and browsers with isolation disabled");
} else {
isnot(principal.jarPrefix, "",
'jarPrefix should not return an empty string for apps or mozbrowsers');
"jarPrefix should not return an empty string for apps or browsers " +
"with isolation enabled");
}
if (data.test.indexOf("eo-unique") != -1) {
@ -297,8 +345,12 @@ function checkIFrame(aFrame, data) {
"extended origin should be the same as the last inserted one");
}
is(principal.isInBrowserElement, !!data.browser,
"check principal.isInBrowserElement");
let isolationExpected = false;
if (data.isolated !== false) {
isolationExpected = !!data.browser;
}
is(principal.isInIsolatedMozBrowserElement, isolationExpected,
"check principal.isInIsolatedMozBrowserElement");
if (data.child) {
let childPrincipal = aFrame.contentWindow.frames[0].document.nodePrincipal;
@ -308,8 +360,15 @@ function checkIFrame(aFrame, data) {
"child should be an installed app");
}
is(childPrincipal.isInBrowserElement, !!data.child.browser || !!data.child.inBrowser,
"check childPrincipal.isInBrowserElement");
let childIsolationExpected = false;
if (data.child.isolated !== false) {
childIsolationExpected = !!data.child.browser;
}
if (data.child.inIsolatedMozBrowser !== undefined) {
childIsolationExpected = data.child.inIsolatedMozBrowser;
}
is(childPrincipal.isInIsolatedMozBrowserElement, childIsolationExpected,
"check childPrincipal.isInIsolatedMozBrowserElement");
if (data.test.indexOf("child-has-same-eo") != -1) {
is(childPrincipal.jarPrefix + childPrincipal.origin,
@ -392,6 +451,10 @@ function runTest() {
childFrame.setAttribute('mozbrowser', '');
}
if (data.child.isolated === false) {
childFrame.setAttribute("noisolation", "");
}
childFrame.src = data.child.src;
this.removeEventListener('load', this.addChild.bind(this));
@ -407,6 +470,10 @@ function runTest() {
iframe.setAttribute('mozbrowser', '');
}
if (data.isolated === false) {
iframe.setAttribute("noisolation", "");
}
iframe.src = data.src;
if (data.child) {
@ -423,8 +490,9 @@ function runTest() {
var gTestRunner = runTest();
SpecialPowers.pushPrefEnv({'set':[["dom.mozBrowserFramesEnabled", true]]},
function() { gTestRunner.next(); });
SpecialPowers.pushPrefEnv({"set": [
["dom.mozBrowserFramesEnabled", true],
]}, function() { gTestRunner.next(); });
</script>
</pre>

View File

@ -24,7 +24,7 @@ function checkCrossOrigin(a, b) {
function checkOriginAttributes(prin, attrs, suffix) {
attrs = attrs || {};
do_check_eq(prin.originAttributes.appId, attrs.appId || 0);
do_check_eq(prin.originAttributes.inBrowser, attrs.inBrowser || false);
do_check_eq(prin.originAttributes.inIsolatedMozBrowser, attrs.inIsolatedMozBrowser || false);
do_check_eq(prin.originSuffix, suffix || '');
do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), suffix || '');
do_check_true(ChromeUtils.originAttributesMatchPattern(prin.originAttributes, attrs));
@ -40,7 +40,7 @@ function printAttrs(name, attrs) {
do_print(name + " {\n" +
"\tappId: " + attrs.appId + ",\n" +
"\tuserContextId: " + attrs.userContextId + ",\n" +
"\tinBrowser: " + attrs.inBrowser + ",\n" +
"\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" +
"\taddonId: '" + attrs.addonId + "',\n" +
"\tsignedPkg: '" + attrs.signedPkg + "'\n}");
}
@ -52,7 +52,7 @@ function checkValues(attrs, values) {
//printAttrs("values", values);
do_check_eq(attrs.appId, values.appId || 0);
do_check_eq(attrs.userContextId, values.userContextId || 0);
do_check_eq(attrs.inBrowser, values.inBrowser || false);
do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false);
do_check_eq(attrs.addonId, values.addonId || '');
do_check_eq(attrs.signedPkg, values.signedPkg || '');
}
@ -99,22 +99,22 @@ function run_test() {
do_check_eq(exampleOrg_app.origin, 'http://example.org^appId=42');
// Just browser.
var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true});
var nullPrin_browser = ssm.createNullPrincipal({inBrowser: true});
checkOriginAttributes(exampleOrg_browser, {inBrowser: true}, '^inBrowser=1');
checkOriginAttributes(nullPrin_browser, {inBrowser: true}, '^inBrowser=1');
var exampleOrg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true});
var nullPrin_browser = ssm.createNullPrincipal({inIsolatedMozBrowser: true});
checkOriginAttributes(exampleOrg_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1');
checkOriginAttributes(nullPrin_browser, {inIsolatedMozBrowser: true}, '^inBrowser=1');
do_check_eq(exampleOrg_browser.origin, 'http://example.org^inBrowser=1');
// App and browser.
var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inBrowser: true, appId: 42});
var nullPrin_appBrowser = ssm.createNullPrincipal({inBrowser: true, appId: 42});
checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
var exampleOrg_appBrowser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {inIsolatedMozBrowser: true, appId: 42});
var nullPrin_appBrowser = ssm.createNullPrincipal({inIsolatedMozBrowser: true, appId: 42});
checkOriginAttributes(exampleOrg_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
checkOriginAttributes(nullPrin_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
do_check_eq(exampleOrg_appBrowser.origin, 'http://example.org^appId=42&inBrowser=1');
// App and browser, different domain.
var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inBrowser: true});
checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inBrowser: true}, '^appId=42&inBrowser=1');
var exampleCom_appBrowser = ssm.createCodebasePrincipal(makeURI('https://www.example.com:123'), {appId: 42, inIsolatedMozBrowser: true});
checkOriginAttributes(exampleCom_appBrowser, {appId: 42, inIsolatedMozBrowser: true}, '^appId=42&inBrowser=1');
do_check_eq(exampleCom_appBrowser.origin, 'https://www.example.com:123^appId=42&inBrowser=1');
// Addon.
@ -161,8 +161,8 @@ function run_test() {
do_check_eq(exampleOrg_signedPkg.origin, 'http://example.org^signedPkg=whatever');
// signedPkg and browser
var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inBrowser: true});
checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inBrowser: true }, '^inBrowser=1&signedPkg=whatever');
var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inIsolatedMozBrowser: true});
checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inIsolatedMozBrowser: true }, '^inBrowser=1&signedPkg=whatever');
do_check_eq(exampleOrg_signedPkg_browser.origin, 'http://example.org^inBrowser=1&signedPkg=whatever');
// Just signedPkg (but different value from 'exampleOrg_signedPkg_app')
@ -212,10 +212,10 @@ function run_test() {
[ "^appId=5", {appId: 5} ],
[ "^userContextId=3", {userContextId: 3} ],
[ "^addonId=fooBar", {addonId: "fooBar"} ],
[ "^inBrowser=1", {inBrowser: true} ],
[ "^inBrowser=1", {inIsolatedMozBrowser: true} ],
[ "^signedPkg=bazQux", {signedPkg: "bazQux"} ],
[ "^appId=3&inBrowser=1&userContextId=6",
{appId: 3, userContextId: 6, inBrowser: true} ] ];
{appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ];
// check that we can create an origin attributes from an origin properly
tests.forEach(function(t) {

13
devtools/bootstrap.js vendored
View File

@ -8,6 +8,13 @@ const Cu = Components.utils;
const Ci = Components.interfaces;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
function actionOccurred(id) {
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let Telemetry = require("devtools/client/shared/telemetry");;
let telemetry = new Telemetry();
telemetry.actionOccurred(id);
}
// Helper to listen to a key on all windows
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
let keyListener = function (event) {
@ -150,6 +157,8 @@ function reload(event) {
gDevTools.showToolbox(target);
}, 1000);
}
actionOccurred("reloadAddonReload");
}
let listener;
@ -165,5 +174,7 @@ function shutdown() {
listener.stop();
listener = null;
}
function install() {}
function install() {
actionOccurred("reloadAddonInstalled");
}
function uninstall() {}

View File

@ -82,7 +82,10 @@ const EVENTS = {
OPTIONS_POPUP_HIDDEN: "Debugger:OptionsPopupHidden",
// When the widgets layout has been changed.
LAYOUT_CHANGED: "Debugger:LayoutChanged"
LAYOUT_CHANGED: "Debugger:LayoutChanged",
// When a worker has been selected.
WORKER_SELECTED: "Debugger::WorkerSelected"
};
// Descriptions for what a stack frame represents after the debugger pauses.
@ -108,7 +111,7 @@ Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
var L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
Cu.import("resource://devtools/client/shared/browser-loader.js");
const require = BrowserLoader("resource://devtools/client/debugger/", this).require;
const require = BrowserLoader("resource://devtools/client/debugger/", window).require;
XPCOMUtils.defineConstant(this, "require", require);
const { gDevTools } = require("devtools/client/framework/devtools");
@ -491,8 +494,8 @@ Workers.prototype = {
for (let workerActor in this._workerForms) {
if (!(workerActor in workerForms)) {
DebuggerView.Workers.removeWorker(this._workerForms[workerActor]);
delete this._workerForms[workerActor];
DebuggerView.Workers.removeWorker(workerActor);
}
}
@ -500,7 +503,7 @@ Workers.prototype = {
if (!(workerActor in this._workerForms)) {
let workerForm = workerForms[workerActor];
this._workerForms[workerActor] = workerForm;
DebuggerView.Workers.addWorker(workerActor, workerForm.url);
DebuggerView.Workers.addWorker(workerForm);
}
}
});
@ -510,10 +513,11 @@ Workers.prototype = {
this._updateWorkerList();
},
_onWorkerSelect: function (workerActor) {
DebuggerController.client.attachWorker(workerActor, (response, workerClient) => {
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW);
_onWorkerSelect: function (workerForm) {
DebuggerController.client.attachWorker(workerForm.actor, (response, workerClient) => {
let toolbox = gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW);
window.emit(EVENTS.WORKER_SELECTED, toolbox);
});
}
};

View File

@ -45,6 +45,9 @@ support-files =
code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
code_worker-source-map.coffee
code_worker-source-map.js
code_worker-source-map.js.map
code_WorkerActor.attach-worker1.js
code_WorkerActor.attach-worker2.js
code_WorkerActor.attachThread-worker.js
@ -112,6 +115,7 @@ support-files =
doc_watch-expressions.html
doc_watch-expression-button.html
doc_with-frame.html
doc_worker-source-map.html
doc_WorkerActor.attach-tab1.html
doc_WorkerActor.attach-tab2.html
doc_WorkerActor.attachThread-tab.html
@ -592,6 +596,8 @@ skip-if = e10s && debug
skip-if = e10s && debug
[browser_dbg_worker-console.js]
skip-if = e10s && debug
[browser_dbg_worker-source-map.js]
skip-if = e10s && debug
[browser_dbg_worker-window.js]
skip-if = e10s && debug
[browser_dbg_WorkerActor.attach.js]

View File

@ -0,0 +1,85 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const TAB_URL = EXAMPLE_URL + "doc_worker-source-map.html";
const WORKER_URL = "code_worker-source-map.js";
const COFFEE_URL = EXAMPLE_URL + "code_worker-source-map.coffee";
function selectWorker(aPanel, aURL) {
let panelWin = aPanel.panelWin;
let promise = waitForDebuggerEvents(aPanel, panelWin.EVENTS.WORKER_SELECTED);
let Workers = panelWin.DebuggerView.Workers;
let item = Workers.getItemForAttachment((workerForm) => {
return workerForm.url === aURL;
});
Workers.selectedItem = item;
return promise;
}
function test() {
return Task.spawn(function* () {
yield pushPrefs(["devtools.debugger.workers", true]);
let [tab,, panel] = yield initDebugger(TAB_URL);
let toolbox = yield selectWorker(panel, WORKER_URL);
let workerPanel = toolbox.getCurrentPanel();
yield waitForSourceShown(workerPanel, ".coffee");
let panelWin = workerPanel.panelWin;
let Sources = panelWin.DebuggerView.Sources;
let editor = panelWin.DebuggerView.editor;
let threadClient = panelWin.gThreadClient;
isnot(Sources.selectedItem.attachment.source.url.indexOf(".coffee"), -1,
"The debugger should show the source mapped coffee source file.");
is(Sources.selectedValue.indexOf(".js"), -1,
"The debugger should not show the generated js source file.");
is(editor.getText().indexOf("isnt"), 211,
"The debugger's editor should have the coffee source source displayed.");
is(editor.getText().indexOf("function"), -1,
"The debugger's editor should not have the JS source displayed.");
yield threadClient.interrupt();
let sourceForm = getSourceForm(Sources, COFFEE_URL);
let source = threadClient.source(sourceForm);
let response = yield source.setBreakpoint({ line: 5 });
ok(!response.error,
"Should be able to set a breakpoint in a coffee source file.");
ok(!response.actualLocation,
"Should be able to set a breakpoint on line 5.");
let promise = new Promise((resolve) => {
threadClient.addOneTimeListener("paused", (event, packet) => {
is(packet.type, "paused",
"We should now be paused again.");
is(packet.why.type, "breakpoint",
"and the reason we should be paused is because we hit a breakpoint.");
// Check that we stopped at the right place, by making sure that the
// environment is in the state that we expect.
is(packet.frame.environment.bindings.variables.start.value, 0,
"'start' is 0.");
is(packet.frame.environment.bindings.variables.stop.value.type, "undefined",
"'stop' hasn't been assigned to yet.");
is(packet.frame.environment.bindings.variables.pivot.value.type, "undefined",
"'pivot' hasn't been assigned to yet.");
waitForCaretUpdated(workerPanel, 5).then(resolve);
});
});
// This will cause the breakpoint to be hit, and put us back in the
// paused state.
yield threadClient.resume();
callInTab(tab, "binary_search", [0, 2, 3, 5, 7, 10], 5);
yield promise;
yield threadClient.resume();
yield toolbox.destroy();
yield closeDebuggerAndFinish(panel);
yield popPrefs();
});
}

View File

@ -0,0 +1,22 @@
# Uses a binary search algorithm to locate a value in the specified array.
binary_search = (items, value) ->
start = 0
stop = items.length - 1
pivot = Math.floor (start + stop) / 2
while items[pivot] isnt value and start < stop
# Adjust the search area.
stop = pivot - 1 if value < items[pivot]
start = pivot + 1 if value > items[pivot]
# Recalculate the pivot.
pivot = Math.floor (stop + start) / 2
# Make sure we've found the correct value.
if items[pivot] is value then pivot else -1
self.onmessage = (event) ->
data = event.data
binary_search(data.items, data.value)

View File

@ -0,0 +1,35 @@
// Generated by CoffeeScript 1.10.0
(function() {
var binary_search;
binary_search = function(items, value) {
var pivot, start, stop;
start = 0;
stop = items.length - 1;
pivot = Math.floor((start + stop) / 2);
while (items[pivot] !== value && start < stop) {
if (value < items[pivot]) {
stop = pivot - 1;
}
if (value > items[pivot]) {
start = pivot + 1;
}
pivot = Math.floor((stop + start) / 2);
}
if (items[pivot] === value) {
return pivot;
} else {
return -1;
}
};
self.onmessage = function(event) {
console.log("EUTA");
var data;
data = event.data;
return binary_search(data.items, data.value);
};
}).call(this);
//# sourceMappingURL=code_worker-source-map.js.map

View File

@ -0,0 +1,10 @@
{
"version": 3,
"file": "code_worker-source-map.js",
"sourceRoot": "",
"sources": [
"code_worker-source-map.coffee"
],
"names": [],
"mappings": ";AACA;AAAA,MAAA;;EAAA,aAAA,GAAgB,SAAC,KAAD,EAAQ,KAAR;AAEd,QAAA;IAAA,KAAA,GAAQ;IACR,IAAA,GAAQ,KAAK,CAAC,MAAN,GAAe;IACvB,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,KAAA,GAAQ,IAAT,CAAA,GAAiB,CAA5B;AAER,WAAM,KAAM,CAAA,KAAA,CAAN,KAAkB,KAAlB,IAA4B,KAAA,GAAQ,IAA1C;MAGE,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,IAAA,GAAQ,KAAA,GAAQ,EAAhB;;MACA,IAAqB,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAnC;QAAA,KAAA,GAAQ,KAAA,GAAQ,EAAhB;;MAGA,KAAA,GAAQ,IAAI,CAAC,KAAL,CAAW,CAAC,IAAA,GAAO,KAAR,CAAA,GAAiB,CAA5B;IAPV;IAUA,IAAG,KAAM,CAAA,KAAA,CAAN,KAAgB,KAAnB;aAA8B,MAA9B;KAAA,MAAA;aAAyC,CAAC,EAA1C;;EAhBc;;EAkBhB,IAAI,CAAC,SAAL,GAAiB,SAAC,KAAD;AACf,QAAA;IAAA,IAAA,GAAO,KAAK,CAAC;WACb,aAAA,CAAc,IAAI,CAAC,KAAnB,EAA0B,IAAI,CAAC,KAA/B;EAFe;AAlBjB"
}

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<script>
var worker = new Worker("code_worker-source-map.js");
function binary_search(items, value) {
worker.postMessage({
items: items,
value: value
});
}
</script>
</head>
<body>
</body>
</html>

View File

@ -28,22 +28,24 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
this.widget.addEventListener("select", this._onWorkerSelect, false);
},
addWorker: function (actor, name) {
addWorker: function (workerForm) {
let element = document.createElement("label");
element.className = "plain dbg-worker-item";
element.setAttribute("value", name);
element.setAttribute("value", workerForm.url);
element.setAttribute("flex", "1");
this.push([element, actor], {});
this.push([element, workerForm.actor], {
attachment: workerForm
});
},
removeWorker: function (actor) {
this.remove(this.getItemByValue(actor));
removeWorker: function (workerForm) {
this.remove(this.getItemByValue(workerForm.actor));
},
_onWorkerSelect: function () {
if (this.selectedItem !== null) {
DebuggerController.Workers._onWorkerSelect(this.selectedItem.value);
DebuggerController.Workers._onWorkerSelect(this.selectedItem.attachment);
this.selectedItem = null;
}
}

View File

@ -912,6 +912,10 @@ Toolbox.prototype = {
if (!this.target.hasActor("gcli")) {
return promise.resolve();
}
// Disable gcli in browser toolbox until there is usages of it
if (this.target.chrome) {
return promise.resolve();
}
const options = {
environment: CommandUtils.createEnvironment(this, '_target')

View File

@ -114,6 +114,7 @@ skip-if = e10s # Bug 1091612
[browser_net_simple-request-details.js]
[browser_net_simple-request.js]
[browser_net_sort-01.js]
skip-if = (e10s && debug && os == 'mac') # Bug 1253037
[browser_net_sort-02.js]
[browser_net_sort-03.js]
[browser_net_statistics-01.js]

View File

@ -233,7 +233,15 @@ Telemetry.prototype = {
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
userHistogram: "DEVTOOLS_CUSTOM_OPENED_PER_USER_FLAG",
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
}
},
reloadAddonInstalled: {
histogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT",
userHistogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_PER_USER_FLAG",
},
reloadAddonReload: {
histogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT",
userHistogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_PER_USER_FLAG",
},
},
/**

View File

@ -34,7 +34,7 @@ function getTopWindow(win) {
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (!docShell.isBrowserOrApp) {
if (!docShell.isMozBrowserOrApp) {
return win.top;
}
@ -94,7 +94,7 @@ function getParentWindow(win) {
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
if (!docShell.isBrowserOrApp) {
if (!docShell.isMozBrowserOrApp) {
return win.parent;
}

View File

@ -34,7 +34,7 @@ nsILoadContext::GetOriginAttributes(mozilla::DocShellOriginAttributes& aAttrs)
aAttrs = attrs;
return true;
}
namespace mozilla {
NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor)
@ -172,13 +172,13 @@ LoadContext::SetRemoteTabs(bool aUseRemoteTabs)
}
NS_IMETHODIMP
LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
LoadContext::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
{
MOZ_ASSERT(mIsNotNull);
NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
NS_ENSURE_ARG_POINTER(aIsInIsolatedMozBrowserElement);
*aIsInBrowserElement = mOriginAttributes.mInBrowser;
*aIsInIsolatedMozBrowserElement = mOriginAttributes.mInIsolatedMozBrowser;
return NS_OK;
}

View File

@ -39,8 +39,8 @@ public:
NS_DECL_NSILOADCONTEXT
NS_DECL_NSIINTERFACEREQUESTOR
// AppId/inBrowser arguments override those in SerializedLoadContext provided
// by child process.
// appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext
// provided by child process.
LoadContext(const IPC::SerializedLoadContext& aToCopy,
dom::Element* aTopFrameElement,
DocShellOriginAttributes& aAttrs)
@ -56,8 +56,8 @@ public:
{
}
// AppId/inBrowser arguments override those in SerializedLoadContext provided
// by child process.
// appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext
// provided by child process.
LoadContext(const IPC::SerializedLoadContext& aToCopy,
uint64_t aNestedFrameId,
DocShellOriginAttributes& aAttrs)

View File

@ -332,7 +332,7 @@ nsDSURIContentListener::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel,
curDocShellItem->GetParent(getter_AddRefs(parentDocShellItem))) &&
parentDocShellItem) {
nsCOMPtr<nsIDocShell> curDocShell = do_QueryInterface(curDocShellItem);
if (curDocShell && curDocShell->GetIsBrowserOrApp()) {
if (curDocShell && curDocShell->GetIsMozBrowserOrApp()) {
break;
}

View File

@ -781,6 +781,7 @@ nsDocShell::nsDocShell()
, mAllowKeywordFixup(false)
, mIsOffScreenBrowser(false)
, mIsActive(true)
, mDisableMetaRefreshWhenInactive(false)
, mIsPrerendered(false)
, mIsAppTab(false)
, mUseGlobalHistory(false)
@ -806,6 +807,7 @@ nsDocShell::nsDocShell()
, mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
, mBlankTiming(false)
, mFrameType(eFrameTypeRegular)
, mIsInIsolatedMozBrowser(false)
, mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
, mUserContextId(nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID)
, mParentCharsetSource(0)
@ -885,8 +887,6 @@ nsDocShell::Init()
NS_ASSERTION(mLoadGroup, "Something went wrong!");
mContentListener = new nsDSURIContentListener(this);
NS_ENSURE_TRUE(mContentListener, NS_ERROR_OUT_OF_MEMORY);
rv = mContentListener->Init();
NS_ENSURE_SUCCESS(rv, rv);
@ -894,7 +894,6 @@ nsDocShell::Init()
// ref to us... use an InterfaceRequestorProxy to do this.
nsCOMPtr<nsIInterfaceRequestor> proxy =
new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
mLoadGroup->SetNotificationCallbacks(proxy);
rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
@ -1651,7 +1650,6 @@ NS_IMETHODIMP
nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
{
nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
localRef.forget(aLoadInfo);
@ -2573,7 +2571,7 @@ nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
NS_IMETHODIMP
nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
{
if (!nsIDocShell::GetIsBrowserOrApp()) {
if (!nsIDocShell::GetIsMozBrowserOrApp()) {
// Only allow setting of fullscreenAllowed on content/process boundaries.
// At non-boundaries the fullscreenAllowed attribute is calculated based on
// whether all enclosing frames have the "mozFullscreenAllowed" attribute
@ -2632,10 +2630,6 @@ nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection,
docShellEnum = new nsDocShellBackwardsEnumerator;
}
if (!docShellEnum) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
if (NS_FAILED(rv)) {
return rv;
@ -3385,7 +3379,7 @@ nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
NS_ENSURE_ARG_POINTER(aParent);
*aParent = nullptr;
if (nsIDocShell::GetIsBrowserOrApp()) {
if (nsIDocShell::GetIsMozBrowserOrApp()) {
return NS_OK;
}
@ -3521,7 +3515,8 @@ nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
return false;
}
if (targetDS->GetIsInBrowserElement() != accessingDS->GetIsInBrowserElement() ||
if (targetDS->GetIsInIsolatedMozBrowserElement() !=
accessingDS->GetIsInIsolatedMozBrowserElement() ||
targetDS->GetAppId() != accessingDS->GetAppId()) {
return false;
}
@ -4036,6 +4031,7 @@ nsDocShell::AddChild(nsIDocShellTreeItem* aChild)
aChild->SetTreeOwner(mTreeOwner);
childDocShell->SetUserContextId(mUserContextId);
childDocShell->SetIsInIsolatedMozBrowserElement(mIsInIsolatedMozBrowser);
nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
if (!childAsDocShell) {
@ -5656,6 +5652,10 @@ nsDocShell::Create()
gAddedPreferencesVarCache = true;
}
mDisableMetaRefreshWhenInactive =
Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
mDisableMetaRefreshWhenInactive);
mDeviceSizeIsPageSize =
Preferences::GetBool("docshell.device_size_is_page_size",
mDeviceSizeIsPageSize);
@ -5841,10 +5841,14 @@ nsDocShell::SetPosition(int32_t aX, int32_t aY)
NS_IMETHODIMP
nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
{
// Added to nsIBaseWindow in bug 1247335;
// implement if a use-case is found.
NS_ASSERTION(false, "implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
if (ownerWindow) {
return ownerWindow->SetPositionDesktopPix(aX, aY);
}
double scale = 1.0;
GetDevicePixelsPerDesktopPixel(&scale);
return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
}
NS_IMETHODIMP
@ -6145,7 +6149,7 @@ nsDocShell::SetIsActiveInternal(bool aIsActive, bool aIsHidden)
continue;
}
if (!docshell->GetIsBrowserOrApp()) {
if (!docshell->GetIsMozBrowserOrApp()) {
if (aIsHidden) {
docshell->SetIsActive(aIsActive);
} else {
@ -6154,6 +6158,15 @@ nsDocShell::SetIsActiveInternal(bool aIsActive, bool aIsHidden)
}
}
// Restart or stop meta refresh timers if necessary
if (mDisableMetaRefreshWhenInactive) {
if (mIsActive) {
ResumeRefreshURIs();
} else {
SuspendRefreshURIs();
}
}
return NS_OK;
}
@ -6599,7 +6612,6 @@ nsDocShell::RefreshURI(nsIURI* aURI, int32_t aDelay, bool aRepeat,
}
nsRefreshTimer* refreshTimer = new nsRefreshTimer();
NS_ENSURE_TRUE(refreshTimer, NS_ERROR_OUT_OF_MEMORY);
uint32_t busyFlags = 0;
GetBusyFlags(&busyFlags);
@ -6616,10 +6628,9 @@ nsDocShell::RefreshURI(nsIURI* aURI, int32_t aDelay, bool aRepeat,
NS_ERROR_FAILURE);
}
if (busyFlags & BUSY_FLAGS_BUSY) {
// We are busy loading another page. Don't create the
// timer right now. Instead queue up the request and trigger the
// timer in EndPageLoad().
if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) {
// We don't want to create the timer right now. Instead queue up the request
// and trigger the timer in EndPageLoad() or whenever we become active.
mRefreshURIList->AppendElement(refreshTimer);
} else {
// There is no page loading going on right now. Create the
@ -7572,7 +7583,8 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
}
// if there's a refresh header in the channel, this method
// will set it up for us.
RefreshURIFromQueue();
if (mIsActive || !mDisableMetaRefreshWhenInactive)
RefreshURIFromQueue();
// Test whether this is the top frame or a subframe
bool isTopFrame = true;
@ -13910,13 +13922,6 @@ nsDocShell::SetUserContextId(uint32_t aUserContextId)
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBrowserElement(bool* aIsBrowser)
{
*aIsBrowser = (mFrameType == eFrameTypeBrowser);
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsApp(bool* aIsApp)
{
@ -13925,15 +13930,15 @@ nsDocShell::GetIsApp(bool* aIsApp)
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsBrowserOrApp(bool* aIsBrowserOrApp)
nsDocShell::GetIsMozBrowserOrApp(bool* aIsMozBrowserOrApp)
{
switch (mFrameType) {
case eFrameTypeRegular:
*aIsBrowserOrApp = false;
*aIsMozBrowserOrApp = false;
break;
case eFrameTypeBrowser:
case eFrameTypeApp:
*aIsBrowserOrApp = true;
*aIsMozBrowserOrApp = true;
break;
}
@ -13959,22 +13964,42 @@ nsDocShell::GetInheritedFrameType()
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsInBrowserElement(bool* aIsInBrowserElement)
nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement)
{
*aIsInBrowserElement = (GetInheritedFrameType() == eFrameTypeBrowser);
bool result = mFrameType == eFrameTypeBrowser && mIsInIsolatedMozBrowser;
*aIsIsolatedMozBrowserElement = result;
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsInBrowserOrApp(bool* aIsInBrowserOrApp)
nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
{
MOZ_ASSERT(!mIsInIsolatedMozBrowser ||
(GetInheritedFrameType() == eFrameTypeBrowser),
"Isolated mozbrowser should only be true inside browser frames");
bool result = (GetInheritedFrameType() == eFrameTypeBrowser) &&
mIsInIsolatedMozBrowser;
*aIsInIsolatedMozBrowserElement = result;
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::SetIsInIsolatedMozBrowserElement(bool aIsInIsolatedMozBrowserElement)
{
mIsInIsolatedMozBrowser = aIsInIsolatedMozBrowserElement;
return NS_OK;
}
/* [infallible] */ NS_IMETHODIMP
nsDocShell::GetIsInMozBrowserOrApp(bool* aIsInMozBrowserOrApp)
{
switch (GetInheritedFrameType()) {
case eFrameTypeRegular:
*aIsInBrowserOrApp = false;
*aIsInMozBrowserOrApp = false;
break;
case eFrameTypeBrowser:
case eFrameTypeApp:
*aIsInBrowserOrApp = true;
*aIsInMozBrowserOrApp = true;
break;
}
@ -14020,10 +14045,7 @@ nsDocShell::GetOriginAttributes()
}
attrs.mUserContextId = mUserContextId;
if (mFrameType == eFrameTypeBrowser) {
attrs.mInBrowser = true;
}
attrs.mInIsolatedMozBrowser = mIsInIsolatedMozBrowser;
return attrs;
}

View File

@ -939,6 +939,7 @@ protected:
bool mAllowKeywordFixup;
bool mIsOffScreenBrowser;
bool mIsActive;
bool mDisableMetaRefreshWhenInactive;
bool mIsPrerendered;
bool mIsAppTab;
bool mUseGlobalHistory;
@ -1001,6 +1002,9 @@ protected:
// Are we a regular frame, a browser frame, or an app frame?
FrameType mFrameType;
// Whether we are in an isolated mozbrowser frame.
bool mIsInIsolatedMozBrowser;
// We only expect mOwnOrContainingAppId to be something other than
// UNKNOWN_APP_ID if mFrameType != eFrameTypeRegular. For vanilla iframes
// inside an app, we'll retrieve the containing app-id by walking up the

View File

@ -765,44 +765,55 @@ interface nsIDocShell : nsIDocShellTreeItem
*/
[noscript] void notifyScrollObservers();
/**
* Returns true if this docshell corresponds to an <iframe mozbrowser>.
* (<iframe mozapp mozbrowser> is not considered a browser.)
*/
[infallible] readonly attribute boolean isBrowserElement;
/**
* Returns true iff the docshell corresponds to an <iframe mozapp>.
*/
[infallible] readonly attribute boolean isApp;
/**
* Returns isBrowserElement || isApp.
* Returns true if this docshell corresponds to an <iframe mozbrowser> or
* <iframe mozapp>. <xul:browser> returns false here.
*/
[infallible] readonly attribute boolean isBrowserOrApp;
[infallible] readonly attribute boolean isMozBrowserOrApp;
/**
* Returns true if this docshell corresponds to an <iframe mozbrowser> or if
* the docshell is contained in an <iframe mozbrowser>. (<iframe mozapp
* mozbrowser> does not count as a browser.)
* Returns true if this docshell corresponds to an isolated <iframe
* mozbrowser>.
*
* <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
* mozbrowser elements. <iframe mozbrowser noisolation> does not count as
* isolated since isolation is disabled. Isolation can only be disabled if
* the containing document is chrome.
*/
[infallible] readonly attribute boolean isIsolatedMozBrowserElement;
/**
* Returns true if this docshell corresponds to an isolated <iframe
* mozbrowser> or if the docshell is contained in an isolated <iframe
* mozbrowser>.
*
* <iframe mozbrowser mozapp> and <xul:browser> are not considered to be
* mozbrowser elements. <iframe mozbrowser noisolation> does not count as
* isolated since isolation is disabled. Isolation can only be disabled if
* the containing document is chrome.
*
* Our notion here of "contained in" means: Walk up the docshell hierarchy in
* this process until we hit an <iframe mozapp> or <iframe mozbrowser> (or
* until the hierarchy ends). Return true iff the docshell we stopped on has
* isBrowserElement == true.
* isIsolatedMozBrowserElement == true.
*/
[infallible] readonly attribute boolean isInBrowserElement;
[infallible] attribute boolean isInIsolatedMozBrowserElement;
/**
* Returns true if this docshell corresponds to an <iframe mozbrowser> or
* <iframe mozapp>, or if this docshell is contained in an <iframe mozbrowser>
* or <iframe mozapp>.
* or <iframe mozapp>. <xul:browser> returns false here.
*
* To compute this value, we walk up the docshell hierarchy. If we encounter
* a docshell with isBrowserElement or isApp before we hit the end of the
* hierarchy, we return true. Otherwise, we return false.
* a docshell with isMozBrowserOrApp before we hit the end of the hierarchy,
* we return true. Otherwise, we return false.
*/
[infallible] readonly attribute boolean isInBrowserOrApp;
[infallible] readonly attribute boolean isInMozBrowserOrApp;
/**
* Indicate that this docshell corresponds to an app with the given app id.

View File

@ -116,9 +116,13 @@ interface nsILoadContext : nsISupports
[noscript] void SetRemoteTabs(in boolean aUseRemoteTabs);
/**
* Returns true iff the load is occurring inside a browser element.
* Returns true iff the load is occurring inside an isolated mozbrowser
* element. <iframe mozbrowser mozapp> and <xul:browser> are not considered to
* be mozbrowser elements. <iframe mozbrowser noisolation> does not count as
* isolated since isolation is disabled. Isolation can only be disabled if
* the containing document is chrome.
*/
readonly attribute boolean isInBrowserElement;
readonly attribute boolean isInIsolatedMozBrowserElement;
/**
* Returns the app id of the app the load is occurring is in. Returns

View File

@ -91,6 +91,17 @@ public:
*/
virtual void NotifyAnimationUpdated(Animation& aAnimation);
/**
* Returns true if any CSS animations, CSS transitions or Web animations are
* currently associated with this timeline. As soon as an animation is
* applied to an element it is associated with the timeline even if it has a
* delayed start, so this includes animations that may not be active for some
* time.
*/
bool HasAnimations() const {
return !mAnimations.IsEmpty();
}
void RemoveAnimation(Animation* aAnimation);
protected:

View File

@ -106,6 +106,10 @@ AppsService.prototype = {
return DOMApplicationRegistry.getWebAppsBasePath();
},
areAnyAppsInstalled: function() {
return DOMApplicationRegistry.areAnyAppsInstalled();
},
getAppInfo: function getAppInfo(aAppId) {
debug("getAppInfo()");
return DOMApplicationRegistry.getAppInfo(aAppId);

View File

@ -412,6 +412,10 @@ this.DOMApplicationRegistry = {
return null;
},
areAnyAppsInstalled: function() {
return AppsUtils.areAnyAppsInstalled(this.webapps);
},
getAppInfo: function getAppInfo(aAppId) {
return AppsUtils.getAppInfo(this.webapps, aAppId);
},

View File

@ -149,16 +149,17 @@ this.AppsUtils = {
return obj;
},
// Creates a nsILoadContext object with a given appId and isBrowser flag.
createLoadContext: function createLoadContext(aAppId, aIsBrowser) {
// Creates a nsILoadContext object with a given appId and inIsolatedMozBrowser
// flag.
createLoadContext: function createLoadContext(aAppId, aInIsolatedMozBrowser) {
return {
associatedWindow: null,
topWindow : null,
appId: aAppId,
isInBrowserElement: aIsBrowser,
isInIsolatedMozBrowserElement: aInIsolatedMozBrowser,
originAttributes: {
appId: aAppId,
inBrowser: aIsBrowser
inIsolatedMozBrowser: aInIsolatedMozBrowser
},
usePrivateBrowsing: false,
isContent: false,
@ -344,6 +345,10 @@ this.AppsUtils = {
return "";
},
areAnyAppsInstalled: function(aApps) {
return Object.getOwnPropertyNames(aApps).length > 0;
},
getCoreAppsBasePath: function getCoreAppsBasePath() {
debug("getCoreAppsBasePath()");
try {

View File

@ -183,7 +183,7 @@ WebappsRegistry.prototype = {
topId: this._topId,
requestID: requestID,
appId: principal.appId,
isBrowser: principal.isInBrowserElement,
isBrowser: principal.isInIsolatedMozBrowserElement,
isPackage: isPackage
};
},

View File

@ -3536,10 +3536,10 @@ this.DOMApplicationRegistry = {
// nsILoadContext
appId: aOldApp.installerAppId,
isInBrowserElement: aOldApp.installerIsBrowser,
isInIsolatedMozBrowserElement: aOldApp.installerIsBrowser,
originAttributes: {
appId: aOldApp.installerAppId,
inBrowser: aOldApp.installerIsBrowser
inIsolatedMozBrowser: aOldApp.installerIsBrowser
},
usePrivateBrowsing: false,
isContent: false,
@ -4799,6 +4799,10 @@ this.DOMApplicationRegistry = {
return OS.Path.dirname(this.appsFile);
},
areAnyAppsInstalled: function() {
return AppsUtils.areAnyAppsInstalled(this.webapps);
},
updateDataStoreEntriesFromLocalId: function(aLocalId) {
let app = appsService.getAppByLocalId(aLocalId);
if (app) {
@ -4902,7 +4906,7 @@ this.DOMApplicationRegistry = {
_clearOriginData: function(appId, browserOnly) {
let attributes = {appId: appId};
if (browserOnly) {
attributes.inBrowser = true;
attributes.inIsolatedMozBrowser = true;
}
this._notifyCategoryAndObservers(null, "clear-origin-data", JSON.stringify(attributes));
}

View File

@ -53,8 +53,8 @@ add_test(() => {
Assert.equal(mozapp.principal.origin, expectedPrincipalOrigin,
"app principal origin ok");
Assert.equal(mozapp.principal.appId, app.localId, "app principal appId ok");
Assert.equal(mozapp.principal.isInBrowserElement, false,
"app principal isInBrowserElement ok");
Assert.equal(mozapp.principal.isInIsolatedMozBrowserElement, false,
"app principal isInIsolatedMozBrowserElement ok");
run_next_test();
});

View File

@ -108,7 +108,7 @@ ChromeUtils::IsOriginAttributesEqual(dom::GlobalObject& aGlobal,
{
return aA.mAddonId == aB.mAddonId &&
aA.mAppId == aB.mAppId &&
aA.mInBrowser == aB.mInBrowser &&
aA.mInIsolatedMozBrowser == aB.mInIsolatedMozBrowser &&
aA.mSignedPkg == aB.mSignedPkg &&
aA.mUserContextId == aB.mUserContextId;
}

View File

@ -135,14 +135,14 @@ PerformanceObserver::QueueEntry(PerformanceEntry* aEntry)
mQueuedEntries.AppendElement(aEntry);
}
static nsString sValidTypeNames[7] = {
NS_LITERAL_STRING("composite"),
NS_LITERAL_STRING("mark"),
NS_LITERAL_STRING("measure"),
NS_LITERAL_STRING("navigation"),
NS_LITERAL_STRING("render"),
NS_LITERAL_STRING("resource"),
NS_LITERAL_STRING("server")
static const char16_t* sValidTypeNames[7] = {
MOZ_UTF16("composite"),
MOZ_UTF16("mark"),
MOZ_UTF16("measure"),
MOZ_UTF16("navigation"),
MOZ_UTF16("render"),
MOZ_UTF16("resource"),
MOZ_UTF16("server")
};
void
@ -156,7 +156,8 @@ PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
nsTArray<nsString> validEntryTypes;
for (const nsString& validTypeName : sValidTypeNames) {
for (const char16_t* name : sValidTypeNames) {
nsDependentString validTypeName(name);
if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
!validEntryTypes.Contains<nsString>(validTypeName)) {
validEntryTypes.AppendElement(validTypeName);

View File

@ -349,9 +349,10 @@ AutoJSAPI::InitInternal(JSObject* aGlobal, JSContext* aCx, bool aIsMainThread)
mAutoNullableCompartment.emplace(mCx, aGlobal);
}
JSRuntime* rt = JS_GetRuntime(aCx);
mOldErrorReporter.emplace(JS_GetErrorReporter(rt));
if (aIsMainThread) {
JSRuntime* rt = JS_GetRuntime(aCx);
mOldErrorReporter.emplace(JS_GetErrorReporter(rt));
JS_SetErrorReporter(rt, xpc::SystemErrorReporter);
}
}
@ -465,8 +466,21 @@ AutoJSAPI::InitWithLegacyErrorReporting(nsGlobalWindow* aWindow)
void
WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aRep)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
if (!NS_IsMainThread()) {
// Reporting a warning on workers is a bit complicated because we have to
// climb our parent chain until we get to the main thread. So go ahead and
// just go through the worker ReportError codepath here.
//
// That said, it feels like we should be able to short-circuit things a bit
// here by posting an appropriate runnable to the main thread directly...
// Worth looking into sometime.
workers::WorkerPrivate* worker = workers::GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(worker);
worker->ReportError(aCx, aMessage, aRep);
return;
}
RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
nsGlobalWindow* win = xpc::CurrentWindowOrNull(aCx);
@ -484,13 +498,7 @@ AutoJSAPI::TakeOwnershipOfErrorReporting()
JSRuntime *rt = JS_GetRuntime(cx());
mOldAutoJSAPIOwnsErrorReporting = JS::ContextOptionsRef(cx()).autoJSAPIOwnsErrorReporting();
JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(true);
// Workers have their own error reporting mechanism which deals with warnings
// as well, so don't change the worker error reporter for now. Once we switch
// all of workers to TakeOwnershipOfErrorReporting(), we will just make the
// default worker error reporter assert that it only sees warnings.
if (mIsMainThread) {
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
JS_SetErrorReporter(rt, WarningOnlyErrorReporter);
}
void
@ -548,6 +556,7 @@ AutoJSAPI::ReportException()
}
} else {
NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
ClearException();
}
}

View File

@ -422,7 +422,7 @@ nsFrameLoader::ReallyStartLoadingInternal()
int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE;
// Flags for browser frame:
if (OwnerIsBrowserFrame()) {
if (OwnerIsMozBrowserFrame()) {
flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
}
@ -1200,8 +1200,8 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
return NS_ERROR_NOT_IMPLEMENTED;
}
if (ourDocshell->GetIsBrowserElement() !=
otherDocshell->GetIsBrowserElement() ||
if (ourDocshell->GetIsIsolatedMozBrowserElement() !=
otherDocshell->GetIsIsolatedMozBrowserElement() ||
ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -1577,7 +1577,7 @@ nsFrameLoader::SetOwnerContent(Element* aContent)
}
bool
nsFrameLoader::OwnerIsBrowserOrAppFrame()
nsFrameLoader::OwnerIsMozBrowserOrAppFrame()
{
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false;
@ -1585,9 +1585,9 @@ nsFrameLoader::OwnerIsBrowserOrAppFrame()
// The xpcom getter version
NS_IMETHODIMP
nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult)
nsFrameLoader::GetOwnerIsMozBrowserOrAppFrame(bool* aResult)
{
*aResult = OwnerIsBrowserOrAppFrame();
*aResult = OwnerIsMozBrowserOrAppFrame();
return NS_OK;
}
@ -1615,9 +1615,66 @@ nsFrameLoader::OwnerIsAppFrame()
}
bool
nsFrameLoader::OwnerIsBrowserFrame()
nsFrameLoader::OwnerIsMozBrowserFrame()
{
return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame();
return OwnerIsMozBrowserOrAppFrame() && !OwnerIsAppFrame();
}
bool
nsFrameLoader::OwnerIsIsolatedMozBrowserFrame()
{
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
if (!browserFrame) {
return false;
}
if (!OwnerIsMozBrowserFrame()) {
return false;
}
bool isolated = browserFrame->GetIsolated();
if (isolated) {
return true;
}
// After bug 1238160, which allows isolation to be disabled on mozbrowser
// frames, we no longer have a way to tell from the principal alone if
// something "is a mozbrowser". Instead, we now only know "is an isolated
// mozbrowser". The following code paths would return invalid results if it
// were possible to have apps *and* isolation could be disabled:
// * CheckPermission in AppProcessChecker.cpp
// * nsScriptSecurityManager::AppStatusForPrincipal
// * init() in SystemMessageManager.js
// Currently, desktop is the only platform where we intend to disable
// isolation on a browser frame, so non-desktop should be able to assume that
// inIsolatedMozBrowser is true for all mozbrowser frames. To enforce these
// assumptions, we assert that there are no apps installed if we have tried
// to disable isolation.
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
if (!appsService) {
// If the apps service is not present, we assume this means there can't be
// any apps at all, so there is no problem.
return false;
}
bool appsInstalled;
nsresult rv = appsService->AreAnyAppsInstalled(&appsInstalled);
if (NS_WARN_IF(NS_FAILED(rv))) {
// The apps service exists, but it threw an error when checking if there are
// any apps, so we don't know if we have them or not.
return false;
}
#ifdef MOZ_B2G
MOZ_RELEASE_ASSERT(!appsInstalled,
"Disabling mozbrowser isolation is not currently "
"allowed when apps are installed.");
#else
if (appsInstalled) {
NS_WARNING("Disabling mozbrowser isolation is not currently allowed when "
"apps are installed.");
}
#endif
return false;
}
void
@ -1692,7 +1749,7 @@ nsFrameLoader::ShouldUseRemoteProcess()
// If we're an <iframe mozbrowser> and we don't have a "remote" attribute,
// fall back to the default.
if (OwnerIsBrowserOrAppFrame() &&
if (OwnerIsMozBrowserOrAppFrame() &&
!mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) {
return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false);
@ -1700,7 +1757,7 @@ nsFrameLoader::ShouldUseRemoteProcess()
// Otherwise, we're remote if we have "remote=true" and we're either a
// browser frame or a XUL element.
return (OwnerIsBrowserOrAppFrame() ||
return (OwnerIsMozBrowserOrAppFrame() ||
mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) &&
mOwnerContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::Remote,
@ -1883,7 +1940,7 @@ nsFrameLoader::MaybeCreateDocShell()
if (OwnerIsAppFrame()) {
// You can't be both an app and a browser frame.
MOZ_ASSERT(!OwnerIsBrowserFrame());
MOZ_ASSERT(!OwnerIsMozBrowserFrame());
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
MOZ_ASSERT(ownApp);
@ -1895,7 +1952,7 @@ nsFrameLoader::MaybeCreateDocShell()
mDocShell->SetIsApp(ownAppId);
}
if (OwnerIsBrowserFrame()) {
if (OwnerIsMozBrowserFrame()) {
// You can't be both a browser and an app frame.
MOZ_ASSERT(!OwnerIsAppFrame());
@ -1906,9 +1963,10 @@ nsFrameLoader::MaybeCreateDocShell()
NS_ERROR_FAILURE);
}
mDocShell->SetIsBrowserInsideApp(containingAppId);
mDocShell->SetIsInIsolatedMozBrowserElement(OwnerIsIsolatedMozBrowserFrame());
}
if (OwnerIsBrowserOrAppFrame()) {
if (OwnerIsMozBrowserOrAppFrame()) {
// For inproc frames, set the docshell properties.
nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
nsAutoString name;
@ -2249,7 +2307,7 @@ nsFrameLoader::TryRemoteBrowser()
}
// <iframe mozbrowser> gets to skip these checks.
if (!OwnerIsBrowserOrAppFrame()) {
if (!OwnerIsMozBrowserOrAppFrame()) {
if (parentDocShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
return false;
}
@ -2566,7 +2624,7 @@ nsFrameLoader::EnsureMessageManager()
}
if (!mIsTopLevelContent &&
!OwnerIsBrowserOrAppFrame() &&
!OwnerIsMozBrowserOrAppFrame() &&
!IsRemoteFrame() &&
!(mOwnerContent->IsXULElement() &&
mOwnerContent->AttrValueIs(kNameSpaceID_None,
@ -2672,7 +2730,7 @@ nsFrameLoader::SwapRemoteBrowser(nsITabParent* aTabParent)
NS_WARNING("Switching from in-process to out-of-process is not supported.");
return NS_ERROR_NOT_IMPLEMENTED;
}
if (!OwnerIsBrowserOrAppFrame()) {
if (!OwnerIsMozBrowserOrAppFrame()) {
NS_WARNING("Switching process for non-mozbrowser/app frame is not supported.");
return NS_ERROR_NOT_IMPLEMENTED;
}
@ -2823,7 +2881,7 @@ nsFrameLoader::ResetPermissionManagerStatus()
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
if (OwnerIsAppFrame()) {
// You can't be both an app and a browser frame.
MOZ_ASSERT(!OwnerIsBrowserFrame());
MOZ_ASSERT(!OwnerIsMozBrowserFrame());
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
MOZ_ASSERT(ownApp);
@ -2833,7 +2891,7 @@ nsFrameLoader::ResetPermissionManagerStatus()
}
}
if (OwnerIsBrowserFrame()) {
if (OwnerIsMozBrowserFrame()) {
// You can't be both a browser and an app frame.
MOZ_ASSERT(!OwnerIsAppFrame());
@ -2971,7 +3029,7 @@ nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
void
nsFrameLoader::InitializeBrowserAPI()
{
if (OwnerIsBrowserOrAppFrame()) {
if (OwnerIsMozBrowserOrAppFrame()) {
if (!IsRemoteFrame()) {
nsresult rv = EnsureMessageManager();
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -3066,7 +3124,7 @@ nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
DocShellOriginAttributes attrs;
attrs.mInBrowser = OwnerIsBrowserFrame();
attrs.mInIsolatedMozBrowser = OwnerIsIsolatedMozBrowserFrame();
nsCString signedPkgOrigin;
if (!aPackageId.IsEmpty()) {
@ -3107,7 +3165,11 @@ nsFrameLoader::GetNewTabContext(MutableTabContext* aTabContext,
}
bool tabContextUpdated =
aTabContext->SetTabContext(ownApp, containingApp, attrs, signedPkgOrigin);
aTabContext->SetTabContext(OwnerIsMozBrowserFrame(),
ownApp,
containingApp,
attrs,
signedPkgOrigin);
NS_ENSURE_STATE(tabContextUpdated);
return NS_OK;

View File

@ -143,7 +143,7 @@ public:
return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr;
}
/**
/**
* Return the document that owns this, or null if we don't have
* an owner.
*/
@ -194,7 +194,7 @@ public:
* otherwise we'll discard the old presentation and set the detached
* subdoc view to null. aContainerDoc is the document containing the
* the subdoc frame. This enables us to detect when the containing
* document has changed during reframe, so we can discard the presentation
* document has changed during reframe, so we can discard the presentation
* in that case.
*/
void SetDetachedSubdocView(nsView* aDetachedView,
@ -242,8 +242,9 @@ private:
* Is this a frameloader for a bona fide <iframe mozbrowser> or
* <iframe mozapp>? (I.e., does the frame return true for
* nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?)
* <xul:browser> is not a mozbrowser or app, so this is false for that case.
*/
bool OwnerIsBrowserOrAppFrame();
bool OwnerIsMozBrowserOrAppFrame();
/**
* Is this a frameloader for a bona fide <iframe mozwidget>? (I.e., does the
@ -259,8 +260,18 @@ private:
/**
* Is this a frame loader for a bona fide <iframe mozbrowser>?
* <xul:browser> is not a mozbrowser, so this is false for that case.
*/
bool OwnerIsBrowserFrame();
bool OwnerIsMozBrowserFrame();
/**
* Is this a frame loader for an isolated <iframe mozbrowser>?
*
* By default, mozbrowser frames are isolated. Isolation can be disabled by
* setting the frame's noisolation attribute. Disabling isolation is
* only allowed if the containing document is chrome.
*/
bool OwnerIsIsolatedMozBrowserFrame();
/**
* Get our owning element's app manifest URL, or return the empty string if

View File

@ -657,6 +657,7 @@ GK_ATOM(nodeSet, "node-set")
GK_ATOM(noembed, "noembed")
GK_ATOM(noframes, "noframes")
GK_ATOM(nohref, "nohref")
GK_ATOM(noisolation, "noisolation")
GK_ATOM(nonce, "nonce")
GK_ATOM(none, "none")
GK_ATOM(noresize, "noresize")

View File

@ -457,8 +457,6 @@ nsGlobalWindow::DOMMinTimeoutValue() const {
// CIDs
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
static const char sPopStatePrefStr[] = "browser.history.allowPopState";
#define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload")
#define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload")
@ -1158,6 +1156,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mIsPopupSpam(false),
mBlockScriptedClosingFlag(false),
mWasOffline(false),
mHasHadSlowScript(false),
mNotifyIdleObserversIdleOnThaw(false),
mNotifyIdleObserversActiveOnThaw(false),
mCreatingInnerWindow(false),
@ -3801,7 +3800,7 @@ nsGlobalWindow::GetParentOuter()
}
nsCOMPtr<nsPIDOMWindowOuter> parent;
if (mDocShell->GetIsBrowserOrApp()) {
if (mDocShell->GetIsMozBrowserOrApp()) {
parent = AsOuter();
} else {
parent = GetParent();
@ -3967,7 +3966,7 @@ nsGlobalWindow::GetContentInternal(ErrorResult& aError, bool aUnprivilegedCaller
// If we're contained in <iframe mozbrowser> or <iframe mozapp>, then
// GetContent is the same as window.top.
if (mDocShell && mDocShell->GetIsInBrowserOrApp()) {
if (mDocShell && mDocShell->GetIsInMozBrowserOrApp()) {
return GetTopOuter();
}
@ -7175,7 +7174,7 @@ nsGlobalWindow::ResizeToOuter(int32_t aWidth, int32_t aHeight, ErrorResult& aErr
* If caller is a browser-element then dispatch a resize event to
* the embedder.
*/
if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) {
CSSIntSize size(aWidth, aHeight);
if (!DispatchResizeEvent(size)) {
// The embedder chose to prevent the default action for this
@ -7225,7 +7224,7 @@ nsGlobalWindow::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
* If caller is a browser-element then dispatch a resize event to
* parent.
*/
if (mDocShell && mDocShell->GetIsBrowserOrApp()) {
if (mDocShell && mDocShell->GetIsMozBrowserOrApp()) {
CSSIntSize size;
if (NS_FAILED(GetInnerSize(size))) {
return;
@ -8174,7 +8173,7 @@ nsGlobalWindow::CloseOuter(bool aTrustedCaller)
MOZ_RELEASE_ASSERT(IsOuterWindow());
if (!mDocShell || IsInModalState() ||
(IsFrame() && !mDocShell->GetIsBrowserOrApp())) {
(IsFrame() && !mDocShell->GetIsMozBrowserOrApp())) {
// window.close() is called on a frame in a frameset, on a window
// that's already closed, or on a window for which there's
// currently a modal dialog open. Ignore such calls.
@ -8701,7 +8700,7 @@ nsGlobalWindow::GetFrameElementOuter()
{
MOZ_RELEASE_ASSERT(IsOuterWindow());
if (!mDocShell || mDocShell->GetIsBrowserOrApp()) {
if (!mDocShell || mDocShell->GetIsMozBrowserOrApp()) {
return nullptr;
}
@ -9916,11 +9915,6 @@ nsGlobalWindow::DispatchSyncPopState()
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Must be safe to run script here.");
// Check that PopState hasn't been pref'ed off.
if (!Preferences::GetBool(sPopStatePrefStr, false)) {
return NS_OK;
}
nsresult rv = NS_OK;
// Bail if the window is frozen.
@ -10662,6 +10656,13 @@ nsGlobalWindow::ShowSlowScriptDialog()
unsigned lineno;
bool hasFrame = JS::DescribeScriptedCaller(cx, &filename, &lineno);
// Record the slow script event if we haven't done so already for this inner window
// (which represents a particular page to the user).
if (!mHasHadSlowScript) {
Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1);
}
mHasHadSlowScript = true;
if (XRE_IsContentProcess() &&
ProcessHangMonitor::Get()) {
ProcessHangMonitor::SlowScriptAction action;

View File

@ -1685,6 +1685,11 @@ protected:
// Window offline status. Checked to see if we need to fire offline event
bool mWasOffline : 1;
// Represents whether the inner window's page has had a slow script notice.
// Only used by inner windows; will always be false for outer windows.
// This is used to implement Telemetry measures such as SLOW_SCRIPT_PAGE_COUNT.
bool mHasHadSlowScript : 1;
// Track what sorts of events we need to fire when thawed
bool mNotifyIdleObserversIdleOnThaw : 1;
bool mNotifyIdleObserversActiveOnThaw : 1;

View File

@ -25,11 +25,6 @@
using namespace mozilla;
using namespace mozilla::dom;
static const char* sAllowPushStatePrefStr =
"browser.history.allowPushState";
static const char* sAllowReplaceStatePrefStr =
"browser.history.allowReplaceState";
//
// History class implementation
//
@ -304,12 +299,6 @@ nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
return;
}
// Check that PushState hasn't been pref'ed off.
if (!Preferences::GetBool(aReplace ? sAllowReplaceStatePrefStr :
sAllowPushStatePrefStr, false)) {
return;
}
// AddState might run scripts, so we need to hold a strong reference to the
// docShell here to keep it from going away.
nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();

View File

@ -150,7 +150,7 @@ interface nsIFrameLoader : nsISupports
const unsigned long EVENT_MODE_NORMAL_DISPATCH = 0x00000000;
/**
* With this event mode, it's the application's responsability to
* With this event mode, it's the application's responsability to
* convert and forward events to the content process
*/
const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
@ -196,14 +196,15 @@ interface nsIFrameLoader : nsISupports
[infallible] attribute boolean visible;
/**
* Find out whether the owner content really is a browser or app frame
* Especially, a widget frame is regarded as an app frame.
* Find out whether the owner content really is a mozbrowser or app frame
* Especially, a widget frame is regarded as an app frame. <xul:browser> is
* not considered to be a mozbrowser frame.
*/
readonly attribute boolean ownerIsBrowserOrAppFrame;
readonly attribute boolean ownerIsMozBrowserOrAppFrame;
/**
* Find out whether the owner content really is a widget. If this attribute
* returns true, |ownerIsBrowserOrAppFrame| must return true.
* returns true, |ownerIsMozBrowserOrAppFrame| must return true.
*/
readonly attribute boolean ownerIsWidget;

View File

@ -1437,6 +1437,11 @@ TimeUntilNow(TimeStamp start)
struct CycleCollectorStats
{
MOZ_CONSTEXPR CycleCollectorStats() :
mMaxGCDuration(0), mRanSyncForgetSkippable(false), mSuspected(0),
mMaxSkippableDuration(0), mMaxSliceTime(0), mMaxSliceTimeSinceClear(0),
mTotalSliceTime(0), mAnyLockedOut(false), mExtraForgetSkippableCalls(0) {}
void Init()
{
Clear();

View File

@ -259,6 +259,7 @@ support-files =
file_change_policy_redirect.html
file_bug1198095.js
file_bug1250148.sjs
mozbrowser_api_utils.js
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -872,4 +873,6 @@ skip-if = buildapp == 'b2g' #no ssl support
[test_bug1187157.html]
[test_bug769117.html]
[test_bug1250148.html]
[test_bug1240471.html]
[test_bug1240471.html]
[test_mozbrowser_apis_allowed.html]
[test_mozbrowser_apis_blocked.html]

View File

@ -0,0 +1,72 @@
const FRAME_URL = "http://example.org/";
const METHODS = {
setVisible: {},
getVisible: {},
setActive: {},
getActive: {},
addNextPaintListener: {},
removeNextPaintListener: {},
sendMouseEvent: {},
sendTouchEvent: {},
goBack: {},
goForward: {},
reload: {},
stop: {},
download: {},
purgeHistory: {},
getScreenshot: {},
zoom: {},
getCanGoBack: {},
getCanGoForward: {},
getContentDimensions: {},
setInputMethodActive: { alwaysFails: true }, // needs input-manage
setNFCFocus: { alwaysFails: true }, // needs nfc-manager
findAll: {},
findNext: {},
clearMatch: {},
executeScript: { alwaysFails: true }, // needs browser:universalxss
getStructuredData: {},
getWebManifest: {},
mute: {},
unmute: {},
getMuted: {},
setVolume: {},
getVolume: {},
};
const ATTRIBUTES = [
"allowedAudioChannels",
];
function once(target, eventName, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
return new Promise(resolve => {
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addMessageListener", "removeMessageListener"],
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
info("Got event: '" + eventName + "' on " + target + ".");
target[remove](eventName, onEvent, useCapture);
resolve(aArgs);
}, useCapture);
break;
}
}
});
}
function* loadFrame(attributes = {}) {
let iframe = document.createElement("iframe");
iframe.setAttribute("src", FRAME_URL);
for (let key in attributes) {
iframe.setAttribute(key, attributes[key]);
}
let loaded = once(iframe, "load");
document.body.appendChild(iframe);
yield loaded;
return iframe;
}

View File

@ -34,8 +34,8 @@
sendAsyncMessage(message.name, "principal.origin: " +
("origin" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "principal.isInBrowserElement: " +
("isInBrowserElement" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "principal.isInIsolatedMozBrowserElement: " +
("isInIsolatedMozBrowserElement" in message.principal ? "OK" : "KO"));
sendAsyncMessage(message.name, "DONE");
});

View File

@ -38,8 +38,8 @@
sendAsyncMessage("test:result", "principal.origin: " +
("origin" in message.data ? "OK" : "KO"));
sendAsyncMessage("test:result", "principal.isInBrowserElement: " +
("isInBrowserElement" in message.data ? "OK" : "KO"));
sendAsyncMessage("test:result", "principal.isInIsolatedMozBrowserElement: " +
("isInIsolatedMozBrowserElement" in message.data ? "OK" : "KO"));
});
addMessageListener("test:system", function(message) {

View File

@ -110,7 +110,7 @@
{ type: "browser", allow: 1, context: { url: principal.URI.spec,
originAttributes: {
appId: principal.appId,
inBrowser: true }}}
inIsolatedMozBrowser: true }}}
], () => {
SpecialPowers.pushPrefEnv({
set: [

View File

@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Verify mozbrowser APIs are allowed with browser permission</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="mozbrowser_api_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="application/javascript;version=1.8">
add_task(function*() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv(
{ "set": [["dom.mozBrowserFramesEnabled", true]] },
resolve);
});
});
add_task(function*() {
yield new Promise(resolve => {
SpecialPowers.pushPermissions([
{ "type": "browser", "allow": 1, "context": document }
], resolve);
});
});
add_task(function*() {
// Create <iframe mozbrowser>
let frame = yield loadFrame({
mozbrowser: "true"
});
// Verify that mozbrowser APIs are accessible
for (let method in METHODS) {
let { alwaysFails } = METHODS[method];
if (alwaysFails) {
ok(!(method in frame), `frame does not have method ${method}, ` +
`needs more permissions`);
} else {
ok(method in frame, `frame has method ${method}`);
}
}
for (let attribute of ATTRIBUTES) {
ok(attribute in frame, `frame has attribute ${attribute}`);
}
});
</script>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Verify mozbrowser APIs are blocked without browser permission</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="mozbrowser_api_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="application/javascript;version=1.8">
add_task(function*() {
yield new Promise(resolve => {
SpecialPowers.pushPrefEnv(
{ "set": [["dom.mozBrowserFramesEnabled", true]] },
resolve);
});
});
add_task(function*() {
// Create <iframe mozbrowser>
let frame = yield loadFrame({
mozbrowser: "true"
});
// Verify that mozbrowser APIs are not accessible
for (let method in METHODS) {
ok(!(method in frame), `frame does not have method ${method}`);
}
for (let attribute of ATTRIBUTES) {
ok(!(attribute in frame), `frame does not have attribute ${attribute}`);
}
});
</script>
</body>
</html>

View File

@ -12187,6 +12187,15 @@ class CGDictionary(CGThing):
return "DictionaryBase"
def initMethod(self):
"""
This function outputs the body of the Init() method for the dictionary.
For the most part, this is some bookkeeping for our atoms so
we can avoid atomizing strings all the time, then we just spit
out the getMemberConversion() output for each member,
separated by newlines.
"""
body = dedent("""
// Passing a null JSContext is OK only if we're initing from null,
// Since in that case we will not have to do any property gets
@ -12504,6 +12513,25 @@ class CGDictionary(CGThing):
return declType.define()
def getMemberConversion(self, memberInfo):
"""
A function that outputs the initialization of a single dictionary
member from the given dictionary value.
We start with our conversionInfo, which tells us how to
convert a JS::Value to whatever type this member is. We
substiture the template from the conversionInfo with values
that point to our "temp" JS::Value and our member (which is
the C++ value we want to produce). The output is a string of
code to do the conversion. We store this string in
conversionReplacements["convert"].
Now we have three different ways we might use (or skip) this
string of code, depending on whether the value is required,
optional with default value, or optional without default
value. We set up a template in the 'conversion' variable for
exactly how to do this, then substitute into it from the
conversionReplacements dictionary.
"""
member, conversionInfo = memberInfo
replacements = {
"val": "temp.ref()",

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