commit 21800a1aa98c0cebfb60d053a6a39ec2620827bc
parent 792a8cf8b786f909d983351437bba5a6acf4604c
Author: Daisuke Akatsuka <daisuke@birchill.co.jp>
Date: Thu, 11 Dec 2025 01:12:04 +0000
Bug 1995227: Make title calculation lazily r=adw
Differential Revision: https://phabricator.services.mozilla.com/D274563
Diffstat:
8 files changed, 91 insertions(+), 96 deletions(-)
diff --git a/browser/components/urlbar/UrlbarResult.sys.mjs b/browser/components/urlbar/UrlbarResult.sys.mjs
@@ -277,26 +277,6 @@ export class UrlbarResult {
}
/**
- * Returns a title that could be used as a label for this result.
- *
- * @returns {string} The label to show in a simplified title / url view.
- */
- get title() {
- let value = this.#getTitleOrHighlights(this.payload);
- return !value || Array.isArray(value) ? "" : value;
- }
-
- /**
- * Returns an array of highlights for the title.
- *
- * @returns {Array} The array of highlights.
- */
- get titleHighlights() {
- let value = this.#getTitleOrHighlights(this.payloadHighlights);
- return Array.isArray(value) ? value : [];
- }
-
- /**
* Returns an icon url.
*
* @returns {string} url of the icon.
@@ -357,6 +337,11 @@ export class UrlbarResult {
}
}
+ let isTitle = payloadName == "title";
+ if (isTitle) {
+ payloadName = this.#getDisplayableTitlePayloadName();
+ }
+
let value = this.payload[payloadName];
if (!value) {
return {};
@@ -366,35 +351,55 @@ export class UrlbarResult {
value = lazy.UrlbarUtils.prepareUrlForDisplay(value);
}
+ let highlightable = value;
+ let highlightType;
+ if (isTitle) {
+ if (payloadName == "qsSuggestion") {
+ value = this.payload.qsSuggestion + " — " + this.payload.title;
+ } else if (payloadName == "url") {
+ // If there's no title, show the domain as the title. Not all valid URLs
+ // have a domain.
+ try {
+ value = highlightable = new URL(this.payload.url).URI.displayHostPort;
+ highlightType = lazy.UrlbarUtils.HIGHLIGHT.TYPED;
+ } catch (e) {}
+ }
+ }
+
if (typeof value == "string") {
value = value.substring(0, lazy.UrlbarUtils.MAX_TEXT_LENGTH);
}
- if (!options.tokens?.length || !this.#highlights?.[payloadName]) {
+ highlightType ??= this.#highlights?.[payloadName];
+
+ if (!options.tokens?.length || !highlightType) {
let cached = { value, options };
this.#displayValuesCache.set(payloadName, cached);
return cached;
}
- let type = this.#highlights[payloadName];
- let highlights = Array.isArray(value)
+ let highlights = Array.isArray(highlightable)
? value.map(subval =>
- lazy.UrlbarUtils.getTokenMatches(options.tokens, subval, type)
+ lazy.UrlbarUtils.getTokenMatches(
+ options.tokens,
+ subval,
+ highlightType
+ )
)
- : lazy.UrlbarUtils.getTokenMatches(options.tokens, value || "", type);
+ : lazy.UrlbarUtils.getTokenMatches(
+ options.tokens,
+ highlightable
+ ? highlightable.substring(0, lazy.UrlbarUtils.MAX_TEXT_LENGTH)
+ : "",
+ highlightType
+ );
let cached = { value, highlights, options };
this.#displayValuesCache.set(payloadName, cached);
return cached;
}
- /**
- * Returns title or highlights of given payload or payloadHighlights.
- *
- * @param {object} target payload or payloadHighlights
- * @returns {string|Array} The title or array of highlights.
- */
- #getTitleOrHighlights(target) {
+ #getDisplayableTitlePayloadName() {
switch (this.type) {
case lazy.UrlbarUtils.RESULT_TYPE.KEYWORD:
case lazy.UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
@@ -402,34 +407,28 @@ export class UrlbarResult {
case lazy.UrlbarUtils.RESULT_TYPE.OMNIBOX:
case lazy.UrlbarUtils.RESULT_TYPE.REMOTE_TAB:
if (this.payload.qsSuggestion) {
- if (this.payload == target) {
- // We will initially only be targeting en-US users with this
- // experiment but will need to change this to work properly with
- // l10n.
- return target.qsSuggestion + " — " + target.title;
- }
- return target.qsSuggestion;
+ return "qsSuggestion";
}
if (this.payload.fallbackTitle) {
- return target.fallbackTitle;
+ return "fallbackTitle";
}
if (this.payload.title) {
- return target.title;
+ return "title";
}
- return target.url;
+ return "url";
case lazy.UrlbarUtils.RESULT_TYPE.SEARCH:
if (this.payload.title) {
- return target.title;
+ return "title";
}
if (this.payload.providesSearchMode) {
return null;
}
if (this.payload.tail && this.payload.tailOffsetIndex >= 0) {
- return target.tail;
+ return "tail";
} else if (this.payload.suggestion) {
- return target.suggestion;
+ return "suggestion";
}
- return target.query;
+ return "query";
}
return null;
}
diff --git a/browser/components/urlbar/UrlbarView.sys.mjs b/browser/components/urlbar/UrlbarView.sys.mjs
@@ -2110,7 +2110,10 @@ export class UrlbarView {
title.removeAttribute("aria-label");
}
- this.#updateOverflowTooltip(title, result.title);
+ this.#updateOverflowTooltip(
+ title,
+ result.getDisplayableValueAndHighlights("title").value
+ );
let tagsContainer = item._elements.get("tagsContainer");
if (tagsContainer) {
@@ -3147,10 +3150,14 @@ export class UrlbarView {
}
this.#l10nCache.removeElementL10n(titleNode);
+
+ let titleAndHighlights = result.getDisplayableValueAndHighlights("title", {
+ tokens: this.#queryContext.tokens,
+ });
lazy.UrlbarUtils.addTextContentWithHighlights(
titleNode,
- result.title,
- result.titleHighlights
+ titleAndHighlights.value,
+ titleAndHighlights.highlights
);
}
@@ -3723,7 +3730,7 @@ export class UrlbarView {
title.textContent =
localSearchMode || engine
? this.#queryContext.searchString
- : result.title;
+ : result.getDisplayableValueAndHighlights("title").value;
// Set the restyled-search attribute so the action text and title
// separator are shown or hidden via CSS as appropriate.
diff --git a/browser/components/urlbar/private/YelpSuggestions.sys.mjs b/browser/components/urlbar/private/YelpSuggestions.sys.mjs
@@ -194,11 +194,6 @@ export class YelpSuggestions extends SuggestProvider {
}
}
- let titleHighlights = lazy.UrlbarUtils.getTokenMatches(
- queryContext.tokens,
- title,
- lazy.UrlbarUtils.HIGHLIGHT.TYPED
- );
let payload = {
url: url.toString(),
originalUrl: suggestion.url,
@@ -207,12 +202,17 @@ export class YelpSuggestions extends SuggestProvider {
},
iconBlob: suggestion.icon_blob,
};
- let payloadHighlights = {};
+ let highlights;
if (
lazy.UrlbarPrefs.get("yelpServiceResultDistinction") &&
suggestion.subjectType === lazy.YelpSubjectType.SERVICE
) {
+ let titleHighlights = lazy.UrlbarUtils.getTokenMatches(
+ queryContext.tokens,
+ title,
+ lazy.UrlbarUtils.HIGHLIGHT.TYPED
+ );
payload.titleL10n = {
id: "firefox-suggest-yelp-service-title",
args: {
@@ -224,15 +224,18 @@ export class YelpSuggestions extends SuggestProvider {
};
} else {
payload.title = title;
- payloadHighlights.title = titleHighlights;
+ highlights = {
+ title: lazy.UrlbarUtils.HIGHLIGHT.TYPED,
+ };
}
return new lazy.UrlbarResult({
+ queryContext,
type: lazy.UrlbarUtils.RESULT_TYPE.URL,
source: lazy.UrlbarUtils.RESULT_SOURCE.SEARCH,
...resultProperties,
payload,
- payloadHighlights,
+ highlights,
});
}
diff --git a/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs b/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs
@@ -564,7 +564,7 @@ class UrlbarInputTestUtils {
details.autofill = !!result.autofill;
details.image =
element.getElementsByClassName("urlbarView-favicon")[0]?.src;
- details.title = result.title;
+ details.title = result.getDisplayableValueAndHighlights("title").value;
details.tags = "tags" in result.payload ? result.payload.tags : [];
details.isSponsored = result.payload.isSponsored;
details.userContextId = result.payload.userContextId;
diff --git a/browser/components/urlbar/tests/browser/browser_paste_multi_lines.js b/browser/components/urlbar/tests/browser/browser_paste_multi_lines.js
@@ -154,7 +154,7 @@ const TEST_DATA = [
input: "\r\n\r\n\r\n\r\n\r\n",
expected: {
urlbar: "",
- title: "",
+ title: undefined,
type: UrlbarUtils.RESULT_TYPE.SEARCH,
},
},
diff --git a/browser/components/urlbar/tests/browser/browser_selectStaleResults.js b/browser/components/urlbar/tests/browser/browser_selectStaleResults.js
@@ -85,8 +85,8 @@ add_task(async function viewContainsStaleRows() {
let lastMatchingResultUpdatedPromise = TestUtils.waitForCondition(() => {
let row = UrlbarTestUtils.getRowAt(window, halfResults);
- console.log(row.result.title);
- return row.result.title.startsWith("xx");
+ let { value } = row.result.getDisplayableValueAndHighlights("title");
+ return value.startsWith("xx");
}, "Wait for the result to be updated");
// Type another "x" so that we search for "xx", but don't wait for the search
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest.js b/browser/components/urlbar/tests/quicksuggest/unit/test_quicksuggest.js
@@ -279,16 +279,15 @@ add_task(async function allEnabled_sponsoredEnabled_sponsoredSearch() {
// The title should include the full keyword and em dash, and the part of the
// title that the search string does not match should be highlighted.
let result = context.results[0];
+ let { value, highlights } = result.getDisplayableValueAndHighlights("title", {
+ tokens: context.tokens,
+ });
Assert.equal(
- result.title,
+ value,
`${SPONSORED_SEARCH_STRING} — Amp Suggestion`,
- "result.title should be correct"
- );
- Assert.deepEqual(
- result.titleHighlights,
- [],
- "result.titleHighlights should be correct"
+ "The title should be correct"
);
+ Assert.deepEqual(highlights, [], "The highlights should be correct");
});
// Tests with both `all` and sponsored enabled with a non-sponsored search
@@ -310,16 +309,15 @@ add_task(async function allEnabled_sponsoredEnabled_nonsponsoredSearch() {
// The title should include the full keyword and em dash, and the part of the
// title that the search string does not match should be highlighted.
let result = context.results[0];
+ let { value, highlights } = result.getDisplayableValueAndHighlights("title", {
+ tokens: context.tokens,
+ });
Assert.equal(
- result.title,
+ value,
`${NONSPONSORED_SEARCH_STRING} — Wikipedia Suggestion`,
- "result.title should be correct"
- );
- Assert.deepEqual(
- result.titleHighlights,
- [],
- "result.titleHighlights should be correct"
+ "The title should be correct"
);
+ Assert.deepEqual(highlights, [], "The highlights should be correct");
});
// Tests with both `all` and sponsored enabled with a search string that doesn't
diff --git a/browser/components/urlbar/tests/unit/test_providerPlaces.js b/browser/components/urlbar/tests/unit/test_providerPlaces.js
@@ -68,10 +68,7 @@ add_task(async function test_places() {
await controller.startQuery(context);
- info(
- "Results:\n" +
- context.results.map(m => `${m.title} - ${m.payload.url}`).join("\n")
- );
+ info("Results:\n" + context.results.map(m => m.payload.url).join("\n"));
Assert.equal(
context.results.length,
7,
@@ -102,7 +99,7 @@ add_task(async function test_places() {
"Test tab",
"Test history",
],
- context.results.map(m => m.title),
+ context.results.map(m => m.getDisplayableValueAndHighlights("title").value),
"Check match titles"
);
@@ -167,10 +164,7 @@ add_task(async function test_bookmarkBehaviorDisabled_tagged() {
await controller.startQuery(context);
- info(
- "Results:\n" +
- context.results.map(m => `${m.title} - ${m.payload.url}`).join("\n")
- );
+ info("Results:\n" + context.results.map(m => m.payload.url).join("\n"));
Assert.equal(
context.results.length,
2,
@@ -185,7 +179,7 @@ add_task(async function test_bookmarkBehaviorDisabled_tagged() {
Assert.deepEqual(
[searchString, "Test bookmark"],
- context.results.map(m => m.title),
+ context.results.map(m => m.getDisplayableValueAndHighlights("title").value),
"Check match titles"
);
@@ -218,10 +212,7 @@ add_task(async function test_bookmarkBehaviorDisabled_untagged() {
await controller.startQuery(context);
- info(
- "Results:\n" +
- context.results.map(m => `${m.title} - ${m.payload.url}`).join("\n")
- );
+ info("Results:\n" + context.results.map(m => m.payload.url).join("\n"));
Assert.equal(
context.results.length,
2,
@@ -236,7 +227,7 @@ add_task(async function test_bookmarkBehaviorDisabled_untagged() {
Assert.deepEqual(
[searchString, "Test bookmark"],
- context.results.map(m => m.title),
+ context.results.map(m => m.getDisplayableValueAndHighlights("title").value),
"Check match titles"
);
@@ -266,10 +257,7 @@ add_task(async function test_diacritics() {
await controller.startQuery(context);
- info(
- "Results:\n" +
- context.results.map(m => `${m.title} - ${m.payload.url}`).join("\n")
- );
+ info("Results:\n" + context.results.map(m => m.payload.url).join("\n"));
Assert.equal(
context.results.length,
2,
@@ -284,7 +272,7 @@ add_task(async function test_diacritics() {
Assert.deepEqual(
[searchString, "Test bookmark with accents in path"],
- context.results.map(m => m.title),
+ context.results.map(m => m.getDisplayableValueAndHighlights("title").value),
"Check match titles"
);