Bug 1686951: Support switch-to-tab in private browsing window. r=adw

Differential Revision: https://phabricator.services.mozilla.com/D117974
This commit is contained in:
Daisuke Akatsuka 2021-06-21 01:33:26 +00:00
Родитель 28ed679540
Коммит 1cc55fd4cf
12 изменённых файлов: 112 добавлений и 83 удалений

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

@ -8381,13 +8381,12 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams = {}) {
// This will switch to the tab in aWindow having aURI, if present.
function switchIfURIInWindow(aWindow) {
// Only switch to the tab if neither the source nor the destination window
// are private and they are not in permanent private browsing mode
// We can switch tab only if if both the source and destination windows have
// the same private-browsing status.
if (
!kPrivateBrowsingWhitelist.has(aURI.spec) &&
(PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.isWindowPrivate(aWindow)) &&
!PrivateBrowsingUtils.permanentPrivateBrowsing
PrivateBrowsingUtils.isWindowPrivate(window) !==
PrivateBrowsingUtils.isWindowPrivate(aWindow)
) {
return false;
}

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

@ -2792,7 +2792,8 @@
// a switch-to-tab candidate in autocomplete.
this.UrlbarProviderOpenTabs.registerOpenTab(
lazyBrowserURI.spec,
userContextId
userContextId || 0,
PrivateBrowsingUtils.isWindowPrivate(window)
);
b.registeredOpenURI = lazyBrowserURI;
}
@ -3857,7 +3858,8 @@
let userContextId = browser.getAttribute("usercontextid") || 0;
this.UrlbarProviderOpenTabs.unregisterOpenTab(
browser.registeredOpenURI.spec,
userContextId
userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
delete browser.registeredOpenURI;
}
@ -4233,7 +4235,8 @@
let userContextId = otherBrowser.getAttribute("usercontextid") || 0;
this.UrlbarProviderOpenTabs.unregisterOpenTab(
otherBrowser.registeredOpenURI.spec,
userContextId
userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
delete otherBrowser.registeredOpenURI;
}
@ -5560,7 +5563,8 @@
let userContextId = browser.getAttribute("usercontextid") || 0;
this.UrlbarProviderOpenTabs.unregisterOpenTab(
browser.registeredOpenURI.spec,
userContextId
userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
delete browser.registeredOpenURI;
}
@ -6550,20 +6554,16 @@
let uri = this.mBrowser.registeredOpenURI;
gBrowser.UrlbarProviderOpenTabs.unregisterOpenTab(
uri.spec,
userContextId
userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
delete this.mBrowser.registeredOpenURI;
}
// Tabs in private windows aren't registered as "Open" so
// that they don't appear as switch-to-tab candidates.
if (
!isBlankPageURL(aLocation.spec) &&
(!PrivateBrowsingUtils.isWindowPrivate(window) ||
PrivateBrowsingUtils.permanentPrivateBrowsing)
) {
if (!isBlankPageURL(aLocation.spec)) {
gBrowser.UrlbarProviderOpenTabs.registerOpenTab(
aLocation.spec,
userContextId
userContextId,
PrivateBrowsingUtils.isWindowPrivate(window)
);
this.mBrowser.registeredOpenURI = aLocation;
}

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

@ -22,6 +22,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
});
const PRIVATE_USER_CONTEXT_ID = -1;
/**
* Class used to create the provider.
*/
@ -69,7 +71,31 @@ class UrlbarProviderOpenTabs extends UrlbarProvider {
/**
* Maps the open tabs by userContextId.
*/
static openTabs = new Map();
static _openTabs = new Map();
/**
* Return urls that is opening on given user context id.
* @param {integer} userContextId Containers user context id
* @param {boolean} isInPrivateWindow In private browsing window or not
* @returns {Array} urls
*/
static getOpenTabs(userContextId, isInPrivateWindow) {
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
userContextId,
isInPrivateWindow
);
return UrlbarProviderOpenTabs._openTabs.get(userContextId);
}
/**
* Return userContextId that will be used in moz_openpages_temp table.
* @param {integer} userContextId Containers user context id
* @param {boolean} isInPrivateWindow In private browsing window or not
* @returns {interger} userContextId
*/
static getUserContextIdForOpenPagesTable(userContextId, isInPrivateWindow) {
return isInPrivateWindow ? PRIVATE_USER_CONTEXT_ID : userContextId;
}
/**
* Copy over cached open tabs to the memory table once the Urlbar
@ -80,7 +106,7 @@ class UrlbarProviderOpenTabs extends UrlbarProvider {
// Must be set before populating.
UrlbarProviderOpenTabs.memoryTableInitialized = true;
// Populate the table with the current cached tabs.
for (let [userContextId, urls] of UrlbarProviderOpenTabs.openTabs) {
for (let [userContextId, urls] of UrlbarProviderOpenTabs._openTabs) {
for (let url of urls) {
await addToMemoryTable(url, userContextId).catch(Cu.reportError);
}
@ -92,12 +118,18 @@ class UrlbarProviderOpenTabs extends UrlbarProvider {
* Registers a tab as open.
* @param {string} url Address of the tab
* @param {integer} userContextId Containers user context id
* @param {boolean} isInPrivateWindow In private browsing window or not
*/
static async registerOpenTab(url, userContextId = 0) {
if (!UrlbarProviderOpenTabs.openTabs.has(userContextId)) {
UrlbarProviderOpenTabs.openTabs.set(userContextId, []);
static async registerOpenTab(url, userContextId, isInPrivateWindow) {
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
userContextId,
isInPrivateWindow
);
if (!UrlbarProviderOpenTabs._openTabs.has(userContextId)) {
UrlbarProviderOpenTabs._openTabs.set(userContextId, []);
}
UrlbarProviderOpenTabs.openTabs.get(userContextId).push(url);
UrlbarProviderOpenTabs._openTabs.get(userContextId).push(url);
await addToMemoryTable(url, userContextId).catch(Cu.reportError);
}
@ -105,9 +137,15 @@ class UrlbarProviderOpenTabs extends UrlbarProvider {
* Unregisters a previously registered open tab.
* @param {string} url Address of the tab
* @param {integer} userContextId Containers user context id
* @param {boolean} isInPrivateWindow In private browsing window or not
*/
static async unregisterOpenTab(url, userContextId = 0) {
let openTabs = UrlbarProviderOpenTabs.openTabs.get(userContextId);
static async unregisterOpenTab(url, userContextId, isInPrivateWindow) {
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
userContextId,
isInPrivateWindow
);
let openTabs = UrlbarProviderOpenTabs._openTabs.get(userContextId);
if (openTabs) {
let index = openTabs.indexOf(url);
if (index != -1) {

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

@ -16,7 +16,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
"resource:///modules/PartnerLinkAttribution.jsm",
PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
Services: "resource://gre/modules/Services.jsm",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
@ -213,14 +212,11 @@ class ProviderTopSites extends UrlbarProvider {
)
);
let allowTabSwitch =
!queryContext.isPrivate ||
PrivateBrowsingUtils.permanentPrivateBrowsing;
let tabs;
if (allowTabSwitch && UrlbarPrefs.get("suggest.openpage")) {
tabs = UrlbarProviderOpenTabs.openTabs.get(
queryContext.userContextId || 0
if (UrlbarPrefs.get("suggest.openpage")) {
tabs = UrlbarProviderOpenTabs.getOpenTabs(
queryContext.userContextId || 0,
queryContext.isPrivate
);
}

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

@ -4,8 +4,8 @@
"use strict";
/**
* This test ensures that we don't move switch between tabs when one is in
* private browsing and the other is normal, or vice-versa.
* This test ensures that we don't switch between tabs from normal window to
* private browsing window or opposite.
*/
const TEST_URL = `${TEST_BASE_URL}dummy_page.html`;
@ -30,7 +30,7 @@ add_task(async function() {
privateWindow = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
await runTest(privateWindow, privateWindow, false);
await runTest(privateWindow, privateWindow, true);
await BrowserTestUtils.closeWindow(privateWindow);
normalWindow = await BrowserTestUtils.openNewBrowserWindow();

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

@ -297,13 +297,21 @@ async function addTestTailSuggestionsEngine(suggestionsFn = null) {
async function addOpenPages(uri, count = 1, userContextId = 0) {
for (let i = 0; i < count; i++) {
await UrlbarProviderOpenTabs.registerOpenTab(uri.spec, userContextId);
await UrlbarProviderOpenTabs.registerOpenTab(
uri.spec,
userContextId,
false
);
}
}
async function removeOpenPages(aUri, aCount = 1, aUserContextId = 0) {
for (let i = 0; i < aCount; i++) {
await UrlbarProviderOpenTabs.unregisterOpenTab(aUri.spec, aUserContextId);
await UrlbarProviderOpenTabs.unregisterOpenTab(
aUri.spec,
aUserContextId,
false
);
}
}

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

@ -31,7 +31,11 @@ add_task(async function test_restrictions() {
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
title: "match",
});
await UrlbarProviderOpenTabs.registerOpenTab("http://openpagematch.com/");
await UrlbarProviderOpenTabs.registerOpenTab(
"http://openpagematch.com/",
0,
false
);
info("Bookmark restrict");
let results = await get_results({

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

@ -6,16 +6,16 @@
add_task(async function test_openTabs() {
const userContextId = 5;
const url = "http://foo.mozilla.org/";
UrlbarProviderOpenTabs.registerOpenTab(url, userContextId);
UrlbarProviderOpenTabs.registerOpenTab(url, userContextId);
UrlbarProviderOpenTabs.registerOpenTab(url, userContextId, false);
UrlbarProviderOpenTabs.registerOpenTab(url, userContextId, false);
Assert.equal(
UrlbarProviderOpenTabs.openTabs.get(userContextId).length,
UrlbarProviderOpenTabs._openTabs.get(userContextId).length,
2,
"Found all the expected tabs"
);
UrlbarProviderOpenTabs.unregisterOpenTab(url, userContextId);
UrlbarProviderOpenTabs.unregisterOpenTab(url, userContextId, false);
Assert.equal(
UrlbarProviderOpenTabs.openTabs.get(userContextId).length,
UrlbarProviderOpenTabs._openTabs.get(userContextId).length,
1,
"Found all the expected tabs"
);

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

@ -41,7 +41,7 @@ add_task(async function test_unifiedComplete() {
{ uri: "https://history.mozilla.org/", title: "Test history" },
{ uri: "https://tab.mozilla.org/", title: "Test tab" },
]);
UrlbarProviderOpenTabs.registerOpenTab("https://tab.mozilla.org/", 0);
UrlbarProviderOpenTabs.registerOpenTab("https://tab.mozilla.org/", 0, false);
await controller.startQuery(context);
@ -89,7 +89,11 @@ add_task(async function test_unifiedComplete() {
await PlacesUtils.history.clear();
await PlacesUtils.bookmarks.eraseEverything();
UrlbarProviderOpenTabs.unregisterOpenTab("https://tab.mozilla.org/", 0);
UrlbarProviderOpenTabs.unregisterOpenTab(
"https://tab.mozilla.org/",
0,
false
);
});
add_task(async function test_bookmarkBehaviorDisabled_tagged() {

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

@ -117,11 +117,11 @@ XPCOMUtils.defineLazyModuleGetters(this, {
KeywordUtils: "resource://gre/modules/KeywordUtils.jsm",
ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ProfileAge: "resource://gre/modules/ProfileAge.jsm",
PromiseUtils: "resource://gre/modules/PromiseUtils.jsm",
Sqlite: "resource://gre/modules/Sqlite.jsm",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.jsm",
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.jsm",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
@ -401,9 +401,6 @@ const MATCH_TYPE = {
* parameters are supported:
* * enable-actions: Include "actions", such as switch-to-tab and search
* engine aliases, in the results.
* * disable-private-actions: The search is taking place in a private
* window outside of permanent private-browsing mode. The search
* should exclude privacy-sensitive results as appropriate.
* * private-window: The search is taking place in a private window,
* possibly in permanent private-browsing mode. The search
* should exclude privacy-sensitive results as appropriate.
@ -441,8 +438,6 @@ function Search(
if (queryContext) {
this._enableActions = true;
this._inPrivateWindow = queryContext.isPrivate;
this._disablePrivateActions =
this._inPrivateWindow && !PrivateBrowsingUtils.permanentPrivateBrowsing;
this._prohibitAutoFill = !queryContext.allowAutofill;
this._maxResults = queryContext.maxResults;
this._userContextId = queryContext.userContextId;
@ -457,7 +452,6 @@ function Search(
} else {
let params = new Set(searchParam.split(" "));
this._enableActions = params.has("enable-actions");
this._disablePrivateActions = params.has("disable-private-actions");
this._inPrivateWindow = params.has("private-window");
this._prohibitAutoFill = params.has("prohibit-autofill");
// Extract the max-results param.
@ -472,6 +466,11 @@ function Search(
: Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
}
this._userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
this._userContextId,
this._inPrivateWindow
);
// Use the original string here, not the stripped one, so the tokenizer can
// properly recognize token types.
let { tokens } = UrlbarTokenizer.tokenize({
@ -585,14 +584,6 @@ Search.prototype = {
*/
hasBehavior(type) {
let behavior = Ci.mozIPlacesAutoComplete["BEHAVIOR_" + type.toUpperCase()];
if (
this._disablePrivateActions &&
behavior == Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE
) {
return false;
}
return this._behavior & behavior;
},

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

@ -380,13 +380,21 @@ async function check_autocomplete(test) {
async function addOpenPages(aUri, aCount = 1, aUserContextId = 0) {
for (let i = 0; i < aCount; i++) {
await UrlbarProviderOpenTabs.registerOpenTab(aUri.spec, aUserContextId);
await UrlbarProviderOpenTabs.registerOpenTab(
aUri.spec,
aUserContextId,
false
);
}
}
async function removeOpenPages(aUri, aCount = 1, aUserContextId = 0) {
for (let i = 0; i < aCount; i++) {
await UrlbarProviderOpenTabs.unregisterOpenTab(aUri.spec, aUserContextId);
await UrlbarProviderOpenTabs.unregisterOpenTab(
aUri.spec,
aUserContextId,
false
);
}
}

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

@ -145,25 +145,6 @@ add_task(async function test_tab_matches() {
],
});
info("three results, no tab matches (disable-private-actions)");
await check_autocomplete({
search: "abc",
searchParam: "enable-actions disable-private-actions",
matches: [
{ uri: uri1, title: "ABC rocks", style: ["favicon"] },
{
uri: uri2,
title: "xyz.net - we're better than ABC",
style: ["favicon"],
},
{
uri: uri5,
title: "foobar.org - much better than ABC, definitely better than XYZ",
style: ["favicon"],
},
],
});
info("two results (actions disabled)");
await check_autocomplete({
search: "abc",