Skip to content

Commit 05cb18a

Browse files
committed
Bug 1876743 - Enable cross-container Tab Search in Nightly. r=mseibert
Fixes code to properly run tests with the feature enabled. Fixes code not considering payload.userContextId is set to -1 for private windows. Fixes a bug in the _openTabs Map where multiple open tabs to the same url are not properly counted. Differential Revision: https://phabricator.services.mozilla.com/D200036
1 parent 4e854ab commit 05cb18a

12 files changed

+243
-54
lines changed

browser/app/profile/firefox.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,11 @@ pref("browser.urlbar.switchTabs.adoptIntoActiveWindow", false);
556556

557557
// Controls whether searching for open tabs returns tabs from any container
558558
// or only from the current container.
559+
#ifdef NIGHTLY_BUILD
560+
pref("browser.urlbar.switchTabs.searchAllContainers", true);
561+
#else
559562
pref("browser.urlbar.switchTabs.searchAllContainers", false);
563+
#endif
560564

561565
// Whether addresses and search results typed into the address bar
562566
// should be opened in new tabs by default.

browser/components/sessionstore/test/browser_restore_container_tabs_oa.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
"use strict";
66

7+
const { UrlbarProviderOpenTabs } = ChromeUtils.importESModule(
8+
"resource:///modules/UrlbarProviderOpenTabs.sys.mjs"
9+
);
10+
711
const PATH = "browser/browser/components/sessionstore/test/empty.html";
812

913
/* import-globals-from ../../../base/content/test/tabs/helper_origin_attrs_testing.js */
@@ -118,6 +122,13 @@ add_task(async function testRestore() {
118122
"Should have restore data for the closed window"
119123
);
120124

125+
Assert.equal(
126+
0,
127+
(await UrlbarProviderOpenTabs.getDatabaseRegisteredOpenTabsForTests())
128+
.length,
129+
"No registered open pages should be left"
130+
);
131+
121132
// Now restore the window
122133
newWin = SessionStore.undoCloseWindow(0);
123134

@@ -228,4 +239,11 @@ add_task(async function testRestore() {
228239
}
229240

230241
await BrowserTestUtils.closeWindow(newWin);
242+
243+
Assert.equal(
244+
0,
245+
(await UrlbarProviderOpenTabs.getDatabaseRegisteredOpenTabsForTests())
246+
.length,
247+
"No registered open pages should be left"
248+
);
231249
});

browser/components/urlbar/UrlbarInput.sys.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,10 @@ export class UrlbarInput {
10941094
Services.io.newURI(url),
10951095
true,
10961096
loadOpts,
1097-
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers")
1097+
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers") &&
1098+
lazy.UrlbarProviderOpenTabs.isNonPrivateUserContextId(
1099+
result.payload.userContextId
1100+
)
10981101
? result.payload.userContextId
10991102
: null
11001103
);

browser/components/urlbar/UrlbarMuxerUnifiedComplete.sys.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const lazy = {};
1616
ChromeUtils.defineESModuleGetters(lazy, {
1717
QuickSuggest: "resource:///modules/QuickSuggest.sys.mjs",
1818
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
19+
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
1920
UrlbarProviderQuickSuggest:
2021
"resource:///modules/UrlbarProviderQuickSuggest.sys.mjs",
2122
UrlbarProviderTabToSearch:
@@ -40,7 +41,10 @@ function makeMapKeyForTabResult(result) {
4041
return UrlbarUtils.tupleString(
4142
result.payload.url,
4243
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers") &&
43-
result.type == UrlbarUtils.RESULT_TYPE.TAB_SWITCH
44+
result.type == UrlbarUtils.RESULT_TYPE.TAB_SWITCH &&
45+
lazy.UrlbarProviderOpenTabs.isNonPrivateUserContextId(
46+
result.payload.userContextId
47+
)
4448
? result.payload.userContextId
4549
: undefined
4650
);

browser/components/urlbar/UrlbarProviderInputHistory.sys.mjs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const SQL_ADAPTIVE_QUERY = `/* do not warn (bug 487789) */
6969
JOIN moz_places h ON h.id = i.place_id
7070
LEFT JOIN moz_openpages_temp t
7171
ON t.url = h.url
72-
AND t.userContextId = :userContextId
72+
AND (t.userContextId = :userContextId OR (t.userContextId <> -1 AND :userContextId IS NULL))
7373
WHERE AUTOCOMPLETE_MATCH(NULL, h.url,
7474
IFNULL(btitle, h.title), tags,
7575
h.visit_count, h.typed, bookmarked,
@@ -252,11 +252,12 @@ class ProviderInputHistory extends UrlbarProvider {
252252
search_string: queryContext.searchString.toLowerCase(),
253253
matchBehavior: Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE,
254254
searchBehavior: lazy.UrlbarPrefs.get("defaultBehavior"),
255-
userContextId:
256-
lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
257-
queryContext.userContextId,
258-
queryContext.isPrivate
259-
),
255+
userContextId: lazy.UrlbarPrefs.get("switchTabs.searchAllContainers")
256+
? lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
257+
null,
258+
queryContext.isPrivate
259+
)
260+
: queryContext.userContextId,
260261
maxResults: queryContext.maxResults,
261262
},
262263
];

browser/components/urlbar/UrlbarProviderOpenTabs.sys.mjs

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,48 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
7575

7676
/**
7777
* Maps the open tabs by userContextId.
78+
* Each entry is a Map of url => count.
7879
*/
7980
static _openTabs = new Map();
8081

8182
/**
82-
* Return urls that is opening on given user context id.
83+
* Return unique urls that are open for given user context id.
8384
*
8485
* @param {integer} userContextId Containers user context id
85-
* @param {boolean} isInPrivateWindow In private browsing window or not
86+
* @param {boolean} [isInPrivateWindow] In private browsing window or not
8687
* @returns {Array} urls
8788
*/
88-
static getOpenTabs(userContextId, isInPrivateWindow) {
89+
static getOpenTabs(userContextId, isInPrivateWindow = false) {
8990
userContextId = UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
9091
userContextId,
9192
isInPrivateWindow
9293
);
93-
return UrlbarProviderOpenTabs._openTabs.get(userContextId);
94+
return Array.from(
95+
UrlbarProviderOpenTabs._openTabs.get(userContextId)?.keys() ?? []
96+
);
9497
}
9598

9699
/**
97-
* Return userContextId that will be used in moz_openpages_temp table.
100+
* Return urls registered in the memory table.
101+
* This is mostly for testing purposes.
102+
*
103+
* @returns {Array} Array of {url, userContextId, count} objects.
104+
*/
105+
static async getDatabaseRegisteredOpenTabsForTests() {
106+
let conn = await lazy.PlacesUtils.promiseLargeCacheDBConnection();
107+
let rows = await conn.execute(
108+
"SELECT url, userContextId, open_count FROM moz_openpages_temp"
109+
);
110+
return rows.map(r => ({
111+
url: r.getResultByIndex(0),
112+
userContextId: r.getResultByIndex(1),
113+
count: r.getResultByIndex(2),
114+
}));
115+
}
116+
117+
/**
118+
* Return userContextId that is used in the moz_openpages_temp table and
119+
* returned as part of the payload. It differs only for private windows.
98120
*
99121
* @param {integer} userContextId Containers user context id
100122
* @param {boolean} isInPrivateWindow In private browsing window or not
@@ -104,6 +126,26 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
104126
return isInPrivateWindow ? PRIVATE_USER_CONTEXT_ID : userContextId;
105127
}
106128

129+
/**
130+
* Return whether the provided userContextId is for a non-private tab.
131+
*
132+
* @param {integer} userContextId the userContextId to evaluate
133+
* @returns {boolean}
134+
*/
135+
static isNonPrivateUserContextId(userContextId) {
136+
return userContextId != PRIVATE_USER_CONTEXT_ID;
137+
}
138+
139+
/**
140+
* Return whether the provided userContextId is for a container.
141+
*
142+
* @param {integer} userContextId the userContextId to evaluate
143+
* @returns {boolean}
144+
*/
145+
static isContainerUserContextId(userContextId) {
146+
return userContextId > 0;
147+
}
148+
107149
/**
108150
* Copy over cached open tabs to the memory table once the Urlbar
109151
* connection has been initialized.
@@ -113,9 +155,11 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
113155
// Must be set before populating.
114156
UrlbarProviderOpenTabs.memoryTableInitialized = true;
115157
// Populate the table with the current cached tabs.
116-
for (let [userContextId, urls] of UrlbarProviderOpenTabs._openTabs) {
117-
for (let url of urls) {
118-
await addToMemoryTable(url, userContextId).catch(console.error);
158+
for (let [userContextId, entries] of UrlbarProviderOpenTabs._openTabs) {
159+
for (let [url, count] of entries) {
160+
await addToMemoryTable(url, userContextId, count).catch(
161+
console.error
162+
);
119163
}
120164
}
121165
});
@@ -138,10 +182,12 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
138182
isInPrivateWindow
139183
);
140184

141-
if (!UrlbarProviderOpenTabs._openTabs.has(userContextId)) {
142-
UrlbarProviderOpenTabs._openTabs.set(userContextId, []);
185+
let entries = UrlbarProviderOpenTabs._openTabs.get(userContextId);
186+
if (!entries) {
187+
entries = new Map();
188+
UrlbarProviderOpenTabs._openTabs.set(userContextId, entries);
143189
}
144-
UrlbarProviderOpenTabs._openTabs.get(userContextId).push(url);
190+
entries.set(url, (entries.get(url) ?? 0) + 1);
145191
await addToMemoryTable(url, userContextId).catch(console.error);
146192
}
147193

@@ -163,13 +209,19 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
163209
isInPrivateWindow
164210
);
165211

166-
let openTabs = UrlbarProviderOpenTabs._openTabs.get(userContextId);
167-
if (openTabs) {
168-
let index = openTabs.indexOf(url);
169-
if (index != -1) {
170-
openTabs.splice(index, 1);
171-
await removeFromMemoryTable(url, userContextId).catch(console.error);
212+
let entries = UrlbarProviderOpenTabs._openTabs.get(userContextId);
213+
if (entries) {
214+
let oldCount = entries.get(url);
215+
if (oldCount == 0) {
216+
console.error("Tried to unregister a non registered open tab");
217+
return;
172218
}
219+
if (oldCount == 1) {
220+
entries.delete(url);
221+
} else {
222+
entries.set(url, oldCount - 1);
223+
}
224+
await removeFromMemoryTable(url, userContextId).catch(console.error);
173225
}
174226
}
175227

@@ -222,9 +274,10 @@ export class UrlbarProviderOpenTabs extends UrlbarProvider {
222274
*
223275
* @param {string} url Address of the page
224276
* @param {number} userContextId Containers user context id
277+
* @param {number} [count] The number of times the page is open
225278
* @returns {Promise} resolved after the addition.
226279
*/
227-
async function addToMemoryTable(url, userContextId) {
280+
async function addToMemoryTable(url, userContextId, count = 1) {
228281
if (!UrlbarProviderOpenTabs.memoryTableInitialized) {
229282
return;
230283
}
@@ -239,11 +292,11 @@ async function addToMemoryTable(url, userContextId) {
239292
FROM moz_openpages_temp
240293
WHERE url = :url
241294
AND userContextId = :userContextId ),
242-
1
295+
:count
243296
)
244297
)
245298
`,
246-
{ url, userContextId }
299+
{ url, userContextId, count }
247300
);
248301
});
249302
}

browser/components/urlbar/UrlbarProviderPlaces.sys.mjs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function defaultQuery(conditions = "") {
6868
FROM moz_places h
6969
LEFT JOIN moz_openpages_temp t
7070
ON t.url = h.url
71-
AND (:userContextId IS NULL OR t.userContextId = :userContextId)
71+
AND (t.userContextId = :userContextId OR (t.userContextId <> -1 AND :userContextId IS NULL))
7272
WHERE ${PAGES_FRECENCY_FIELD} <> 0
7373
AND CASE WHEN bookmarked
7474
THEN
@@ -95,7 +95,7 @@ const SQL_SWITCHTAB_QUERY = `SELECT :query_type, t.url, t.url, NULL, NULL, NULL,
9595
FROM moz_openpages_temp t
9696
LEFT JOIN moz_places h ON h.url_hash = hash(t.url) AND h.url = t.url
9797
WHERE h.id IS NULL
98-
AND (:userContextId IS NULL OR t.userContextId = :userContextId)
98+
AND (t.userContextId = :userContextId OR (t.userContextId <> -1 AND :userContextId IS NULL))
9999
AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL,
100100
NULL, NULL, NULL, t.open_count,
101101
:matchBehavior, :searchBehavior, NULL)
@@ -169,7 +169,8 @@ function makeMapKeyForResult(url, match) {
169169
return UrlbarUtils.tupleString(
170170
url,
171171
action?.type == "switchtab" &&
172-
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers")
172+
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers") &&
173+
lazy.UrlbarProviderOpenTabs.isNonPrivateUserContextId(match.userContextId)
173174
? match.userContextId
174175
: undefined
175176
);
@@ -469,12 +470,6 @@ function Search(queryContext, listener, provider) {
469470
this._filterOnHost = engine.searchUrlDomain;
470471
}
471472

472-
this._userContextId =
473-
lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
474-
this._userContextId,
475-
this._inPrivateWindow
476-
);
477-
478473
// Use the original string here, not the stripped one, so the tokenizer can
479474
// properly recognize token types.
480475
let { tokens } = lazy.UrlbarTokenizer.tokenize({
@@ -1298,7 +1293,10 @@ Search.prototype = {
12981293
params.userContextId = lazy.UrlbarPrefs.get(
12991294
"switchTabs.searchAllContainers"
13001295
)
1301-
? null
1296+
? lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
1297+
null,
1298+
this._inPrivateWindow
1299+
)
13021300
: this._userContextId;
13031301

13041302
if (this._filterOnHost) {
@@ -1325,7 +1323,10 @@ Search.prototype = {
13251323
// original search string.
13261324
searchString: this._keywordFilteredSearchString,
13271325
userContextId: lazy.UrlbarPrefs.get("switchTabs.searchAllContainers")
1328-
? null
1326+
? lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
1327+
null,
1328+
this._inPrivateWindow
1329+
)
13291330
: this._userContextId,
13301331
maxResults: this._maxResults,
13311332
},

browser/components/urlbar/UrlbarUtils.sys.mjs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
2121
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
2222
UrlbarProviderInterventions:
2323
"resource:///modules/UrlbarProviderInterventions.sys.mjs",
24+
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
2425
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
2526
UrlbarProviderSearchTips:
2627
"resource:///modules/UrlbarProviderSearchTips.sys.mjs",
@@ -2129,8 +2130,10 @@ export class UrlbarQueryContext {
21292130
this.deferUserSelectionProviders = new Set();
21302131
this.trimmedSearchString = this.searchString.trim();
21312132
this.userContextId =
2132-
options.userContextId ||
2133-
Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
2133+
lazy.UrlbarProviderOpenTabs.getUserContextIdForOpenPagesTable(
2134+
options.userContextId,
2135+
this.isPrivate
2136+
) || Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
21342137
}
21352138

21362139
/**

browser/components/urlbar/UrlbarView.sys.mjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
1313
"resource://gre/modules/ContextualIdentityService.sys.mjs",
1414
L10nCache: "resource:///modules/UrlbarUtils.sys.mjs",
1515
ObjectUtils: "resource://gre/modules/ObjectUtils.sys.mjs",
16+
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.sys.mjs",
1617
UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
1718
UrlbarProviderQuickSuggest:
1819
"resource:///modules/UrlbarProviderQuickSuggest.sys.mjs",
@@ -2631,7 +2632,9 @@ export class UrlbarView {
26312632
if (
26322633
lazy.UrlbarPrefs.get("switchTabs.searchAllContainers") &&
26332634
result.type == lazy.UrlbarUtils.RESULT_TYPE.TAB_SWITCH &&
2634-
result.payload.userContextId
2635+
lazy.UrlbarProviderOpenTabs.isContainerUserContextId(
2636+
result.payload.userContextId
2637+
)
26352638
) {
26362639
let label = lazy.ContextualIdentityService.getUserContextLabel(
26372640
result.payload.userContextId

0 commit comments

Comments
 (0)