1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This module exports a component used to register search providers and manage
7 * the connection between such providers and a UrlbarController.
12 ChromeUtils.defineESModuleGetters(lazy, {
13 ObjectUtils: "resource://gre/modules/ObjectUtils.sys.mjs",
14 PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
15 SkippableTimer: "resource:///modules/UrlbarUtils.sys.mjs",
16 UrlbarMuxer: "resource:///modules/UrlbarUtils.sys.mjs",
17 UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
18 UrlbarProvider: "resource:///modules/UrlbarUtils.sys.mjs",
19 UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs",
20 UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.sys.mjs",
21 UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs",
24 ChromeUtils.defineLazyGetter(lazy, "logger", () =>
25 lazy.UrlbarUtils.getLogger({ prefix: "ProvidersManager" })
28 // List of available local providers, each is implemented in its own jsm module
29 // and will track different queries internally by queryContext.
30 // When adding new providers please remember to update the list in metrics.yaml.
31 var localProviderModules = {
32 UrlbarProviderAboutPages:
33 "resource:///modules/UrlbarProviderAboutPages.sys.mjs",
34 UrlbarProviderActionsSearchMode:
35 "resource:///modules/UrlbarProviderActionsSearchMode.sys.mjs",
36 UrlbarProviderGlobalActions:
37 "resource:///modules/UrlbarProviderGlobalActions.sys.mjs",
38 UrlbarProviderAliasEngines:
39 "resource:///modules/UrlbarProviderAliasEngines.sys.mjs",
40 UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.sys.mjs",
41 UrlbarProviderBookmarkKeywords:
42 "resource:///modules/UrlbarProviderBookmarkKeywords.sys.mjs",
43 UrlbarProviderCalculator:
44 "resource:///modules/UrlbarProviderCalculator.sys.mjs",
45 UrlbarProviderClipboard:
46 "resource:///modules/UrlbarProviderClipboard.sys.mjs",
47 UrlbarProviderHeuristicFallback:
48 "resource:///modules/UrlbarProviderHeuristicFallback.sys.mjs",
49 UrlbarProviderHistoryUrlHeuristic:
50 "resource:///modules/UrlbarProviderHistoryUrlHeuristic.sys.mjs",
51 UrlbarProviderInputHistory:
52 "resource:///modules/UrlbarProviderInputHistory.sys.mjs",
53 UrlbarProviderInterventions:
54 "resource:///modules/UrlbarProviderInterventions.sys.mjs",
55 UrlbarProviderOmnibox: "resource:///modules/UrlbarProviderOmnibox.sys.mjs",
56 UrlbarProviderPlaces: "resource:///modules/UrlbarProviderPlaces.sys.mjs",
57 UrlbarProviderPrivateSearch:
58 "resource:///modules/UrlbarProviderPrivateSearch.sys.mjs",
59 UrlbarProviderQuickSuggest:
60 "resource:///modules/UrlbarProviderQuickSuggest.sys.mjs",
61 UrlbarProviderQuickSuggestContextualOptIn:
62 "resource:///modules/UrlbarProviderQuickSuggestContextualOptIn.sys.mjs",
63 UrlbarProviderRecentSearches:
64 "resource:///modules/UrlbarProviderRecentSearches.sys.mjs",
65 UrlbarProviderRemoteTabs:
66 "resource:///modules/UrlbarProviderRemoteTabs.sys.mjs",
67 UrlbarProviderRestrictKeywords:
68 "resource:///modules/UrlbarProviderRestrictKeywords.sys.mjs",
69 UrlbarProviderRestrictKeywordsAutofill:
70 "resource:///modules/UrlbarProviderRestrictKeywordsAutofill.sys.mjs",
71 UrlbarProviderSearchTips:
72 "resource:///modules/UrlbarProviderSearchTips.sys.mjs",
73 UrlbarProviderSearchSuggestions:
74 "resource:///modules/UrlbarProviderSearchSuggestions.sys.mjs",
75 UrlbarProviderTabToSearch:
76 "resource:///modules/UrlbarProviderTabToSearch.sys.mjs",
77 UrlbarProviderTokenAliasEngines:
78 "resource:///modules/UrlbarProviderTokenAliasEngines.sys.mjs",
79 UrlbarProviderTopSites: "resource:///modules/UrlbarProviderTopSites.sys.mjs",
80 UrlbarProviderUnitConversion:
81 "resource:///modules/UrlbarProviderUnitConversion.sys.mjs",
84 // List of available local muxers, each is implemented in its own jsm module.
85 var localMuxerModules = {
86 UrlbarMuxerUnifiedComplete:
87 "resource:///modules/UrlbarMuxerUnifiedComplete.sys.mjs",
90 const DEFAULT_MUXER = "UnifiedComplete";
93 * Class used to create a manager.
94 * The manager is responsible to keep a list of providers, instantiate query
95 * objects and pass those to the providers.
97 class ProvidersManager {
99 // Tracks the available providers. This is a sorted array, with HEURISTIC
100 // providers at the front.
102 this.providersByNotificationType = {
103 onEngagement: new Set(),
104 onImpression: new Set(),
105 onAbandonment: new Set(),
106 onSearchSessionEnd: new Set(),
108 for (let [symbol, module] of Object.entries(localProviderModules)) {
109 let { [symbol]: provider } = ChromeUtils.importESModule(module);
110 this.registerProvider(provider);
113 // Tracks ongoing Query instances by queryContext.
114 this.queries = new Map();
116 // Interrupt() allows to stop any running SQL query, some provider may be
117 // running a query that shouldn't be interrupted, and if so it should
118 // bump this through disableInterrupt and enableInterrupt.
119 this.interruptLevel = 0;
121 // This maps muxer names to muxers.
122 this.muxers = new Map();
123 for (let [symbol, module] of Object.entries(localMuxerModules)) {
124 let { [symbol]: muxer } = ChromeUtils.importESModule(module);
125 this.registerMuxer(muxer);
128 // These can be set by tests to increase or reduce the chunk delays.
129 // See _notifyResultsFromProvider for additional details.
130 // To improve dataflow and reduce UI work, when a result is added we may notify
131 // it to the controller after a delay, so that we can chunk results in that
132 // timeframe into a single call. See _notifyResultsFromProvider for details.
133 this.CHUNK_RESULTS_DELAY_MS = 16;
137 * Registers a provider object with the manager.
139 * @param {object} provider
140 * The provider object to register.
142 registerProvider(provider) {
143 if (!provider || !(provider instanceof lazy.UrlbarProvider)) {
144 throw new Error(`Trying to register an invalid provider`);
147 !Object.values(lazy.UrlbarUtils.PROVIDER_TYPE).includes(provider.type)
149 throw new Error(`Unknown provider type ${provider.type}`);
151 lazy.logger.info(`Registering provider ${provider.name}`);
153 if (provider.type == lazy.UrlbarUtils.PROVIDER_TYPE.HEURISTIC) {
154 // Keep heuristic providers in order at the front of the array. Find the
155 // first non-heuristic provider and insert the new provider there.
156 index = this.providers.findIndex(
157 p => p.type != lazy.UrlbarUtils.PROVIDER_TYPE.HEURISTIC
161 index = this.providers.length;
163 this.providers.splice(index, 0, provider);
165 for (const notificationType of Object.keys(
166 this.providersByNotificationType
168 if (typeof provider[notificationType] === "function") {
169 this.providersByNotificationType[notificationType].add(provider);
175 * Unregisters a previously registered provider object.
177 * @param {object} provider
178 * The provider object to unregister.
180 unregisterProvider(provider) {
181 lazy.logger.info(`Unregistering provider ${provider.name}`);
182 let index = this.providers.findIndex(p => p.name == provider.name);
184 this.providers.splice(index, 1);
187 Object.values(this.providersByNotificationType).forEach(providers =>
188 providers.delete(provider)
193 * Returns the provider with the given name.
195 * @param {string} name
197 * @returns {UrlbarProvider} The provider.
200 return this.providers.find(p => p.name == name);
204 * Registers a muxer object with the manager.
206 * @param {object} muxer
207 * a UrlbarMuxer object
209 registerMuxer(muxer) {
210 if (!muxer || !(muxer instanceof lazy.UrlbarMuxer)) {
211 throw new Error(`Trying to register an invalid muxer`);
213 lazy.logger.info(`Registering muxer ${muxer.name}`);
214 this.muxers.set(muxer.name, muxer);
218 * Unregisters a previously registered muxer object.
220 * @param {object} muxer
221 * a UrlbarMuxer object or name.
223 unregisterMuxer(muxer) {
224 let muxerName = typeof muxer == "string" ? muxer : muxer.name;
225 lazy.logger.info(`Unregistering muxer ${muxerName}`);
226 this.muxers.delete(muxerName);
232 * @param {object} queryContext
233 * The query context object
234 * @param {object} [controller]
235 * a UrlbarController instance
237 async startQuery(queryContext, controller = null) {
238 lazy.logger.info(`Query start "${queryContext.searchString}"`);
240 // Define the muxer to use.
241 let muxerName = queryContext.muxer || DEFAULT_MUXER;
242 lazy.logger.debug(`Using muxer ${muxerName}`);
243 let muxer = this.muxers.get(muxerName);
245 throw new Error(`Muxer with name ${muxerName} not found`);
248 // If the queryContext specifies a list of providers to use, filter on it,
249 // otherwise just pass the full list of providers.
250 let providers = queryContext.providers
251 ? this.providers.filter(p => queryContext.providers.includes(p.name))
254 queryContext.canceled = false;
256 // The tokenizer needs to synchronously check whether the first token is a
257 // keyword, thus here we must ensure the keywords cache is up.
258 await lazy.PlacesUtils.keywords.ensureCacheInitialized();
261 "Unable to ensure keyword cache is initialization. A keyword may not be \
262 detected at the beginning of the search string.",
267 // The query may have been canceled while awaiting for asynchronous work.
268 if (queryContext.canceled) {
272 // Apply tokenization.
273 lazy.UrlbarTokenizer.tokenize(queryContext);
275 // If there's a single source, we are in restriction mode.
276 if (queryContext.sources && queryContext.sources.length == 1) {
277 queryContext.restrictSource = queryContext.sources[0];
279 // Providers can use queryContext.sources to decide whether they want to be
281 // The sources may be defined in the context, then the whole search string
282 // can be used for searching. Otherwise sources are extracted from prefs and
283 // restriction tokens, then restriction tokens must be filtered out of the
285 let restrictToken = updateSourcesIfEmpty(queryContext);
287 queryContext.restrictToken = restrictToken;
288 // If the restriction token has an equivalent source, then set it as
290 if (lazy.UrlbarTokenizer.SEARCH_MODE_RESTRICT.has(restrictToken.value)) {
291 queryContext.restrictSource = queryContext.sources[0];
294 lazy.logger.debug(`Context sources ${queryContext.sources}`);
296 let query = new Query(queryContext, controller, muxer, providers);
297 this.queries.set(queryContext, query);
299 // The muxer and many providers depend on the search service and our search
300 // utils. Make sure they're initialized now (via UrlbarSearchUtils) so that
301 // all query-related urlbar modules don't need to do it.
303 await lazy.UrlbarSearchUtils.init();
305 // We continue anyway, because we want the user to be able to search their
306 // history and bookmarks even if search engines are not available.
309 if (query.canceled) {
317 * Cancels a running query.
319 * @param {object} queryContext The query context object
321 cancelQuery(queryContext) {
322 lazy.logger.info(`Query cancel "${queryContext.searchString}"`);
323 queryContext.canceled = true;
325 let query = this.queries.get(queryContext);
327 // The query object may have not been created yet, if the query was
328 // canceled immediately.
332 if (!this.interruptLevel) {
334 let db = lazy.PlacesUtils.promiseLargeCacheDBConnection();
338 this.queries.delete(queryContext);
342 * A provider can use this util when it needs to run a SQL query that can't
343 * be interrupted. Otherwise, when a query is canceled any running SQL query
344 * is interrupted abruptly.
346 * @param {Function} taskFn a Task to execute in the critical section.
348 async runInCriticalSection(taskFn) {
349 this.interruptLevel++;
353 this.interruptLevel--;
358 * Notifies all providers about changes in user engagement with the urlbar.
359 * This function centralizes the dispatch of engagement-related events to the
360 * appropriate providers based on the current state of interaction.
362 * @param {string} state
363 * The state of the engagement, one of: engagement, abandonment
364 * @param {UrlbarQueryContext} queryContext
365 * The engagement's query context, if available.
366 * @param {object} details
367 * An object that describes the search string and the picked result, if any.
368 * @param {UrlbarController} controller
369 * The controller associated with the engagement
371 notifyEngagementChange(state, queryContext, details = {}, controller) {
372 if (!["engagement", "abandonment"].includes(state)) {
373 lazy.logger.error(`Unsupported state for engagement change: ${state}`);
377 const visibleResults = controller.view?.visibleResults ?? [];
378 const visibleResultsByProviderName = new Map();
380 visibleResults.forEach((result, index) => {
381 const providerName = result.providerName;
382 let results = visibleResultsByProviderName.get(providerName);
385 visibleResultsByProviderName.set(providerName, results);
387 results.push({ index, result });
390 if (!details.isSessionOngoing) {
391 this.#notifyImpression(
392 this.providersByNotificationType.onImpression,
396 visibleResultsByProviderName,
397 state == "engagement" && details.result ? details : null
401 if (state === "engagement") {
402 if (details.result) {
403 this.#notifyEngagement(
404 this.providersByNotificationType.onEngagement,
411 this.#notifyAbandonment(
412 this.providersByNotificationType.onAbandonment,
415 visibleResultsByProviderName
419 if (!details.isSessionOngoing) {
420 this.#notifySearchSessionEnd(
421 this.providersByNotificationType.onSearchSessionEnd,
429 #notifyEngagement(engagementProviders, queryContext, controller, details) {
430 for (const provider of engagementProviders) {
431 if (details.result.providerName == provider.name) {
432 provider.tryMethod("onEngagement", queryContext, controller, details);
443 visibleResultsByProviderName,
446 for (const provider of impressionProviders) {
447 const providerVisibleResults =
448 visibleResultsByProviderName.get(provider.name) ?? [];
450 if (providerVisibleResults.length) {
456 providerVisibleResults,
467 visibleResultsByProviderName
469 for (const provider of abandomentProviders) {
470 if (visibleResultsByProviderName.has(provider.name)) {
471 provider.tryMethod("onAbandonment", queryContext, controller);
476 #notifySearchSessionEnd(
477 searchSessionEndProviders,
482 for (const provider of searchSessionEndProviders) {
484 "onSearchSessionEnd",
493 export var UrlbarProvidersManager = new ProvidersManager();
496 * Tracks a query status.
497 * Multiple queries can potentially be executed at the same time by different
498 * controllers. Each query has to track its own status and delays separately,
499 * to avoid conflicting with other ones.
503 * Initializes the query object.
505 * @param {object} queryContext
507 * @param {object} controller
508 * The controller to be notified
509 * @param {object} muxer
510 * The muxer to sort results
511 * @param {Array} providers
512 * Array of all the providers.
514 constructor(queryContext, controller, muxer, providers) {
515 this.context = queryContext;
516 this.context.results = [];
517 // Clear any state in the context object, since it could be reused by the
518 // caller and we don't want to port previous query state over.
519 this.context.pendingHeuristicProviders.clear();
520 this.context.deferUserSelectionProviders.clear();
521 this.unsortedResults = [];
523 this.controller = controller;
524 this.providers = providers;
525 this.started = false;
526 this.canceled = false;
528 // This is used as a last safety filter in add(), thus we keep an unmodified
530 this.acceptableSources = queryContext.sources.slice();
538 throw new Error("This Query has been started already");
542 // Check which providers should be queried by calling isActive on them.
543 let activeProviders = [];
544 let activePromises = [];
545 let maxPriority = -1;
546 for (let provider of this.providers) {
547 // This can be used by the provider to check the query is still running
548 // after executing async tasks:
549 // let instance = this.queryInstance;
551 // if (instance != this.queryInstance) {
552 // // Query was canceled or a new one started.
555 provider.queryInstance = this;
557 // Not all isActive implementations are async, so wrap the call in a
558 // promise so we can be sure we can call `then` on it. Note that
559 // Promise.resolve returns its arg directly if it's already a promise.
561 provider.tryMethod("isActive", this.context, this.controller)
564 if (isActive && !this.canceled) {
565 let priority = provider.tryMethod("getPriority", this.context);
566 if (priority >= maxPriority) {
567 // The provider's priority is at least as high as the max.
568 if (priority > maxPriority) {
569 // The provider's priority is higher than the max. Remove all
570 // previously added providers, since their priority is
571 // necessarily lower, by setting length to zero.
572 activeProviders.length = 0;
573 maxPriority = priority;
575 activeProviders.push(provider);
576 if (provider.deferUserSelection) {
577 this.context.deferUserSelectionProviders.add(provider.name);
582 .catch(ex => lazy.logger.error(ex))
586 // We have to wait for all isActive calls to finish because we want to query
587 // only the highest priority active providers as determined by the priority
589 await Promise.all(activePromises);
592 this.controller = null;
596 // Start querying active providers.
597 let startQuery = async provider => {
598 provider.logger.debug(
599 `Starting query for "${this.context.searchString}"`
601 let addedResult = false;
602 await provider.tryMethod("startQuery", this.context, (...args) => {
607 this.context.deferUserSelectionProviders.delete(provider.name);
611 let queryPromises = [];
612 for (let provider of activeProviders) {
613 // Track heuristic providers. later we'll use this Set to wait for them
614 // before returning results to the user.
615 if (provider.type == lazy.UrlbarUtils.PROVIDER_TYPE.HEURISTIC) {
616 this.context.pendingHeuristicProviders.add(provider.name);
618 startQuery(provider).finally(() => {
619 this.context.pendingHeuristicProviders.delete(provider.name);
624 if (!this._sleepTimer) {
625 // Tracks the delay timer. We will fire (in this specific case, cancel
626 // would do the same, since the callback is empty) the timer when the
627 // search is canceled, unblocking start().
628 this._sleepTimer = new lazy.SkippableTimer({
629 name: "Query provider timer",
630 time: lazy.UrlbarPrefs.get("delay"),
631 logger: provider.logger,
635 this._sleepTimer.promise.then(() =>
636 this.canceled ? undefined : startQuery(provider)
642 `Queried ${queryPromises.length} providers: ${activeProviders.map(
647 // Normally we wait for all the queries, but in case this is canceled we can
649 let cancelPromise = new Promise(resolve => {
650 this._cancelQueries = resolve;
652 await Promise.race([Promise.all(queryPromises), cancelPromise]);
654 // All the providers are done returning results, so we can stop chunking.
655 if (!this.canceled) {
656 await this._chunkTimer?.fire();
659 // Break cycles with the controller to avoid leaks.
660 this.controller = null;
664 * Cancels this query. Note: Invoking cancel multiple times is a no-op.
670 this.canceled = true;
671 this.context.deferUserSelectionProviders.clear();
672 for (let provider of this.providers) {
673 provider.logger.debug(
674 `Canceling query for "${this.context.searchString}"`
676 // Mark the instance as no more valid, see start() for details.
677 provider.queryInstance = null;
678 provider.tryMethod("cancelQuery", this.context);
680 this._chunkTimer?.cancel().catch(ex => lazy.logger.error(ex));
681 this._sleepTimer?.fire().catch(ex => lazy.logger.error(ex));
682 this._cancelQueries?.();
686 * Adds a result returned from a provider to the results set.
688 * @param {UrlbarProvider} provider The provider that returned the result.
689 * @param {object} result The result object.
691 add(provider, result) {
692 if (!(provider instanceof lazy.UrlbarProvider)) {
693 throw new Error("Invalid provider passed to the add callback");
696 // When this set is empty, we can display heuristic results early. We remove
697 // the provider from the list without checking result.heuristic since
698 // heuristic providers don't necessarily have to return heuristic results.
699 // We expect a provider with type HEURISTIC will return its heuristic
701 this.context.pendingHeuristicProviders.delete(provider.name);
703 // Stop returning results as soon as we've been canceled.
708 // In search mode, don't allow heuristic results in the following cases
709 // since they don't make sense:
710 // * When the search string is empty, or
711 // * In local search mode, except for autofill results
714 this.context.searchMode &&
715 (!this.context.trimmedSearchString ||
716 (!this.context.searchMode.engineName && !result.autofill))
721 // Check if the result source should be filtered out. Pay attention to the
722 // heuristic result though, that is supposed to be added regardless.
724 !this.acceptableSources.includes(result.source) &&
726 // Treat form history as searches for the purpose of acceptableSources.
727 (result.type != lazy.UrlbarUtils.RESULT_TYPE.SEARCH ||
728 result.source != lazy.UrlbarUtils.RESULT_SOURCE.HISTORY ||
729 !this.acceptableSources.includes(lazy.UrlbarUtils.RESULT_SOURCE.SEARCH))
734 // Filter out javascript results for safety. The provider is supposed to do
735 // it, but we don't want to risk leaking these out.
737 result.type != lazy.UrlbarUtils.RESULT_TYPE.KEYWORD &&
738 result.payload.url &&
739 result.payload.url.startsWith("javascript:") &&
740 !this.context.searchString.startsWith("javascript:") &&
741 lazy.UrlbarPrefs.get("filter.javascript")
746 result.providerName = provider.name;
747 result.providerType = provider.type;
748 this.unsortedResults.push(result);
750 this._notifyResultsFromProvider(provider);
753 _notifyResultsFromProvider(provider) {
754 // We use a timer to reduce UI flicker, by adding results in chunks.
755 if (!this._chunkTimer || this._chunkTimer.done) {
756 // Either there's no heuristic provider pending at all, or the previous
757 // timer is done, but we're still getting results. Start a short timer
758 // to chunk remaining results.
759 this._chunkTimer = new lazy.SkippableTimer({
761 callback: () => this._notifyResults(),
762 time: UrlbarProvidersManager.CHUNK_RESULTS_DELAY_MS,
763 logger: provider.logger,
766 !this.context.pendingHeuristicProviders.size &&
767 provider.type == lazy.UrlbarUtils.PROVIDER_TYPE.HEURISTIC
769 // All the active heuristic providers have returned results, we can skip
770 // the heuristic chunk timer and start showing results immediately.
771 this._chunkTimer.fire().catch(ex => lazy.logger.error(ex));
774 // Otherwise some timer is still ongoing and we'll wait for it.
778 this.muxer.sort(this.context, this.unsortedResults);
779 // We don't want to notify consumers if there are no results since they
780 // generally expect at least one result when notified, so bail, but only
781 // after nulling out the chunk timer above so that it will be restarted
782 // the next time results are added.
783 if (!this.context.results.length) {
787 this.context.firstResultChanged = !lazy.ObjectUtils.deepEqual(
788 this.context.firstResult,
789 this.context.results[0]
791 this.context.firstResult = this.context.results[0];
793 if (this.controller) {
794 this.controller.receiveResults(this.context);
800 * Updates in place the sources for a given UrlbarQueryContext.
802 * @param {UrlbarQueryContext} context The query context to examine
803 * @returns {object} The restriction token that was used to set sources, or
804 * undefined if there's no restriction token.
806 function updateSourcesIfEmpty(context) {
807 if (context.sources && context.sources.length) {
810 let acceptedSources = [];
811 // There can be only one restrict token per query.
812 let restrictToken = context.tokens.find(t =>
814 lazy.UrlbarTokenizer.TYPE.RESTRICT_HISTORY,
815 lazy.UrlbarTokenizer.TYPE.RESTRICT_BOOKMARK,
816 lazy.UrlbarTokenizer.TYPE.RESTRICT_TAG,
817 lazy.UrlbarTokenizer.TYPE.RESTRICT_OPENPAGE,
818 lazy.UrlbarTokenizer.TYPE.RESTRICT_SEARCH,
819 lazy.UrlbarTokenizer.TYPE.RESTRICT_TITLE,
820 lazy.UrlbarTokenizer.TYPE.RESTRICT_URL,
821 lazy.UrlbarTokenizer.TYPE.RESTRICT_ACTION,
825 // RESTRICT_TITLE and RESTRICT_URL do not affect query sources.
826 let restrictTokenType =
828 restrictToken.type != lazy.UrlbarTokenizer.TYPE.RESTRICT_TITLE &&
829 restrictToken.type != lazy.UrlbarTokenizer.TYPE.RESTRICT_URL
833 for (let source of Object.values(lazy.UrlbarUtils.RESULT_SOURCE)) {
834 // Skip sources that the context doesn't care about.
835 if (context.sources && !context.sources.includes(source)) {
838 // Check prefs and restriction tokens.
840 case lazy.UrlbarUtils.RESULT_SOURCE.BOOKMARKS:
842 restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_BOOKMARK ||
843 restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_TAG ||
844 (!restrictTokenType && lazy.UrlbarPrefs.get("suggest.bookmark"))
846 acceptedSources.push(source);
849 case lazy.UrlbarUtils.RESULT_SOURCE.HISTORY:
851 restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_HISTORY ||
852 (!restrictTokenType && lazy.UrlbarPrefs.get("suggest.history"))
854 acceptedSources.push(source);
857 case lazy.UrlbarUtils.RESULT_SOURCE.SEARCH:
859 restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_SEARCH ||
862 // We didn't check browser.urlbar.suggest.searches here, because it
863 // just controls search suggestions. If a search suggestion arrives
864 // here, we lost already, because we broke user's privacy by hitting
865 // the network. Thus, it's better to leave things go through and
866 // notice the bug, rather than hiding it with a filter.
867 acceptedSources.push(source);
870 case lazy.UrlbarUtils.RESULT_SOURCE.TABS:
872 restrictTokenType === lazy.UrlbarTokenizer.TYPE.RESTRICT_OPENPAGE ||
873 (!restrictTokenType && lazy.UrlbarPrefs.get("suggest.openpage"))
875 acceptedSources.push(source);
878 case lazy.UrlbarUtils.RESULT_SOURCE.OTHER_NETWORK:
879 if (!context.isPrivate && !restrictTokenType) {
880 acceptedSources.push(source);
883 case lazy.UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL:
884 case lazy.UrlbarUtils.RESULT_SOURCE.ADDON:
886 if (!restrictTokenType) {
887 acceptedSources.push(source);
892 context.sources = acceptedSources;
893 return restrictToken;