Loading toolkit/components/search/AppProvidedSearchEngine.sys.mjs +16 −38 Original line number Diff line number Diff line Loading @@ -116,6 +116,10 @@ class IconHandler { await this.#buildIconMap(); } if (AppConstants.BASE_BROWSER_VERSION) { return this.#iconMap.get(engineIdentifier); } let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) Loading @@ -132,29 +136,7 @@ class IconHandler { * source object or null of there is no icon with the supplied width. */ async createIconURL(iconRecord) { let iconData; try { iconData = await this.#iconCollection.attachments.get(iconRecord); } catch (ex) { console.error(ex); } if (!iconData) { console.warn("Unable to find the attachment for", iconRecord.id); // Queue an update in case we haven't downloaded it yet. this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); this.#maybeQueueIdle(); return null; } if (iconData.record.last_modified != iconRecord.last_modified) { // The icon we have stored is out of date, queue an update so that we'll // download the new icon. this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); this.#maybeQueueIdle(); } return URL.createObjectURL( new Blob([iconData.buffer], { type: iconRecord.attachment.mimetype }) ); return iconRecord.url; } QueryInterface = ChromeUtils.generateQI(["nsIObserver"]); Loading Loading @@ -238,27 +220,23 @@ class IconHandler { * Obtains the icon list from the remote settings collection. */ async #buildIconMap() { let iconList = []; try { iconList = await this.#iconCollection.get(); this.#iconMap = new Map( Object.entries( await ( await fetch( "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ); } catch (ex) { console.error(ex); this.#iconMap = null; } if (!iconList.length) { if (!this.#iconMap) { console.error("Failed to obtain search engine icon list records"); } this.#iconMap = new Map(); for (let record of iconList) { let keys = new Set(record.engineIdentifiers.map(this.getKey)); for (let key of keys) { if (this.#iconMap.has(key)) { this.#iconMap.get(key).push(record); } else { this.#iconMap.set(key, [record]); } } } } /** Loading toolkit/components/search/SearchEngineSelector.sys.mjs +23 −24 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. Loading Loading @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } this._getConfigurationPromise = Promise.all([ this._getConfiguration(), this._getConfigurationOverrides(), ]); let remoteSettingsData = await this._getConfigurationPromise; this._configuration = remoteSettingsData[0]; this._configurationOverrides = remoteSettingsData[1]; delete this._getConfigurationPromise; if (!this._configuration?.length) { throw Components.Exception( "Failed to get engine data from Remote Settings", Cr.NS_ERROR_UNEXPECTED ); } if (!this._listenerAdded) { this._remoteConfig.on("sync", this._onConfigurationUpdated); this._remoteConfigOverrides.on( "sync", this._onConfigurationOverridesUpdated ); this._listenerAdded = true; } let { promise, resolve } = Promise.withResolvers(); this._getConfigurationPromise = promise; this._configuration = await ( await fetch( "chrome://global/content/search/base-browser-search-engines.json" ) ).json(); this._configurationOverrides = []; resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( Loading Loading @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do // not want them to interfere in any way. if (AppConstants.BASE_BROWSER_VERSION) { return; } this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { Loading @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do // not want them to interfere in any way. if (AppConstants.BASE_BROWSER_VERSION) { return; } this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { Loading toolkit/components/search/content/base-browser-search-engine-icons.json 0 → 100644 +18 −0 Original line number Diff line number Diff line { "ddg": [ { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-noai": [ { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "startpage": [ { "url": "chrome://global/content/search/startpage-16.png", "imageSize": 16 }, { "url": "chrome://global/content/search/startpage-32.png", "imageSize": 32 } ] } toolkit/components/search/content/base-browser-search-engines.json 0 → 100644 +74 −0 Original line number Diff line number Diff line [ { "base": { "aliases": ["duckduckgo", "ddg"], "classification": "general", "name": "DuckDuckGo", "urls": { "search": { "base": "https://duckduckgo.com/", "params": [], "searchTermParamName": "q" } } }, "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", "identifier": "ddg", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { "aliases": ["ddgnoai"], "classification": "general", "name": "DuckDuckGo (no AI)", "urls": { "search": { "base": "https://noai.duckduckgo.com/", "params": [], "searchTermParamName": "q" } } }, "id": "91687f02-56dd-4fef-ba26-bf139dff3166", "identifier": "ddg-noai", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { "aliases": ["startpage", "sp"], "classification": "general", "name": "Startpage", "urls": { "search": { "base": "https://www.startpage.com/sp/search", "params": [], "searchTermParamName": "q" } } }, "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", "identifier": "startpage", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "recordType": "defaultEngines", "globalDefault": "ddg", "globalDefaultPrivate": "ddg" }, { "recordType": "engineOrders", "orders": [ { "environment": { "allRegionsAndLocales": true }, "order": [ "ddg", "ddg-noai", "startpage" ] } ] } ] toolkit/components/search/content/duckduckgo.ico 0 → 100644 +2.73 KiB Loading image diff... Loading
toolkit/components/search/AppProvidedSearchEngine.sys.mjs +16 −38 Original line number Diff line number Diff line Loading @@ -116,6 +116,10 @@ class IconHandler { await this.#buildIconMap(); } if (AppConstants.BASE_BROWSER_VERSION) { return this.#iconMap.get(engineIdentifier); } let iconList = this.#iconMap.get(this.getKey(engineIdentifier)) || []; return iconList.filter(r => this.#identifierMatches(engineIdentifier, r.engineIdentifiers) Loading @@ -132,29 +136,7 @@ class IconHandler { * source object or null of there is no icon with the supplied width. */ async createIconURL(iconRecord) { let iconData; try { iconData = await this.#iconCollection.attachments.get(iconRecord); } catch (ex) { console.error(ex); } if (!iconData) { console.warn("Unable to find the attachment for", iconRecord.id); // Queue an update in case we haven't downloaded it yet. this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); this.#maybeQueueIdle(); return null; } if (iconData.record.last_modified != iconRecord.last_modified) { // The icon we have stored is out of date, queue an update so that we'll // download the new icon. this.#pendingUpdatesMap.set(iconRecord.id, iconRecord); this.#maybeQueueIdle(); } return URL.createObjectURL( new Blob([iconData.buffer], { type: iconRecord.attachment.mimetype }) ); return iconRecord.url; } QueryInterface = ChromeUtils.generateQI(["nsIObserver"]); Loading Loading @@ -238,27 +220,23 @@ class IconHandler { * Obtains the icon list from the remote settings collection. */ async #buildIconMap() { let iconList = []; try { iconList = await this.#iconCollection.get(); this.#iconMap = new Map( Object.entries( await ( await fetch( "chrome://global/content/search/base-browser-search-engine-icons.json" ) ).json() ) ); } catch (ex) { console.error(ex); this.#iconMap = null; } if (!iconList.length) { if (!this.#iconMap) { console.error("Failed to obtain search engine icon list records"); } this.#iconMap = new Map(); for (let record of iconList) { let keys = new Set(record.engineIdentifiers.map(this.getKey)); for (let key of keys) { if (this.#iconMap.has(key)) { this.#iconMap.get(key).push(record); } else { this.#iconMap.set(key, [record]); } } } } /** Loading
toolkit/components/search/SearchEngineSelector.sys.mjs +23 −24 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; /** * @typedef {import("../uniffi-bindgen-gecko-js/components/generated/RustSearch.sys.mjs").SearchEngineSelector} RustSearchEngineSelector * We use "Rust" above to avoid conflict with the class name for the JavaScript wrapper. Loading Loading @@ -92,30 +94,15 @@ export class SearchEngineSelector { return this._getConfigurationPromise; } this._getConfigurationPromise = Promise.all([ this._getConfiguration(), this._getConfigurationOverrides(), ]); let remoteSettingsData = await this._getConfigurationPromise; this._configuration = remoteSettingsData[0]; this._configurationOverrides = remoteSettingsData[1]; delete this._getConfigurationPromise; if (!this._configuration?.length) { throw Components.Exception( "Failed to get engine data from Remote Settings", Cr.NS_ERROR_UNEXPECTED ); } if (!this._listenerAdded) { this._remoteConfig.on("sync", this._onConfigurationUpdated); this._remoteConfigOverrides.on( "sync", this._onConfigurationOverridesUpdated ); this._listenerAdded = true; } let { promise, resolve } = Promise.withResolvers(); this._getConfigurationPromise = promise; this._configuration = await ( await fetch( "chrome://global/content/search/base-browser-search-engines.json" ) ).json(); this._configurationOverrides = []; resolve(this._configuration); if (lazy.SearchUtils.rustSelectorFeatureGate) { this.#selector.setSearchConfig( Loading Loading @@ -242,6 +229,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationUpdated({ data: { current } }) { // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do // not want them to interfere in any way. if (AppConstants.BASE_BROWSER_VERSION) { return; } this._configuration = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { Loading @@ -268,6 +261,12 @@ export class SearchEngineSelector { * The new configuration object */ _onConfigurationOverridesUpdated({ data: { current } }) { // tor-browser#43525: Even though RemoteSettings are a no-op for us, we do // not want them to interfere in any way. if (AppConstants.BASE_BROWSER_VERSION) { return; } this._configurationOverrides = current; if (lazy.SearchUtils.rustSelectorFeatureGate) { Loading
toolkit/components/search/content/base-browser-search-engine-icons.json 0 → 100644 +18 −0 Original line number Diff line number Diff line { "ddg": [ { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "ddg-noai": [ { "url": "chrome://global/content/search/duckduckgo.ico", "imageSize": 32 } ], "startpage": [ { "url": "chrome://global/content/search/startpage-16.png", "imageSize": 16 }, { "url": "chrome://global/content/search/startpage-32.png", "imageSize": 32 } ] }
toolkit/components/search/content/base-browser-search-engines.json 0 → 100644 +74 −0 Original line number Diff line number Diff line [ { "base": { "aliases": ["duckduckgo", "ddg"], "classification": "general", "name": "DuckDuckGo", "urls": { "search": { "base": "https://duckduckgo.com/", "params": [], "searchTermParamName": "q" } } }, "id": "04e99a38-13ee-47d8-8aa4-64482b3dea99", "identifier": "ddg", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { "aliases": ["ddgnoai"], "classification": "general", "name": "DuckDuckGo (no AI)", "urls": { "search": { "base": "https://noai.duckduckgo.com/", "params": [], "searchTermParamName": "q" } } }, "id": "91687f02-56dd-4fef-ba26-bf139dff3166", "identifier": "ddg-noai", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "base": { "aliases": ["startpage", "sp"], "classification": "general", "name": "Startpage", "urls": { "search": { "base": "https://www.startpage.com/sp/search", "params": [], "searchTermParamName": "q" } } }, "id": "927bbd9f-b2f3-48b4-8974-1c1148028f4d", "identifier": "startpage", "recordType": "engine", "variants": [{ "environment": { "allRegionsAndLocales": true } }] }, { "recordType": "defaultEngines", "globalDefault": "ddg", "globalDefaultPrivate": "ddg" }, { "recordType": "engineOrders", "orders": [ { "environment": { "allRegionsAndLocales": true }, "order": [ "ddg", "ddg-noai", "startpage" ] } ] } ]