summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /toolkit/components/search/AppProvidedSearchEngine.sys.mjs
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz
firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/search/AppProvidedSearchEngine.sys.mjs')
-rw-r--r--toolkit/components/search/AppProvidedSearchEngine.sys.mjs185
1 files changed, 133 insertions, 52 deletions
diff --git a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
index a8db801ac4..7401ba115c 100644
--- a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
+++ b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
@@ -12,10 +12,95 @@ import {
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
+ RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs",
});
/**
+ * Handles loading application provided search engine icons from remote settings.
+ */
+class IconHandler {
+ #iconList = null;
+ #iconCollection = null;
+
+ /**
+ * Returns the icon for the record that matches the engine identifier
+ * and the preferred width.
+ *
+ * @param {string} engineIdentifier
+ * The identifier of the engine to match against.
+ * @param {number} preferredWidth
+ * The preferred with of the icon.
+ * @returns {string}
+ * An object URL that can be used to reference the contents of the specified
+ * source object.
+ */
+ async getIcon(engineIdentifier, preferredWidth) {
+ if (!this.#iconList) {
+ await this.#getIconList();
+ }
+
+ let iconRecords = this.#iconList.filter(r => {
+ return r.engineIdentifiers.some(i => {
+ if (i.endsWith("*")) {
+ return engineIdentifier.startsWith(i.slice(0, -1));
+ }
+ return engineIdentifier == i;
+ });
+ });
+
+ if (!iconRecords.length) {
+ console.warn("No icon found for", engineIdentifier);
+ return null;
+ }
+
+ // Default to the first record, in the event we don't have any records
+ // that match the width.
+ let iconRecord = iconRecords[0];
+ for (let record of iconRecords) {
+ // TODO: Bug 1655070. We should be using the closest size, but for now use
+ // an exact match.
+ if (record.imageSize == preferredWidth) {
+ iconRecord = record;
+ break;
+ }
+ }
+
+ let iconURL;
+ try {
+ iconURL = await this.#iconCollection.attachments.get(iconRecord);
+ } catch (ex) {
+ console.error(ex);
+ return null;
+ }
+ if (!iconURL) {
+ console.warn("Unable to find the icon for", engineIdentifier);
+ return null;
+ }
+ return URL.createObjectURL(
+ new Blob([iconURL.buffer]),
+ iconRecord.attachment.mimetype
+ );
+ }
+
+ /**
+ * Obtains the icon list from the remote settings collection.
+ */
+ async #getIconList() {
+ this.#iconCollection = lazy.RemoteSettings("search-config-icons");
+ try {
+ this.#iconList = await this.#iconCollection.get();
+ } catch (ex) {
+ console.error(ex);
+ this.#iconList = [];
+ }
+ if (!this.#iconList.length) {
+ console.error("Failed to obtain search engine icon list records");
+ }
+ }
+}
+
+/**
* AppProvidedSearchEngine represents a search engine defined by the
* search configuration.
*/
@@ -25,6 +110,20 @@ export class AppProvidedSearchEngine extends SearchEngine {
["suggestions", lazy.SearchUtils.URL_TYPE.SUGGEST_JSON],
["trending", lazy.SearchUtils.URL_TYPE.TRENDING_JSON],
]);
+ static iconHandler = new IconHandler();
+
+ /**
+ * @typedef {?Promise<string>}
+ * A promise for the blob URL of the icon. We save the promise to avoid
+ * reentrancy issues.
+ */
+ #blobURLPromise = null;
+
+ /**
+ * @typedef {?string}
+ * The identifier from the configuration.
+ */
+ #configurationId = null;
/**
* @param {object} options
@@ -51,26 +150,35 @@ export class AppProvidedSearchEngine extends SearchEngine {
this._extensionID = extensionId;
this._locale = config.webExtension.locale;
+ this.#configurationId = config.identifier;
this.#init(config);
this._loadSettings(settings);
}
/**
+ * Used to clean up the engine when it is removed. This will revoke the blob
+ * URL for the icon.
+ */
+ async cleanup() {
+ if (this.#blobURLPromise) {
+ URL.revokeObjectURL(await this.#blobURLPromise);
+ this.#blobURLPromise = null;
+ }
+ }
+
+ /**
* Update this engine based on new config, used during
* config upgrades.
* @param {object} options
* The options object.
*
- * @param {object} options.locale
- * The locale that is being used for the engine.
* @param {object} options.configuration
* The search engine configuration for application provided engines.
*/
- update({ locale, configuration } = {}) {
+ update({ configuration } = {}) {
this._urls = [];
- this._iconMapObj = null;
this.#init(configuration);
lazy.SearchUtils.notifyAction(this, lazy.SearchUtils.MODIFIED_TYPE.CHANGED);
}
@@ -89,24 +197,10 @@ export class AppProvidedSearchEngine extends SearchEngine {
* Returns true if the engine was updated, false otherwise.
*/
async updateIfNoNameChange({ configuration, locale }) {
- let newName;
- if (locale != "default") {
- newName = configuration.webExtension.searchProvider[locale].name;
- } else if (
- locale == "default" &&
- configuration.webExtension.default_locale
- ) {
- newName =
- configuration.webExtension.searchProvider[
- configuration.webExtension.default_locale
- ].name;
- } else {
- newName = configuration.webExtension.name;
- }
-
- if (this.name != newName.trim()) {
+ if (this.name != configuration.name.trim()) {
return false;
}
+
this.update({ locale, configuration });
return true;
}
@@ -145,6 +239,25 @@ export class AppProvidedSearchEngine extends SearchEngine {
}
/**
+ * Returns the icon URL for the search engine closest to the preferred width.
+ *
+ * @param {number} preferredWidth
+ * The preferred width of the image.
+ * @returns {Promise<string>}
+ * A promise that resolves to the URL of the icon.
+ */
+ async getIconURL(preferredWidth) {
+ if (this.#blobURLPromise) {
+ return this.#blobURLPromise;
+ }
+ this.#blobURLPromise = AppProvidedSearchEngine.iconHandler.getIcon(
+ this.#configurationId,
+ preferredWidth
+ );
+ return this.#blobURLPromise;
+ }
+
+ /**
* Creates a JavaScript object that represents this engine.
*
* @returns {object}
@@ -175,38 +288,6 @@ export class AppProvidedSearchEngine extends SearchEngine {
this._telemetryId += `-${engineConfig.telemetrySuffix}`;
}
- // Set the main icon URL for the engine.
- // let iconURL = searchProvider.favicon_url;
-
- // if (!iconURL) {
- // iconURL =
- // manifest.icons &&
- // extensionBaseURI.resolve(
- // lazy.ExtensionParent.IconDetails.getPreferredIcon(manifest.icons).icon
- // );
- // }
-
- // // Record other icons that the WebExtension has.
- // if (manifest.icons) {
- // let iconList = Object.entries(manifest.icons).map(icon => {
- // return {
- // width: icon[0],
- // height: icon[0],
- // url: extensionBaseURI.resolve(icon[1]),
- // };
- // });
- // for (let icon of iconList) {
- // this._addIconToMap(icon.size, icon.size, icon.url);
- // }
- // }
-
- // this._initWithDetails(config);
-
- // this._sendAttributionRequest = config.sendAttributionRequest ?? false; // TODO check if we need to this?
- // if (details.iconURL) {
- // this._setIcon(details.iconURL, true);
- // }
-
this._name = engineConfig.name.trim();
this._definedAliases =
engineConfig.aliases?.map(alias => `@${alias}`) ?? [];