Backed out changeset 23c9c6b2dc81 (bug 1490527) per developer's request
authorNoemi Erli <nerli@mozilla.com>
Tue, 18 Sep 2018 22:06:32 +0300
changeset 437005 2320823921ee0d3d8ffb1e3618bbb1f93e61878d
parent 437004 34e2583a8fee9f8bc937b61d268f73fc59384796
child 437006 0727f57a291f43fc380f29ed9a1e2c23a16934c8
push id34667
push useraiakab@mozilla.com
push dateWed, 19 Sep 2018 02:13:23 +0000
treeherdermozilla-central@3857cbe7b717 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1490527
milestone64.0a1
backs out23c9c6b2dc81eb29930487af76d48cb2332e84a2
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 23c9c6b2dc81 (bug 1490527) per developer's request
toolkit/components/places/UnifiedComplete.js
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -15,16 +15,54 @@ const MS_PER_DAY = 86400000; // 24 * 60 
 const {
   MATCH_ANYWHERE,
   MATCH_BOUNDARY_ANYWHERE,
   MATCH_BOUNDARY,
   MATCH_BEGINNING,
   MATCH_BEGINNING_CASE_SENSITIVE,
 } = Ci.mozIPlacesAutoComplete;
 
+// Values for browser.urlbar.insertMethod
+const INSERTMETHOD = {
+  APPEND: 0, // Just append new results.
+  MERGE_RELATED: 1, // Merge previous and current results if search strings are related
+  MERGE: 2, // Always merge previous and current results
+};
+
+// Prefs are defined as [pref name, default value] or [pref name, [default
+// value, nsIPrefBranch getter method name]].  In the former case, the getter
+// method name is inferred from the typeof the default value.
+const PREF_URLBAR_BRANCH = "browser.urlbar.";
+const PREF_URLBAR_DEFAULTS = new Map([
+  ["autocomplete.enabled", true],
+  ["autoFill", true],
+  ["autoFill.searchEngines", false],
+  ["autoFill.stddevMultiplier", [0.0, "getFloatPref"]],
+  ["restyleSearches", false],
+  ["delay", 50],
+  ["matchBehavior", MATCH_BOUNDARY_ANYWHERE],
+  ["filter.javascript", true],
+  ["maxRichResults", 10],
+  ["suggest.history", true],
+  ["suggest.bookmark", true],
+  ["suggest.openpage", true],
+  ["suggest.history.onlyTyped", false],
+  ["suggest.searches", false],
+  ["maxCharsForSearchSuggestions", 20],
+  ["maxHistoricalSearchSuggestions", 0],
+  ["usepreloadedtopurls.enabled", true],
+  ["usepreloadedtopurls.expire_days", 14],
+  ["matchBuckets", "suggestion:4,general:Infinity"],
+  ["matchBucketsSearch", ""],
+  ["insertMethod", INSERTMETHOD.MERGE_RELATED],
+]);
+const PREF_OTHER_DEFAULTS = new Map([
+  ["keyword.enabled", true],
+]);
+
 // AutoComplete query type constants.
 // Describes the various types of queries that we can process rows for.
 const QUERYTYPE_FILTERED            = 0;
 const QUERYTYPE_AUTOFILL_ORIGIN     = 1;
 const QUERYTYPE_AUTOFILL_URL        = 2;
 const QUERYTYPE_ADAPTIVE            = 3;
 
 // This separator is used as an RTL-friendly way to split the title and tags.
@@ -33,16 +71,22 @@ const QUERYTYPE_ADAPTIVE            = 3;
 const TITLE_TAGS_SEPARATOR = " \u2013 ";
 
 // Telemetry probes.
 const TELEMETRY_1ST_RESULT = "PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS";
 const TELEMETRY_6_FIRST_RESULTS = "PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS";
 // The default frecency value used when inserting matches with unknown frecency.
 const FRECENCY_DEFAULT = 1000;
 
+// Extensions are allowed to add suggestions if they have registered a keyword
+// with the omnibox API. This is the maximum number of suggestions an extension
+// is allowed to add for a given search string.
+// This value includes the heuristic result.
+const MAXIMUM_ALLOWED_EXTENSION_MATCHES = 6;
+
 // After this time, we'll give up waiting for the extension to return matches.
 const MAXIMUM_ALLOWED_EXTENSION_TIME_MS = 3000;
 
 // By default we add remote tabs that have been used less than this time ago.
 // Any remaining remote tabs are added in queue if no other results are found.
 const RECENT_REMOTE_TAB_THRESHOLD_MS = 259200000; // 72 hours.
 
 // A regex that matches "single word" hostnames for whitelisting purposes.
@@ -87,16 +131,45 @@ const TOKEN_TO_BEHAVIOR_MAP = new Map([
   ["+", "tag"],
   ["%", "openpage"],
   ["~", "typed"],
   ["$", "searches"],
   ["#", "title"],
   ["@", "url"],
 ]);
 
+const MATCHTYPE = {
+  HEURISTIC: "heuristic",
+  GENERAL: "general",
+  SUGGESTION: "suggestion",
+  EXTENSION: "extension",
+};
+
+// Buckets for match insertion.
+// Every time a new match is returned, we go through each bucket in array order,
+// and look for the first one having available space for the given match type.
+// Each bucket is an array containing the following indices:
+//   0: The match type of the acceptable entries.
+//   1: available number of slots in this bucket.
+// There are different matchBuckets definition for different contexts, currently
+// a general one (matchBuckets) and a search one (matchBucketsSearch).
+//
+// First buckets. Anything with an Infinity frecency ends up here.
+const DEFAULT_BUCKETS_BEFORE = [
+  [MATCHTYPE.HEURISTIC, 1],
+  [MATCHTYPE.EXTENSION, MAXIMUM_ALLOWED_EXTENSION_MATCHES - 1],
+];
+// => USER DEFINED BUCKETS WILL BE INSERTED HERE <=
+//
+// Catch-all buckets. Anything remaining ends up here.
+const DEFAULT_BUCKETS_AFTER = [
+  [MATCHTYPE.SUGGESTION, Infinity],
+  [MATCHTYPE.GENERAL, Infinity],
+];
+
 // If a URL starts with one of these prefixes, then we don't provide search
 // suggestions for it.
 const DISALLOWED_URLLIKE_PREFIXES = [
   "http", "https", "ftp",
 ];
 
 // This SQL query fragment provides the following:
 //   - whether the entry is bookmarked (QUERYINDEX_BOOKMARKED)
@@ -329,27 +402,25 @@ const SQL_URL_PREFIX_BOOKMARKED_QUERY = 
 // Getters
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
 
 XPCOMUtils.defineLazyModuleGetters(this, {
-  BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
+  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
+  TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
+  Sqlite: "resource://gre/modules/Sqlite.jsm",
+  OS: "resource://gre/modules/osfile.jsm",
   ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
-  OS: "resource://gre/modules/osfile.jsm",
-  PlacesRemoteTabsAutocompleteProvider: "resource://gre/modules/PlacesRemoteTabsAutocompleteProvider.jsm",
   PlacesSearchAutocompleteProvider: "resource://gre/modules/PlacesSearchAutocompleteProvider.jsm",
-  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
+  PlacesRemoteTabsAutocompleteProvider: "resource://gre/modules/PlacesRemoteTabsAutocompleteProvider.jsm",
+  BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
   ProfileAge: "resource://gre/modules/ProfileAge.jsm",
-  Sqlite: "resource://gre/modules/Sqlite.jsm",
-  TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
-  UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
-  UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
 });
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "syncUsernamePref",
                                       "services.sync.username");
 
 function setTimeout(callback, ms) {
   let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   timer.initWithCallback(callback, ms, timer.TYPE_ONE_SHOT);
@@ -478,16 +549,185 @@ XPCOMUtils.defineLazyGetter(this, "Switc
   },
 
   shutdown() {
     this._conn = null;
     this._queue.clear();
   },
 }));
 
+/**
+ * This helper keeps track of preferences and their updates.
+ */
+XPCOMUtils.defineLazyGetter(this, "Prefs", () => {
+  let branch = Services.prefs.getBranch(PREF_URLBAR_BRANCH);
+  let types = ["history", "bookmark", "openpage", "searches"];
+  let prefTypes = new Map([["boolean", "Bool"], ["string", "Char"], ["number", "Int"]]);
+
+  function readPref(pref) {
+    let prefs = branch;
+    let def = PREF_URLBAR_DEFAULTS.get(pref);
+    if (def === undefined) {
+      prefs = Services.prefs;
+      def = PREF_OTHER_DEFAULTS.get(pref);
+    }
+    if (def === undefined)
+      throw new Error("Trying to access an unknown pref " + pref);
+    let getterName;
+    if (!Array.isArray(def)) {
+      getterName = `get${prefTypes.get(typeof def)}Pref`;
+    } else {
+      if (def.length != 2) {
+        throw new Error("Malformed pref def: " + pref);
+      }
+      [def, getterName] = def;
+    }
+    return prefs[getterName](pref, def);
+  }
+
+  function getPrefValue(pref) {
+    switch (pref) {
+      case "matchBuckets": {
+        // Convert from pref char format to an array and add the default buckets.
+        let val = readPref(pref);
+        try {
+          val = PlacesUtils.convertMatchBucketsStringToArray(val);
+        } catch (ex) {
+          val = PlacesUtils.convertMatchBucketsStringToArray(PREF_URLBAR_DEFAULTS.get(pref));
+        }
+        return [ ...DEFAULT_BUCKETS_BEFORE,
+                ...val,
+                ...DEFAULT_BUCKETS_AFTER ];
+      }
+      case "matchBucketsSearch": {
+        // Convert from pref char format to an array and add the default buckets.
+        let val = readPref(pref);
+        if (val) {
+          // Convert from pref char format to an array and add the default buckets.
+          try {
+            val = PlacesUtils.convertMatchBucketsStringToArray(val);
+            return [ ...DEFAULT_BUCKETS_BEFORE,
+                    ...val,
+                    ...DEFAULT_BUCKETS_AFTER ];
+          } catch (ex) { /* invalid format, will just return matchBuckets */ }
+        }
+        return store.get("matchBuckets");
+      }
+      case "suggest.history.onlyTyped": {
+        // If history is not set, onlyTyped value should be ignored.
+        return store.get("suggest.history") && readPref(pref);
+      }
+      case "defaultBehavior": {
+        let val = 0;
+        for (let type of [...types, "history.onlyTyped"]) {
+          let behavior = type == "history.onlyTyped" ? "TYPED" : type.toUpperCase();
+          val |= store.get("suggest." + type) &&
+                      Ci.mozIPlacesAutoComplete["BEHAVIOR_" + behavior];
+        }
+        return val;
+      }
+      case "emptySearchDefaultBehavior": {
+        // Further restrictions to apply for "empty searches" (searching for "").
+        // The empty behavior is typed history, if history is enabled. Otherwise,
+        // it is bookmarks, if they are enabled. If both history and bookmarks are
+        // disabled, it defaults to open pages.
+        let val = Ci.mozIPlacesAutoComplete.BEHAVIOR_RESTRICT;
+        if (store.get("suggest.history")) {
+          val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_HISTORY |
+                Ci.mozIPlacesAutoComplete.BEHAVIOR_TYPED;
+        } else if (store.get("suggest.bookmark")) {
+          val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_BOOKMARK;
+        } else {
+          val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE;
+        }
+        return val;
+      }
+      case "matchBehavior": {
+        // Validate matchBehavior; default to MATCH_BOUNDARY_ANYWHERE.
+        let val = readPref(pref);
+        if (![MATCH_ANYWHERE, MATCH_BOUNDARY, MATCH_BEGINNING].includes(val)) {
+          val = MATCH_BOUNDARY_ANYWHERE;
+        }
+        return val;
+      }
+    }
+    return readPref(pref);
+  }
+
+  // Used to keep some pref values linked.
+  // TODO: remove autocomplete.enabled and rely only on suggest.* prefs once we
+  // can drop legacy add-ons compatibility.
+  let linkingPrefs = false;
+  function updateLinkedPrefs(changedPref = "") {
+    // Avoid re-entrance.
+    if (linkingPrefs)
+      return;
+    linkingPrefs = true;
+    try {
+      if (changedPref.startsWith("suggest.")) {
+        // A suggest pref changed, fix autocomplete.enabled.
+        branch.setBoolPref("autocomplete.enabled",
+                          types.some(type => store.get("suggest." + type)));
+      } else if (store.get("autocomplete.enabled")) {
+        // If autocomplete is enabled and all of the suggest.* prefs are disabled,
+        // reset the suggest.* prefs to their default value.
+        if (types.every(type => !store.get("suggest." + type))) {
+          for (let type of types) {
+            let def = PREF_URLBAR_DEFAULTS.get("suggest." + type);
+            branch.setBoolPref("suggest." + type, def);
+          }
+        }
+      } else {
+        // If autocomplete is disabled, deactivate all suggest preferences.
+        for (let type of types) {
+          branch.setBoolPref("suggest." + type, false);
+        }
+      }
+    } finally {
+      linkingPrefs = false;
+    }
+  }
+
+  let store = {
+    _map: new Map(),
+    get(pref) {
+      if (!this._map.has(pref))
+        this._map.set(pref, getPrefValue(pref));
+      return this._map.get(pref);
+    },
+    observe(subject, topic, data) {
+      let pref = data.replace(PREF_URLBAR_BRANCH, "");
+      if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref))
+        return;
+      this._map.delete(pref);
+      // Some prefs may influence others.
+      if (pref == "matchBuckets") {
+        this._map.delete("matchBucketsSearch");
+      } else if (pref == "suggest.history") {
+        this._map.delete("suggest.history.onlyTyped");
+      }
+      if (pref == "autocomplete.enabled" || pref.startsWith("suggest.")) {
+        this._map.delete("defaultBehavior");
+        this._map.delete("emptySearchDefaultBehavior");
+        updateLinkedPrefs(pref);
+      }
+    },
+    QueryInterface: ChromeUtils.generateQI([
+      Ci.nsIObserver,
+      Ci.nsISupportsWeakReference,
+    ]),
+  };
+  Services.prefs.addObserver(PREF_URLBAR_BRANCH, store, true);
+  Services.prefs.addObserver("keyword.enabled", store, true);
+
+  // On startup we must check that some prefs are linked.
+  updateLinkedPrefs();
+  return store;
+});
+
 // Preloaded Sites related
 
 function PreloadedSite(url, title) {
   this.uri = Services.io.newURI(url);
   this.title = title;
   this._matchTitle = title.toLowerCase();
   this._hasWWW = this.uri.host.startsWith("www.");
   this._hostWithoutWWW = this._hasWWW ? this.uri.host.slice(4)
@@ -652,20 +892,20 @@ function Search(searchString, searchPara
                 autocompleteSearch, prohibitSearchSuggestions, previousResult) {
   // We want to store the original string for case sensitive searches.
   this._originalSearchString = searchString;
   this._trimmedOriginalSearchString = searchString.trim();
   let [prefix, suffix] = stripPrefix(this._trimmedOriginalSearchString);
   this._searchString = Services.textToSubURI.unEscapeURIForUI("UTF-8", suffix);
   this._strippedPrefix = prefix.toLowerCase();
 
-  this._matchBehavior = UrlbarPrefs.get("matchBehavior");
+  this._matchBehavior = Prefs.get("matchBehavior");
   // Set the default behavior for this search.
-  this._behavior = this._searchString ? UrlbarPrefs.get("defaultBehavior")
-                                      : UrlbarPrefs.get("emptySearchDefaultBehavior");
+  this._behavior = this._searchString ? Prefs.get("defaultBehavior")
+                                      : Prefs.get("emptySearchDefaultBehavior");
 
   let params = new Set(searchParam.split(" "));
   this._enableActions = params.has("enable-actions");
   this._disablePrivateActions = params.has("disable-private-actions");
   this._inPrivateWindow = params.has("private-window");
   this._prohibitAutoFill = params.has("prohibit-autofill");
 
   let userContextId = searchParam.match(REGEXP_USER_CONTEXT_ID);
@@ -701,23 +941,23 @@ function Search(searchString, searchPara
   // Will be set later, if needed.
   result.setDefaultIndex(-1);
   this._result = result;
 
   this._previousSearchMatchTypes = [];
   for (let i = 0; previousResult && i < previousResult.matchCount; ++i) {
     let style = previousResult.getStyleAt(i);
     if (style.includes("heuristic")) {
-      this._previousSearchMatchTypes.push(UrlbarUtils.MATCHTYPE.HEURISTIC);
+      this._previousSearchMatchTypes.push(MATCHTYPE.HEURISTIC);
     } else if (style.includes("suggestion")) {
-      this._previousSearchMatchTypes.push(UrlbarUtils.MATCHTYPE.SUGGESTION);
+      this._previousSearchMatchTypes.push(MATCHTYPE.SUGGESTION);
     } else if (style.includes("extension")) {
-      this._previousSearchMatchTypes.push(UrlbarUtils.MATCHTYPE.EXTENSION);
+      this._previousSearchMatchTypes.push(MATCHTYPE.EXTENSION);
     } else {
-      this._previousSearchMatchTypes.push(UrlbarUtils.MATCHTYPE.GENERAL);
+      this._previousSearchMatchTypes.push(MATCHTYPE.GENERAL);
     }
   }
 
   // Used to limit the number of adaptive results.
   this._adaptiveCount = 0;
   this._extraAdaptiveRows = [];
 
   // Used to limit the number of remote tab results.
@@ -728,17 +968,17 @@ function Search(searchString, searchPara
   // Indeed this._result.matchCount may include matches from the previous search.
   this._currentMatchCount = 0;
 
   // These are used to avoid adding duplicate entries to the results.
   this._usedURLs = [];
   this._usedPlaceIds = new Set();
 
   // Counters for the number of matches per MATCHTYPE.
-  this._counts = Object.values(UrlbarUtils.MATCHTYPE)
+  this._counts = Object.values(MATCHTYPE)
                        .reduce((o, p) => { o[p] = 0; return o; }, {});
 }
 
 Search.prototype = {
   /**
    * Enables the desired AutoComplete behavior.
    *
    * @param type
@@ -817,17 +1057,17 @@ Search.prototype = {
         this.setBehavior(behavior);
         tokens.splice(i, 1);
       }
     }
 
     // Set the right JavaScript behavior based on our preference.  Note that the
     // preference is whether or not we should filter JavaScript, and the
     // behavior is if we should search it or not.
-    if (!UrlbarPrefs.get("filter.javascript")) {
+    if (!Prefs.get("filter.javascript")) {
       this.setBehavior("javascript");
     }
 
     return tokens;
   },
 
   /**
    * Stop this search.
@@ -915,27 +1155,27 @@ Search.prototype = {
     await this._checkPreloadedSitesExpiry();
 
     // Add the first heuristic result, if any.  Set _addingHeuristicFirstMatch
     // to true so that when the result is added, "heuristic" can be included in
     // its style.
     this._addingHeuristicFirstMatch = true;
     let hasHeuristic = await this._matchFirstHeuristicResult(conn);
     this._addingHeuristicFirstMatch = false;
-    this._cleanUpNonCurrentMatches(UrlbarUtils.MATCHTYPE.HEURISTIC);
+    this._cleanUpNonCurrentMatches(MATCHTYPE.HEURISTIC);
     if (!this.pending)
       return;
 
     // We sleep a little between adding the heuristicFirstMatch and matching
     // any other searches so we aren't kicking off potentially expensive
     // searches on every keystroke.
     // Though, if there's no heuristic result, we start searching immediately,
     // since autocomplete may be waiting for us.
     if (hasHeuristic) {
-      await this._sleep(UrlbarPrefs.get("delay"));
+      await this._sleep(Prefs.get("delay"));
       if (!this.pending)
         return;
     }
 
     // Only add extension suggestions if the first token is a registered keyword
     // and the search string has characters after the first token.
     let extensionsCompletePromise = Promise.resolve();
     if (this._searchTokens.length > 0 &&
@@ -947,36 +1187,36 @@ Search.prototype = {
     } else if (ExtensionSearchHandler.hasActiveInputSession()) {
       ExtensionSearchHandler.handleInputCancelled();
     }
 
     let searchSuggestionsCompletePromise = Promise.resolve();
     if (this._enableActions && this._searchTokens.length > 0) {
       // Limit the string sent for search suggestions to a maximum length.
       let searchString = this._searchTokens.join(" ")
-                             .substr(0, UrlbarPrefs.get("maxCharsForSearchSuggestions"));
+                             .substr(0, Prefs.get("maxCharsForSearchSuggestions"));
       // Avoid fetching suggestions if they are not required, private browsing
       // mode is enabled, or the search string may expose sensitive information.
       if (this.hasBehavior("searches") && !this._inPrivateWindow &&
           !this._prohibitSearchSuggestionsFor(searchString)) {
         searchSuggestionsCompletePromise = this._matchSearchSuggestions(searchString);
         if (this.hasBehavior("restrict")) {
           // Wait for the suggestions to be added.
           await searchSuggestionsCompletePromise;
-          this._cleanUpNonCurrentMatches(UrlbarUtils.MATCHTYPE.SUGGESTION);
+          this._cleanUpNonCurrentMatches(MATCHTYPE.SUGGESTION);
           // We're done if we're restricting to search suggestions.
           // Notify the result completion then stop the search.
           this._autocompleteSearch.finishSearch(true);
           return;
         }
       }
     }
     // In any case, clear previous suggestions.
     searchSuggestionsCompletePromise.then(() => {
-      this._cleanUpNonCurrentMatches(UrlbarUtils.MATCHTYPE.SUGGESTION);
+      this._cleanUpNonCurrentMatches(MATCHTYPE.SUGGESTION);
     });
 
     // Run the adaptive query first.
     await conn.executeCached(this._adaptiveQuery[0], this._adaptiveQuery[1],
                              this._onResultRow.bind(this));
     if (!this.pending)
       return;
 
@@ -1001,37 +1241,36 @@ Search.prototype = {
     for (let [query, params] of queries) {
       await conn.executeCached(query, params, this._onResultRow.bind(this));
       if (!this.pending)
         return;
     }
 
     // If we have some unused adaptive matches, add them now.
     while (this._extraAdaptiveRows.length &&
-           this._currentMatchCount < UrlbarPrefs.get("maxRichResults")) {
+           this._currentMatchCount < Prefs.get("maxRichResults")) {
       this._addFilteredQueryMatch(this._extraAdaptiveRows.shift());
     }
 
     // If we have some unused remote tab matches, add them now.
     while (this._extraRemoteTabRows.length &&
-          this._currentMatchCount < UrlbarPrefs.get("maxRichResults")) {
+          this._currentMatchCount < Prefs.get("maxRichResults")) {
       this._addMatch(this._extraRemoteTabRows.shift());
     }
 
     // Ideally we should wait until MATCH_BOUNDARY_ANYWHERE, but that query
     // may be really slow and we may end up showing old results for too long.
-    this._cleanUpNonCurrentMatches(UrlbarUtils.MATCHTYPE.GENERAL);
+    this._cleanUpNonCurrentMatches(MATCHTYPE.GENERAL);
 
     // If we do not have enough results, and our match type is
     // MATCH_BOUNDARY_ANYWHERE, search again with MATCH_ANYWHERE to get more
     // results.
-    let count = this._counts[UrlbarUtils.MATCHTYPE.GENERAL] +
-                this._counts[UrlbarUtils.MATCHTYPE.HEURISTIC];
+    let count = this._counts[MATCHTYPE.GENERAL] + this._counts[MATCHTYPE.HEURISTIC];
     if (this._matchBehavior == MATCH_BOUNDARY_ANYWHERE &&
-        count < UrlbarPrefs.get("maxRichResults")) {
+        count < Prefs.get("maxRichResults")) {
       this._matchBehavior = MATCH_ANYWHERE;
       for (let [query, params] of [ this._adaptiveQuery,
                                     this._searchQuery ]) {
         await conn.executeCached(query, params, this._onResultRow.bind(this));
         if (!this.pending)
           return;
       }
     }
@@ -1039,26 +1278,26 @@ Search.prototype = {
     this._matchPreloadedSites();
 
     // Ensure to fill any remaining space.
     await searchSuggestionsCompletePromise;
     await extensionsCompletePromise;
   },
 
   async _checkPreloadedSitesExpiry() {
-    if (!UrlbarPrefs.get("usepreloadedtopurls.enabled"))
+    if (!Prefs.get("usepreloadedtopurls.enabled"))
       return;
     let profileCreationDate = await ProfileAgeCreatedPromise;
     let daysSinceProfileCreation = (Date.now() - profileCreationDate) / MS_PER_DAY;
-    if (daysSinceProfileCreation > UrlbarPrefs.get("usepreloadedtopurls.expire_days"))
+    if (daysSinceProfileCreation > Prefs.get("usepreloadedtopurls.expire_days"))
       Services.prefs.setBoolPref("browser.urlbar.usepreloadedtopurls.enabled", false);
   },
 
   _matchPreloadedSites() {
-    if (!UrlbarPrefs.get("usepreloadedtopurls.enabled")) {
+    if (!Prefs.get("usepreloadedtopurls.enabled")) {
       return;
     }
 
     if (!this._searchString) {
       // The user hasn't typed anything, or they've only typed a scheme.
       return;
     }
 
@@ -1073,17 +1312,17 @@ Search.prototype = {
           style: "preloaded-top-site",
           frecency: FRECENCY_DEFAULT - 1,
         });
       }
     }
   },
 
   _matchPreloadedSiteForAutofill() {
-    if (!UrlbarPrefs.get("usepreloadedtopurls.enabled")) {
+    if (!Prefs.get("usepreloadedtopurls.enabled")) {
       return false;
     }
 
     let matchedSite = PreloadedSiteStorage.sites.find(site => {
       return (!this._strippedPrefix ||
               site.uri.spec.startsWith(this._strippedPrefix)) &&
              (site.uri.host.startsWith(this._searchString) ||
               site.uri.host.startsWith("www." + this._searchString));
@@ -1172,18 +1411,17 @@ Search.prototype = {
       let matched = await this._matchUnknownUrl();
       if (matched) {
         // Since we can't tell if this is a real URL and
         // whether the user wants to visit or search for it,
         // we always provide an alternative searchengine match.
         try {
           new URL(this._originalSearchString);
         } catch (ex) {
-          if (UrlbarPrefs.get("keyword.enabled") &&
-              !looksLikeUrl(this._originalSearchString, true)) {
+          if (Prefs.get("keyword.enabled") && !looksLikeUrl(this._originalSearchString, true)) {
             this._addingHeuristicFirstMatch = false;
             await this._matchCurrentSearchEngine();
             this._addingHeuristicFirstMatch = true;
           }
         }
         return true;
       }
     }
@@ -1200,18 +1438,18 @@ Search.prototype = {
     return false;
   },
 
   _matchSearchSuggestions(searchString) {
     this._searchSuggestionController =
       PlacesSearchAutocompleteProvider.getSuggestionController(
         searchString,
         this._inPrivateWindow,
-        UrlbarPrefs.get("maxHistoricalSearchSuggestions"),
-        UrlbarPrefs.get("maxRichResults") - UrlbarPrefs.get("maxHistoricalSearchSuggestions"),
+        Prefs.get("maxHistoricalSearchSuggestions"),
+        Prefs.get("maxRichResults") - Prefs.get("maxHistoricalSearchSuggestions"),
         this._userContextId
       );
     return this._searchSuggestionController.fetchCompletePromise.then(() => {
       // The search has been canceled already.
       if (!this._searchSuggestionController)
         return;
       if (this._searchSuggestionController.resultsCount >= 0 &&
           this._searchSuggestionController.resultsCount < 2) {
@@ -1336,17 +1574,17 @@ Search.prototype = {
     });
     if (!this._keywordSubstitute) {
       this._keywordSubstitute = entry.url.host;
     }
     return true;
   },
 
   async _matchSearchEngineDomain() {
-    if (!UrlbarPrefs.get("autoFill.searchEngines")) {
+    if (!Prefs.get("autoFill.searchEngines")) {
       return false;
     }
     if (!this._searchString) {
       return false;
     }
 
     // PlacesSearchAutocompleteProvider only matches against engine domains.
     // Remove an eventual trailing slash from the search string (without the
@@ -1425,32 +1663,31 @@ Search.prototype = {
       return false;
 
     let query = this._originalSearchString;
     this._addSearchEngineMatch(match, query);
     return true;
   },
 
   _addExtensionMatch(content, comment) {
-    let count = this._counts[UrlbarUtils.MATCHTYPE.EXTENSION] +
-                this._counts[UrlbarUtils.MATCHTYPE.HEURISTIC];
-    if (count >= UrlbarUtils.MAXIMUM_ALLOWED_EXTENSION_MATCHES) {
+    let count = this._counts[MATCHTYPE.EXTENSION] + this._counts[MATCHTYPE.HEURISTIC];
+    if (count >= MAXIMUM_ALLOWED_EXTENSION_MATCHES) {
       return;
     }
 
     this._addMatch({
       value: PlacesUtils.mozActionURI("extension", {
         content,
         keyword: this._searchTokens[0],
       }),
       comment,
       icon: "chrome://browser/content/extension.svg",
       style: "action extension",
       frecency: Infinity,
-      type: UrlbarUtils.MATCHTYPE.EXTENSION,
+      type: MATCHTYPE.EXTENSION,
     });
   },
 
   _addSearchEngineMatch(searchMatch, query, suggestion = "", historical = false) {
     let actionURLParams = {
       engineName: searchMatch.engineName,
       input: suggestion || this._originalSearchString,
       searchQuery: query,
@@ -1465,17 +1702,17 @@ Search.prototype = {
       value,
       comment: searchMatch.engineName,
       icon: searchMatch.iconUrl,
       style: "action searchengine",
       frecency: FRECENCY_DEFAULT,
     };
     if (suggestion) {
       match.style += " suggestion";
-      match.type = UrlbarUtils.MATCHTYPE.SUGGESTION;
+      match.type = MATCHTYPE.SUGGESTION;
     }
 
     this._addMatch(match);
   },
 
   _matchExtensionSuggestions() {
     let promise = ExtensionSearchHandler.handleSearch(this._searchTokens[0], this._originalSearchString,
       suggestions => {
@@ -1484,17 +1721,17 @@ Search.prototype = {
           this._addExtensionMatch(content, suggestion.description);
         }
       }
     );
     // Remove previous search matches sooner than the maximum timeout, otherwise
     // matches may appear stale for a long time.
     // This is necessary because WebExtensions don't have a method to notify
     // that they are done providing results, so they could be pending forever.
-    setTimeout(() => this._cleanUpNonCurrentMatches(UrlbarUtils.MATCHTYPE.EXTENSION), 100);
+    setTimeout(() => this._cleanUpNonCurrentMatches(MATCHTYPE.EXTENSION), 100);
 
     // Since the extension has no way to signale when it's done pushing
     // results, we add a timeout racing with the addition.
     let timeoutPromise = new Promise(resolve => {
       setTimeout(resolve, MAXIMUM_ALLOWED_EXTENSION_TIME_MS);
     });
     return Promise.race([timeoutPromise, promise]).catch(Cu.reportError);
   },
@@ -1540,18 +1777,17 @@ Search.prototype = {
     let flags = Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
                 Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
     let fixupInfo = null;
     let searchUrl = this._trimmedOriginalSearchString;
     try {
       fixupInfo = Services.uriFixup.getFixupURIInfo(searchUrl,
                                                     flags);
     } catch (e) {
-      if (e.result == Cr.NS_ERROR_MALFORMED_URI &&
-          !UrlbarPrefs.get("keyword.enabled")) {
+      if (e.result == Cr.NS_ERROR_MALFORMED_URI && !Prefs.get("keyword.enabled")) {
         let value = PlacesUtils.mozActionURI("visiturl", {
           url: searchUrl,
           input: searchUrl,
         });
         this._addMatch({
           value,
           comment: searchUrl,
           style: "action visiturl",
@@ -1630,19 +1866,18 @@ Search.prototype = {
         this._addAdaptiveQueryMatch(row);
         break;
       case QUERYTYPE_FILTERED:
         this._addFilteredQueryMatch(row);
         break;
     }
     // If the search has been canceled by the user or by _addMatch, or we
     // fetched enough results, we can stop the underlying Sqlite query.
-    let count = this._counts[UrlbarUtils.MATCHTYPE.GENERAL] +
-                this._counts[UrlbarUtils.MATCHTYPE.HEURISTIC];
-    if (!this.pending || count >= UrlbarPrefs.get("maxRichResults")) {
+    let count = this._counts[MATCHTYPE.GENERAL] + this._counts[MATCHTYPE.HEURISTIC];
+    if (!this.pending || count >= Prefs.get("maxRichResults")) {
       cancel();
     }
   },
 
   _maybeRestyleSearchMatch(match) {
     // Return if the URL does not represent a search result.
     let parseResult =
       PlacesSearchAutocompleteProvider.parseSubmissionURL(match.value);
@@ -1671,29 +1906,29 @@ Search.prototype = {
     match.style = "action searchengine favicon";
   },
 
   _addMatch(match) {
     if (typeof match.frecency != "number")
       throw new Error("Frecency not provided");
 
     if (this._addingHeuristicFirstMatch)
-      match.type = UrlbarUtils.MATCHTYPE.HEURISTIC;
+      match.type = MATCHTYPE.HEURISTIC;
     else if (typeof match.type != "string")
-      match.type = UrlbarUtils.MATCHTYPE.GENERAL;
+      match.type = MATCHTYPE.GENERAL;
 
     // A search could be canceled between a query start and its completion,
     // in such a case ensure we won't notify any result for it.
     if (!this.pending)
       return;
 
     match.style = match.style || "favicon";
 
     // Restyle past searches, unless they are bookmarks or special results.
-    if (UrlbarPrefs.get("restyleSearches") && match.style == "favicon") {
+    if (Prefs.get("restyleSearches") && match.style == "favicon") {
       this._maybeRestyleSearchMatch(match);
     }
 
     if (this._addingHeuristicFirstMatch) {
       match.style += " heuristic";
     }
 
     match.icon = match.icon || "";
@@ -1713,17 +1948,17 @@ Search.prototype = {
                                match.finalCompleteValue);
     this._currentMatchCount++;
     this._counts[match.type]++;
 
     if (this._currentMatchCount == 1)
       TelemetryStopwatch.finish(TELEMETRY_1ST_RESULT, this);
     if (this._currentMatchCount == 6)
       TelemetryStopwatch.finish(TELEMETRY_6_FIRST_RESULTS, this);
-    this.notifyResult(true, match.type == UrlbarUtils.MATCHTYPE.HEURISTIC);
+    this.notifyResult(true, match.type == MATCHTYPE.HEURISTIC);
   },
 
   _getInsertIndexForMatch(match) {
     // Check for duplicates and either discard (by returning -1) the duplicate
     // or suggest to replace the original match, in case the new one is more
     // specific (for example a Remote Tab wins over History, and a Switch to Tab
     // wins over a Remote Tab).
     // Must check both id and url, cause keywords dynamically modify the url.
@@ -1738,18 +1973,17 @@ Search.prototype = {
         // The new entry is a switch/remote tab entry, look for the duplicate
         // among current matches.
         for (let i = 0; i < this._usedURLs.length; ++i) {
           let {key: matchKey, action: matchAction, type: matchType} = this._usedURLs[i];
           if (matchKey == urlMapKey) {
             isDupe = true;
             // Don't replace the match if the existing one is heuristic and the
             // new one is a switchtab, instead also add the switchtab match.
-            if (matchType == UrlbarUtils.MATCHTYPE.HEURISTIC &&
-                action.type == "switchtab") {
+            if (matchType == MATCHTYPE.HEURISTIC && action.type == "switchtab") {
               isDupe = false;
               // Since we allow to insert a dupe in this case, we must continue
               // checking the next matches to be sure we won't insert more than
               // one dupe. For this same reason we must reset isDupe = true for
               // each found dupe.
               continue;
             }
             if (!matchAction || action.type == "switchtab") {
@@ -1774,19 +2008,19 @@ Search.prototype = {
     if (match.placeId)
       this._usedPlaceIds.add(match.placeId);
 
     let index = 0;
     // The buckets change depending on the context, that is currently decided by
     // the first added match (the heuristic one).
     if (!this._buckets) {
       // Convert the buckets to readable objects with a count property.
-      let buckets = match.type == UrlbarUtils.MATCHTYPE.HEURISTIC &&
-                    match.style.includes("searchengine") ? UrlbarPrefs.get("matchBucketsSearch")
-                                                         : UrlbarPrefs.get("matchBuckets");
+      let buckets = match.type == MATCHTYPE.HEURISTIC &&
+                    match.style.includes("searchengine") ? Prefs.get("matchBucketsSearch")
+                                                         : Prefs.get("matchBuckets");
       // - available is the number of available slots in the bucket
       // - insertIndex is the index of the first available slot in the bucket
       // - count is the number of matches in the bucket, note that it also
       //   account for matches from the previous search, while available and
       //   insertIndex don't.
       this._buckets = buckets.map(([type, available]) => ({ type,
                                                             available,
                                                             insertIndex: 0,
@@ -1832,17 +2066,17 @@ Search.prototype = {
     this._usedURLs[index] = {key: urlMapKey, action, type: match.type};
     return { index, replace };
   },
 
   /**
    * Removes matches from a previous search, that are no more returned by the
    * current search
    * @param type
-   *        The UrlbarUtils.MATCHTYPE to clean up.
+   *        The MATCHTYPE to clean up.
    * @param [optional] notify
    *        Whether to notify a result change.
    */
   _cleanUpNonCurrentMatches(type, notify = true) {
     if (this._previousSearchMatchTypes.length == 0 || !this.pending)
       return;
 
     let index = 0;
@@ -1944,17 +2178,17 @@ Search.prototype = {
   // This is the same as _addFilteredQueryMatch, but it only returns a few
   // results, caching the others. If at the end we don't find other results, we
   // can add these.
   _addAdaptiveQueryMatch(row) {
     // Allow one quarter of the results to be adaptive results.
     // Note: ideally adaptive results should have their own provider and the
     // results muxer should decide what to show.  But that's too complex to
     // support in the current code, so that's left for a future refactoring.
-    if (this._adaptiveCount < Math.ceil(UrlbarPrefs.get("maxRichResults") / 4)) {
+    if (this._adaptiveCount < Math.ceil(Prefs.get("maxRichResults") / 4)) {
       this._addFilteredQueryMatch(row);
     } else {
       this._extraAdaptiveRows.push(row);
     }
     this._adaptiveCount++;
   },
 
   _addFilteredQueryMatch(row) {
@@ -2090,17 +2324,17 @@ Search.prototype = {
         matchBehavior: this._matchBehavior,
         searchBehavior: this._behavior,
         // We only want to search the tokens that we are left with - not the
         // original search string.
         searchString: this._keywordSubstitutedSearchString,
         userContextId: this._userContextId,
         // Limit the query to the the maximum number of desired results.
         // This way we can avoid doing more work than needed.
-        maxResults: UrlbarPrefs.get("maxRichResults"),
+        maxResults: Prefs.get("maxRichResults"),
       },
     ];
   },
 
   /**
    * Obtains the query to search for switch-to-tab entries.
    *
    * @return an array consisting of the correctly optimized query to search the
@@ -2112,17 +2346,17 @@ Search.prototype = {
       {
         query_type: QUERYTYPE_FILTERED,
         matchBehavior: this._matchBehavior,
         searchBehavior: this._behavior,
         // We only want to search the tokens that we are left with - not the
         // original search string.
         searchString: this._keywordSubstitutedSearchString,
         userContextId: this._userContextId,
-        maxResults: UrlbarPrefs.get("maxRichResults"),
+        maxResults: Prefs.get("maxRichResults"),
       },
     ];
   },
 
   /**
    * Obtains the query to search for adaptive results.
    *
    * @return an array consisting of the correctly optimized query to search the
@@ -2133,27 +2367,27 @@ Search.prototype = {
       SQL_ADAPTIVE_QUERY,
       {
         parent: PlacesUtils.tagsFolderId,
         search_string: this._searchString,
         query_type: QUERYTYPE_ADAPTIVE,
         matchBehavior: this._matchBehavior,
         searchBehavior: this._behavior,
         userContextId: this._userContextId,
-        maxResults: UrlbarPrefs.get("maxRichResults"),
+        maxResults: Prefs.get("maxRichResults"),
       },
     ];
   },
 
   /**
    * Whether we should try to autoFill.
    */
   get _shouldAutofill() {
     // First of all, check for the autoFill pref.
-    if (!UrlbarPrefs.get("autoFill"))
+    if (!Prefs.get("autoFill"))
       return false;
 
     if (this._searchTokens.length != 1)
       return false;
 
     // autoFill can only cope with history or bookmarks entries.
     if (!this.hasBehavior("history") &&
         !this.hasBehavior("bookmark"))
@@ -2193,17 +2427,17 @@ Search.prototype = {
     let searchStr =
       this._searchString.endsWith("/") ?
       this._searchString.slice(0, -1) :
       this._searchString;
 
     let opts = {
       query_type: QUERYTYPE_AUTOFILL_ORIGIN,
       searchString: searchStr.toLowerCase(),
-      stddevMultiplier: UrlbarPrefs.get("autoFill.stddevMultiplier"),
+      stddevMultiplier: Prefs.get("autoFill.stddevMultiplier"),
     };
 
     let bookmarked = this.hasBehavior("bookmark") &&
                      !this.hasBehavior("history");
     if (this._strippedPrefix) {
       opts.prefix = this._strippedPrefix;
       if (bookmarked) {
         return [SQL_ORIGIN_PREFIX_BOOKMARKED_QUERY, opts];
@@ -2247,17 +2481,17 @@ Search.prototype = {
       strippedURL = strippedURL.substr(this._strippedPrefix.length);
     }
     strippedURL = host + strippedURL.substr(host.length);
 
     let opts = {
       query_type: QUERYTYPE_AUTOFILL_URL,
       revHost,
       strippedURL,
-      stddevMultiplier: UrlbarPrefs.get("autoFill.stddevMultiplier"),
+      stddevMultiplier: Prefs.get("autoFill.stddevMultiplier"),
     };
 
     let bookmarked = this.hasBehavior("bookmark") &&
                      !this.hasBehavior("history");
 
     if (this._strippedPrefix) {
       opts.prefix = this._strippedPrefix;
       if (bookmarked) {
@@ -2317,17 +2551,23 @@ Search.prototype = {
     }
   },
 };
 
 // UnifiedComplete class
 // component @mozilla.org/autocomplete/search;1?name=unifiedcomplete
 
 function UnifiedComplete() {
-  if (UrlbarPrefs.get("usepreloadedtopurls.enabled")) {
+  // Make sure the preferences are initialized as soon as possible.
+  // If the value of browser.urlbar.autocomplete.enabled is set to false,
+  // then all the other suggest preferences for history, bookmarks and
+  // open pages should be set to false.
+  Prefs;
+
+  if (Prefs.get("usepreloadedtopurls.enabled")) {
     // force initializing the profile age check
     // to ensure the off-main-thread-IO happens ASAP
     // and we don't have to wait for it when doing an autocomplete lookup
     ProfileAgeCreatedPromise;
 
     fetch("chrome://global/content/unifiedcomplete-top-urls.json")
       .then(response => response.json())
       .then(sites => PreloadedSiteStorage.populate(sites))
@@ -2347,18 +2587,17 @@ UnifiedComplete.prototype = {
   /**
    * Gets a Sqlite database handle.
    *
    * @return {Promise}
    * @resolves to the Sqlite database handle (according to Sqlite.jsm).
    * @rejects javascript exception.
    */
   getDatabaseHandle() {
-    if (UrlbarPrefs.get("autocomplete.enabled") &&
-        !this._promiseDatabase) {
+    if (Prefs.get("autocomplete.enabled") && !this._promiseDatabase) {
       this._promiseDatabase = (async () => {
         let conn = await PlacesUtils.promiseLargeCacheDBConnection();
 
         try {
            Sqlite.shutdown.addBlocker("Places UnifiedComplete.js closing",
                                       () => {
                                         // Break a possible cycle through the
                                         // previous result, the controller and
@@ -2420,39 +2659,39 @@ UnifiedComplete.prototype = {
     //    didn't match it.
     // What we can do is reuse the previous result along with the bucketing
     // system to avoid flickering. Since we know where a new match should be
     // positioned, we  wait for a new match to arrive before replacing the
     // previous one. This may leave stale matches from the previous search that
     // would not be returned by the current one, thus once the current search is
     // complete, we remove those stale matches with _cleanUpNonCurrentMatches().
     let previousResult = null;
-    let insertMethod = UrlbarPrefs.get("insertMethod");
-    if (this._currentSearch && insertMethod != UrlbarUtils.INSERTMETHOD.APPEND) {
+    let insertMethod = Prefs.get("insertMethod");
+    if (this._currentSearch && insertMethod != INSERTMETHOD.APPEND) {
       let result = this._currentSearch._result;
       // Only reuse the previous result when one of the search strings is an
       // extension of the other one.  We could expand this to any case, but
       // that may leave exposed unrelated matches for a longer time.
       let previousSearchString = result.searchString;
       let stringsRelated = previousSearchString.length > 0 &&
                            searchString.length > 0 &&
                            (previousSearchString.includes(searchString) ||
                             searchString.includes(previousSearchString));
-      if (insertMethod == UrlbarUtils.INSERTMETHOD.MERGE || stringsRelated) {
+      if (insertMethod == INSERTMETHOD.MERGE || stringsRelated) {
         previousResult = result;
       }
     }
 
     this._currentSearch = new Search(searchString, searchParam, listener,
                                      this, prohibitSearchSuggestions,
                                      previousResult);
 
     // If we are not enabled, we need to return now.  Notice we need an empty
     // result regardless, so we still create the Search object.
-    if (!UrlbarPrefs.get("autocomplete.enabled")) {
+    if (!Prefs.get("autocomplete.enabled")) {
       this.finishSearch(true);
       return;
     }
 
     let search = this._currentSearch;
     this.getDatabaseHandle().then(conn => search.execute(conn))
                             .catch(ex => {
                               dump(`Query failed: ${ex}\n`);