try: -b do -p all -u all -t none draft
authorDrew Willcoxon <adw@mozilla.com>
Mon, 29 Jan 2018 13:31:29 -0800
changeset 748464 0c8d6a0ae81a528aa29980c33a02b27f62e83eec
parent 723224 20e194b34185de3009453b87f637daa5f432f74b
push id97174
push userbmo:adw@mozilla.com
push dateMon, 29 Jan 2018 21:32:10 +0000
bugs1239708
milestone60.0a1
try: -b do -p all -u all -t none Bug 1239708 - Improve the autofill decisions algorithms. MozReview-Commit-ID: 7oY6Y9eOoI2
browser/app/profile/firefox.js
browser/base/content/test/urlbar/browser.ini
browser/base/content/test/urlbar/browser_autocomplete_autoselect.js
browser/base/content/test/urlbar/browser_autocomplete_cursor.js
browser/base/content/test/urlbar/browser_autocomplete_enter_race.js
browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
browser/base/content/test/urlbar/browser_urlbarDelete.js
browser/base/content/test/urlbar/browser_urlbarEnter.js
browser/base/content/test/urlbar/browser_urlbar_canonize_on_autofill.js
browser/base/content/test/urlbar/browser_urlbar_search_speculative_connect.js
browser/base/content/urlbarBindings.xml
netwerk/base/nsIBrowserSearchService.idl
services/sync/tests/unit/test_history_store.js
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/places/Bookmarks.jsm
toolkit/components/places/Database.cpp
toolkit/components/places/Database.h
toolkit/components/places/History.cpp
toolkit/components/places/History.jsm
toolkit/components/places/PlacesSearchAutocompleteProvider.jsm
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/SQLFunctions.cpp
toolkit/components/places/SQLFunctions.h
toolkit/components/places/UnifiedComplete.js
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/nsPlacesIndexes.h
toolkit/components/places/nsPlacesTables.h
toolkit/components/places/nsPlacesTriggers.h
toolkit/components/places/tests/PlacesTestUtils.jsm
toolkit/components/places/tests/favicons/test_root_icons.js
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/migration/places_v42.sqlite
toolkit/components/places/tests/migration/xpcshell.ini
toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
toolkit/components/places/tests/unifiedcomplete/head_autofill.js
toolkit/components/places/tests/unifiedcomplete/test_417798.js
toolkit/components/places/tests/unifiedcomplete/test_418257.js
toolkit/components/places/tests/unifiedcomplete/test_422277.js
toolkit/components/places/tests/unifiedcomplete/test_PlacesSearchAutocompleteProvider.js
toolkit/components/places/tests/unifiedcomplete/test_autocomplete_functional.js
toolkit/components/places/tests/unifiedcomplete/test_autofill_default_behavior.js
toolkit/components/places/tests/unifiedcomplete/test_autofill_origins.js
toolkit/components/places/tests/unifiedcomplete/test_autofill_search_engines.js
toolkit/components/places/tests/unifiedcomplete/test_autofill_urls.js
toolkit/components/places/tests/unifiedcomplete/test_avoid_middle_complete.js
toolkit/components/places/tests/unifiedcomplete/test_avoid_stripping_to_empty_tokens.js
toolkit/components/places/tests/unifiedcomplete/test_casing.js
toolkit/components/places/tests/unifiedcomplete/test_dupe_urls.js
toolkit/components/places/tests/unifiedcomplete/test_enabled.js
toolkit/components/places/tests/unifiedcomplete/test_escape_self.js
toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js
toolkit/components/places/tests/unifiedcomplete/test_keywords.js
toolkit/components/places/tests/unifiedcomplete/test_match_beginning.js
toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js
toolkit/components/places/tests/unifiedcomplete/test_query_url.js
toolkit/components/places/tests/unifiedcomplete/test_search_engine_host.js
toolkit/components/places/tests/unifiedcomplete/test_search_suggestions.js
toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js
toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js
toolkit/components/places/tests/unifiedcomplete/test_trimming.js
toolkit/components/places/tests/unifiedcomplete/test_typed.js
toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js
toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
toolkit/components/places/tests/unit/test_adaptive_bug527311.js
toolkit/components/places/tests/unit/test_frecency_stats.js
toolkit/components/places/tests/unit/test_hosts_triggers.js
toolkit/components/places/tests/unit/test_origins.js
toolkit/components/places/tests/unit/test_preventive_maintenance.js
toolkit/components/places/tests/unit/xpcshell.ini
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/test_resultDomain.js
toolkit/content/widgets/autocomplete.xml
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -290,17 +290,16 @@ pref("browser.urlbar.clickSelectsAll", t
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.doubleClickSelectsAll", true);
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
 
 // Control autoFill behavior
 pref("browser.urlbar.autoFill", true);
-pref("browser.urlbar.autoFill.typed", true);
 pref("browser.urlbar.speculativeConnect.enabled", true);
 
 // 0: Match anywhere (e.g., middle of words)
 // 1: Match on word boundaries and then try matching anywhere
 // 2: Match only on word boundaries (e.g., after / or .)
 // 3: Match at the beginning of the url or title
 pref("browser.urlbar.matchBehavior", 1);
 pref("browser.urlbar.filter.javascript", true);
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -54,29 +54,34 @@ support-files =
 [browser_tabMatchesInAwesomebar_perwindowpb.js]
 skip-if = os == 'linux' # Bug 1104755
 [browser_urlbarAddonIframe.js]
 support-files =
   Panel.jsm
   urlbarAddonIframe.html
   urlbarAddonIframe.js
   urlbarAddonIframeContentScript.js
+
+
 [browser_urlbarAboutHomeLoading.js]
 [browser_urlbarAutoFillTrimURLs.js]
 [browser_urlbarCopying.js]
 subsuite = clipboard
 support-files =
   authenticate.sjs
 [browser_urlbarDecode.js]
 [browser_urlbarDelete.js]
 [browser_urlbarEnter.js]
+
+
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarFocusedCmdK.js]
 [browser_urlbarHashChangeProxyState.js]
+
 [browser_urlbarKeepStateAcrossTabSwitches.js]
 [browser_urlbarOneOffs.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarOneOffs_searchSuggestions.js]
 support-files =
   searchSuggestionEngine.xml
--- a/browser/base/content/test/urlbar/browser_autocomplete_autoselect.js
+++ b/browser/base/content/test/urlbar/browser_autocomplete_autoselect.js
@@ -23,41 +23,56 @@ function is_selected_one_off(index) {
      "Expected one-off button should be selected");
 
   // This is true because although both the listbox and the one-offs can have
   // selections, the test doesn't check that.
   is(gURLBar.popup.richlistbox.selectedIndex, -1,
      "A one-off is selected, so the listbox should not have a selection");
 }
 
+// add_task(function init() {
+//   Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+//   registerCleanupFunction(() => {
+//     Services.prefs.clearUserPref("browser.urlbar.autoFill");
+//   });
+// });
+
 add_task(async function() {
   let maxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
   Services.prefs.setBoolPref(ONEOFF_URLBAR_PREF, true);
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
   registerCleanupFunction(async function() {
     await PlacesTestUtils.clearHistory();
     Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
     await BrowserTestUtils.removeTab(tab);
   });
 
+//   Services.prefs.setBoolPref("browser.urlbar.suggest.searches", true);
+
+
+//   let maxResults = 10;
+
   let visits = [];
   repeat(maxResults, i => {
     visits.push({
       uri: makeURI("http://example.com/autocomplete/?" + i),
     });
   });
   await PlacesTestUtils.addVisits(visits);
 
+//   await new Promise(r => {});
+
   await promiseAutocompleteResultPopup("example.com/autocomplete");
   await waitForAutocompleteResultAt(maxResults - 1);
 
   let popup = gURLBar.popup;
   let results = popup.richlistbox.children;
   is(results.length, maxResults,
      "Should get maxResults=" + maxResults + " results");
+//   await new Promise(r => {});
   is_selected(0);
 
   info("Key Down to select the next item");
   EventUtils.synthesizeKey("VK_DOWN", {});
   is_selected(1);
 
   info("Key Down maxResults-1 times should select the first one-off");
   repeat(maxResults - 1, () => EventUtils.synthesizeKey("VK_DOWN", {}));
--- a/browser/base/content/test/urlbar/browser_autocomplete_cursor.js
+++ b/browser/base/content/test/urlbar/browser_autocomplete_cursor.js
@@ -8,13 +8,14 @@ add_task(async function() {
   gURLBar.selectTextRange(4, 4);
 
   is(gURLBar.popup.state, "open", "Popup should be open");
   is(gURLBar.popup.richlistbox.selectedIndex, 0, "Should have selected something");
 
   EventUtils.synthesizeKey("VK_RIGHT", {});
   await promisePopupHidden(gURLBar.popup);
 
-  is(gURLBar.selectionStart, 5, "Should have moved the cursor");
-  is(gURLBar.selectionEnd, 5, "And not selected anything");
+  let index = "www.mozilla.org/".length;
+  is(gURLBar.selectionStart, index, "Should have moved the cursor");
+  is(gURLBar.selectionEnd, index, "And not selected anything");
 
   await BrowserTestUtils.removeTab(tab);
 });
--- a/browser/base/content/test/urlbar/browser_autocomplete_enter_race.js
+++ b/browser/base/content/test/urlbar/browser_autocomplete_enter_race.js
@@ -8,28 +8,33 @@ add_task(async function setup() {
     title: "test"
   });
   registerCleanupFunction(async function() {
     await PlacesUtils.bookmarks.remove(bm);
     await BrowserTestUtils.removeTab(tab);
   });
   await PlacesUtils.keywords.insert({ keyword: "keyword",
                                       url: "http://example.com/?q=%s" });
+
+  dump(`XXXadw frecencyMean=${PlacesUtils.history.frecencyMean} frecencyStandardDeviation=${PlacesUtils.history.frecencyStandardDeviation}\n`);
+
   // Needs at least one success.
   ok(true, "Setup complete");
 });
 
 add_task(async function test_keyword() {
   await promiseAutocompleteResultPopup("keyword bear");
   gURLBar.focus();
   EventUtils.synthesizeKey("d", {});
   EventUtils.synthesizeKey("VK_RETURN", {});
   info("wait for the page to load");
   await BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
                                       false, "http://example.com/?q=beard");
+
+  dump(`XXXadw frecencyMean=${PlacesUtils.history.frecencyMean} frecencyStandardDeviation=${PlacesUtils.history.frecencyStandardDeviation}\n`);
 });
 
 add_task(async function test_sametext() {
   await promiseAutocompleteResultPopup("example.com", window, true);
 
   // Simulate re-entering the same text searched the last time. This may happen
   // through a copy paste, but clipboard handling is not much reliable, so just
   // fire an input event.
@@ -37,23 +42,37 @@ add_task(async function test_sametext() 
   let event = document.createEvent("Events");
   event.initEvent("input", true, true);
   gURLBar.dispatchEvent(event);
   EventUtils.synthesizeKey("VK_RETURN", {});
 
   info("wait for the page to load");
   await BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
                                        false, "http://example.com/");
+
+  dump(`XXXadw frecencyMean=${PlacesUtils.history.frecencyMean} frecencyStandardDeviation=${PlacesUtils.history.frecencyStandardDeviation}\n`);
 });
 
 add_task(async function test_after_empty_search() {
+
+//     await new Promise(r => setTimeout(r, 2000));
+
+    dump("\n\n*********************XXXadw*********************\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_autofill_origins");
+    dump_table("moz_places");
+
+
   await promiseAutocompleteResultPopup("");
   gURLBar.focus();
   gURLBar.value = "e";
   EventUtils.synthesizeKey("x", {});
+//   await new Promise(r => {});
   EventUtils.synthesizeKey("VK_RETURN", {});
 
   info("wait for the page to load");
   await BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
                                        false, "http://example.com/");
 });
 
 add_task(async function test_disabled_ac() {
@@ -117,8 +136,77 @@ add_task(async function test_delay() {
   gURLBar.value = "e";
   EventUtils.synthesizeKey("x", {});
   EventUtils.synthesizeKey("VK_RETURN", {});
   info("wait for the page to load");
   await BrowserTestUtils.browserLoaded(gBrowser.selectedTab.linkedBrowser,
                                        false, "http://example.com/");
   Assert.ok((Date.now() - start) < TIMEOUT);
 });
+
+
+
+
+
+
+
+//XXXadw
+var gDBConn;
+function DBConn(aForceNewConnection) {
+  if (!aForceNewConnection) {
+    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
+                                .DBConnection;
+    if (db.connectionReady)
+      return db;
+  }
+
+  // If the Places database connection has been closed, create a new connection.
+  if (!gDBConn || aForceNewConnection) {
+    let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
+    file.append("places.sqlite");
+    let dbConn = gDBConn = Services.storage.openDatabase(file);
+
+    // Be sure to cleanly close this connection.
+    promiseTopicObserved("profile-before-change").then(() => dbConn.asyncClose());
+  }
+
+  return gDBConn.connectionReady ? gDBConn : null;
+}
+function dump_table(aName) {
+  let stmt = DBConn().createStatement("SELECT * FROM " + aName);
+
+  dump("\n\n*** Printing data from " + aName + "\n");
+  let count = 0;
+  while (stmt.executeStep()) {
+    let columns = stmt.numEntries;
+
+    if (count == 0) {
+      // Print the column names.
+      for (let i = 0; i < columns; i++)
+        dump(stmt.getColumnName(i) + "\t");
+      dump("\n");
+    }
+
+    // Print the rows.
+    for (let i = 0; i < columns; i++) {
+      switch (stmt.getTypeOfIndex(i)) {
+        case Ci.mozIStorageValueArray.VALUE_TYPE_NULL:
+          dump("NULL\t");
+          break;
+        case Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER:
+          dump(stmt.getInt64(i) + "\t");
+          break;
+        case Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT:
+          dump(stmt.getDouble(i) + "\t");
+          break;
+        case Ci.mozIStorageValueArray.VALUE_TYPE_TEXT:
+          dump(stmt.getString(i) + "\t");
+          break;
+      }
+    }
+    dump("\n");
+
+    count++;
+  }
+  dump("*** There were a total of " + count + " rows of data.\n\n");
+
+  stmt.finalize();
+}
--- a/browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
+++ b/browser/base/content/test/urlbar/browser_urlbarAutoFillTrimURLs.js
@@ -56,61 +56,66 @@ async function promiseTestResult(test) {
 
 const tests = [{
     search: "http://",
     autofilledValue: "http://",
     resultListDisplayTitle: "http://",
     resultListActionText: "Search with Google",
     resultListType: "searchengine",
     finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"http%3A%2F%2F","searchQuery":"http%3A%2F%2F"}'
-  }, {
+  },
+  {
     search: "https://",
     autofilledValue: "https://",
     resultListDisplayTitle: "https://",
     resultListActionText: "Search with Google",
     resultListType: "searchengine",
     finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"https%3A%2F%2F","searchQuery":"https%3A%2F%2F"}'
-  }, {
+  },
+  {
     search: "au",
     autofilledValue: "autofilltrimurl.com/",
     resultListDisplayTitle: "www.autofilltrimurl.com",
     resultListActionText: "Visit",
     resultListType: "",
-    finalCompleteValue: "www.autofilltrimurl.com/"
-  }, {
+    finalCompleteValue: "http://www.autofilltrimurl.com/"
+  },
+  {
     search: "http://au",
     autofilledValue: "http://autofilltrimurl.com/",
-    resultListDisplayTitle: "autofilltrimurl.com",
+    resultListDisplayTitle: "www.autofilltrimurl.com",
     resultListActionText: "Visit",
     resultListType: "",
-    finalCompleteValue: "http://autofilltrimurl.com/"
-  }, {
+    finalCompleteValue: "http://www.autofilltrimurl.com/"
+  },
+  {
     search: "sec",
     autofilledValue: "secureautofillurl.com/",
     resultListDisplayTitle: "https://www.secureautofillurl.com",
     resultListActionText: "Visit",
     resultListType: "",
     finalCompleteValue: "https://www.secureautofillurl.com/"
-  }, {
+  },
+  {
     search: "https://sec",
     autofilledValue: "https://secureautofillurl.com/",
-    resultListDisplayTitle: "https://secureautofillurl.com",
+    resultListDisplayTitle: "https://www.secureautofillurl.com",
     resultListActionText: "Visit",
     resultListType: "",
-    finalCompleteValue: "https://secureautofillurl.com/"
+    finalCompleteValue: "https://www.secureautofillurl.com/"
   },
 ];
 
 add_task(async function autofill_tests() {
   for (let test of tests) {
     await promiseTestResult(test);
   }
 });
 
-add_task(async function autofill_complete_domain() {
-  await promiseSearch("http://www.autofilltrimurl.com");
-  is(gURLBar.inputField.value, "http://www.autofilltrimurl.com/", "Autofilled value is as expected");
+// add_task(async function autofill_complete_domain() {
+//   await promiseSearch("http://www.autofilltrimurl.com");
+//   is(gURLBar.inputField.value, "http://www.autofilltrimurl.com/", "Autofilled value is as expected");
 
-  // Now ensure selecting from the popup correctly trims.
-  is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
-  EventUtils.synthesizeKey("VK_DOWN", {});
-  is(gURLBar.inputField.value, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
-});
+//   // Now ensure selecting from the popup correctly trims.
+//   is(gURLBar.controller.matchCount, 2, "Found the expected number of matches");
+//   EventUtils.synthesizeKey("VK_DOWN", {});
+//   is(gURLBar.inputField.value, "www.autofilltrimurl.com/whatever", "trim was applied correctly");
+// });
--- a/browser/base/content/test/urlbar/browser_urlbarDelete.js
+++ b/browser/base/content/test/urlbar/browser_urlbarDelete.js
@@ -1,15 +1,17 @@
 add_task(async function() {
   let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
                                                 url: "http://bug1105244.example.com/",
                                                 title: "test" });
 
+  Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
   registerCleanupFunction(async function() {
     await PlacesUtils.bookmarks.remove(bm);
+    Services.prefs.clearUserPref("browser.urlbar.autoFill");
   });
 
   await BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" }, testDelete);
 });
 
 function sendHome() {
   // unclear why VK_HOME doesn't work on Mac, but it doesn't...
   if (Services.appinfo.OS == "Darwin") {
@@ -22,17 +24,19 @@ function sendHome() {
 function sendDelete() {
   EventUtils.synthesizeKey("VK_DELETE", {});
 }
 
 async function testDelete() {
   await promiseAutocompleteResultPopup("bug1105244");
 
   // move to the start.
+//   gURLBar.selectTextRange(0, 0);
   sendHome();
+
   // delete the first few chars - each delete should operate on the input field.
   sendDelete();
   Assert.equal(gURLBar.inputField.value, "ug1105244");
 
   await promisePopupShown(gURLBar.popup);
 
   sendDelete();
   Assert.equal(gURLBar.inputField.value, "g1105244");
--- a/browser/base/content/test/urlbar/browser_urlbarEnter.js
+++ b/browser/base/content/test/urlbar/browser_urlbarEnter.js
@@ -1,36 +1,90 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TEST_VALUE = "example.com/\xF7?\xF7";
 const START_VALUE = "example.com/%C3%B7?%C3%B7";
 
-add_task(async function() {
+// add_task(async function() {
+//   info("Simple return keypress");
+//   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, START_VALUE);
+
+//   gURLBar.focus();
+
+// //   await new Promise(r => {});
+
+//   EventUtils.synthesizeKey("VK_RETURN", {});
+//   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+//   // Check url bar and selected tab.
+//   is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+//   is(gBrowser.selectedTab, tab, "New URL was loaded in the current tab");
+
+//   // Cleanup.
+//   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+// });
+
+// add_task(async function() {
+//   info("Alt+Return keypress");
+//   // due to bug 691608, we must wait for the load event, else isTabEmpty() will
+//   // return true on e10s for this tab, so it will be reused even with altKey.
+//   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE);
+
+//   let tabOpenPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
+//   gURLBar.focus();
+//   EventUtils.synthesizeKey("VK_RETURN", {altKey: true});
+
+//   // wait for the new tab to appear.
+//   await tabOpenPromise;
+
+//   // Check url bar and selected tab.
+//   is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
+//   isnot(gBrowser.selectedTab, tab, "New URL was loaded in a new tab");
+
+//   // Cleanup.
+//   await BrowserTestUtils.removeTab(tab);
+//   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
+// });
+
+
+
+
+add_task(async function returnKeypress() {
+//   gURLBar.popup.selectedIndex = -1;
+
   info("Simple return keypress");
-  let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, START_VALUE);
+  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE);
 
   gURLBar.focus();
+
+//   await new Promise(r => {});
+
+//   // This is necessary to get the urlbar to set gBrowser.userTypedValue.
+//   let event = document.createEvent("Events");
+//   event.initEvent("input", true, true);
+//   gURLBar.dispatchEvent(event);
+
+//   await new Promise(r => {});
+
   EventUtils.synthesizeKey("VK_RETURN", {});
   await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
 
   // Check url bar and selected tab.
   is(gURLBar.textValue, TEST_VALUE, "Urlbar should preserve the value on return keypress");
   is(gBrowser.selectedTab, tab, "New URL was loaded in the current tab");
 
   // Cleanup.
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
-add_task(async function() {
+add_task(async function altReturnKeypress() {
   info("Alt+Return keypress");
-  // due to bug 691608, we must wait for the load event, else isTabEmpty() will
-  // return true on e10s for this tab, so it will be reused even with altKey.
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, START_VALUE);
 
   let tabOpenPromise = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen");
   gURLBar.focus();
   EventUtils.synthesizeKey("VK_RETURN", {altKey: true});
 
   // wait for the new tab to appear.
   await tabOpenPromise;
--- a/browser/base/content/test/urlbar/browser_urlbar_canonize_on_autofill.js
+++ b/browser/base/content/test/urlbar/browser_urlbar_canonize_on_autofill.js
@@ -34,17 +34,17 @@ add_task(async function() {
   await PlacesTestUtils.addVisits({
     uri: "http://example.com/",
     transition: Ci.nsINavHistoryService.TRANSITION_TYPED
   });
 
   await test_autocomplete({ desc: "CTRL+ENTER on the autofilled part should use autofill",
                             typed: "exam",
                             autofilled: "example.com/",
-                            modified: "example.com/",
+                            modified: "example.com",
                             waitForUrl: "http://example.com/",
                             keys: [["VK_RETURN", {}]]
                           });
 
   await test_autocomplete({ desc: "CTRL+ENTER on the autofilled part should bypass autofill",
                             typed: "exam",
                             autofilled: "example.com/",
                             modified: "www.exam.com",
--- a/browser/base/content/test/urlbar/browser_urlbar_search_speculative_connect.js
+++ b/browser/base/content/test/urlbar/browser_urlbar_search_speculative_connect.js
@@ -9,21 +9,28 @@
 
 let gHttpServer = null;
 let gScheme = "http";
 let gHost = "localhost"; // 'localhost' by default.
 let gPort = -1;
 let gPrivateWin = null;
 let gIsSpeculativeConnected = false;
 
+let gTest;
+
 add_task(async function setup() {
   gHttpServer = runHttpServer(gScheme, gHost);
   // The server will be run on a random port if the port number wasn't given.
   gPort = gHttpServer.identity.primaryPort;
 
+  gTest = {
+    search: gHost.substr(0, 2),
+    autofilledValue: `${gHost}:${gPort}/`
+  };
+
   await SpecialPowers.pushPrefEnv({
     set: [["browser.urlbar.autoFill", true],
           // Turn off search suggestion so we won't speculative connect to the search engine.
           ["browser.search.suggest.enabled", false],
           ["browser.urlbar.speculativeConnect.enabled", true],
           // In mochitest this number is 0 by default but we have to turn it on.
           ["network.http.speculative-parallel-limit", 6],
           // The http server is using IPv4, so it's better to disable IPv6 to avoid weird
@@ -40,54 +47,50 @@ add_task(async function setup() {
   gPrivateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
   is(PrivateBrowsingUtils.isWindowPrivate(gPrivateWin), true, "A private window created.");
 
   // Bug 764062 - we can't get port number from autocomplete result, so we have to mock
   // this function and add it manually.
   let oldSpeculativeConnect = gURLBar.popup.maybeSetupSpeculativeConnect.bind(gURLBar.popup);
   let newSpeculativeConnect = (uriString) => {
     gIsSpeculativeConnected = true;
-    info(`Original uri is ${uriString}`);
-    let newUriString = uriString.substr(0, uriString.length - 1) +
-                       ":" + gPort + "/";
-    info(`New uri is ${newUriString}`);
-    oldSpeculativeConnect(newUriString);
+//     info(`Original uri is ${uriString}`);
+//     let newUriString = uriString.substr(0, uriString.length - 1) +
+//                        ":" + gPort + "/";
+//     info(`New uri is ${newUriString}`);
+//     oldSpeculativeConnect(newUriString);
+    oldSpeculativeConnect(uriString);
   };
   gURLBar.popup.maybeSetupSpeculativeConnect = newSpeculativeConnect;
   gPrivateWin.gURLBar.popup.maybeSetupSpeculativeConnect = newSpeculativeConnect;
 
   registerCleanupFunction(async function() {
     await PlacesUtils.history.clear();
     gURLBar.popup.maybeSetupSpeculativeConnect = oldSpeculativeConnect;
     gPrivateWin.gURLBar.popup.maybeSetupSpeculativeConnect = oldSpeculativeConnect;
     gHttpServer.identity.remove(gScheme, gHost, gPort);
     gHttpServer.stop(() => {
       gHttpServer = null;
     });
     await BrowserTestUtils.closeWindow(gPrivateWin);
   });
 });
 
-const test = {
-  search: gHost.substr(0, 2),
-  autofilledValue: `${gHost}/`
-};
-
 add_task(async function autofill_tests() {
   gIsSpeculativeConnected = false;
-  info(`Searching for '${test.search}'`);
-  await promiseAutocompleteResultPopup(test.search, window, true);
-  is(gURLBar.inputField.value, test.autofilledValue,
-     `Autofilled value is as expected for search '${test.search}'`);
+  info(`Searching for '${gTest.search}'`);
+  await promiseAutocompleteResultPopup(gTest.search, window, true);
+  is(gURLBar.inputField.value, gTest.autofilledValue,
+     `Autofilled value is as expected for search '${gTest.search}'`);
   is(gIsSpeculativeConnected, true, "Speculative connection should be called");
   await promiseSpeculativeConnection(gHttpServer);
   is(gHttpServer.connectionNumber, 1, `${gHttpServer.connectionNumber} speculative connection has been setup.`);
 });
 
 add_task(async function privateContext_test() {
   info("In private context.");
   gIsSpeculativeConnected = false;
-  info(`Searching for '${test.search}'`);
-  await promiseAutocompleteResultPopup(test.search, gPrivateWin, true);
-  is(gPrivateWin.gURLBar.inputField.value, test.autofilledValue,
-     `Autofilled value is as expected for search '${test.search}'`);
+  info(`Searching for '${gTest.search}'`);
+  await promiseAutocompleteResultPopup(gTest.search, gPrivateWin, true);
+  is(gPrivateWin.gURLBar.inputField.value, gTest.autofilledValue,
+     `Autofilled value is as expected for search '${gTest.search}'`);
   is(gIsSpeculativeConnected, false, "Speculative connection shouldn't be called");
 });
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -35,17 +35,17 @@ file, You can obtain one at http://mozil
           <html:input anonid="input"
                       class="autocomplete-textbox urlbar-input textbox-input"
                       allowevents="true"
                       inputmode="mozAwesomebar"
                       xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
         </xul:hbox>
         <xul:image anonid="urlbar-go-button"
                    class="urlbar-go-button urlbar-icon"
-                   onclick="gURLBar.handleCommand(event);"
+                   onclick="gURLBar.handleEnter(event);"
                    tooltiptext="&goEndCap.tooltip;"
                    xbl:inherits="pageproxystate,parentfocused=focused,usertyping"/>
         <xul:dropmarker anonid="historydropmarker"
                         class="urlbar-history-dropmarker urlbar-icon chromeclass-toolbar-additional"
                         tooltiptext="&urlbar.openHistoryPopup.tooltip;"
                         allowevents="true"
                         xbl:inherits="open,parentfocused=focused,usertyping"/>
         <children includes="hbox"/>
@@ -365,26 +365,29 @@ file, You can obtain one at http://mozil
       ])</field>
       <field name="_deferredKeyEventQueue">[]</field>
       <field name="_deferredKeyEventTimeout">null</field>
       <field name="_deferredKeyEventTimeoutMs">200</field>
       <field name="_searchStartDate">0</field>
 
       <method name="maybeReplayDeferredKeyEvents">
         <body><![CDATA[
+          dump(`*****XXXadw maybeReplayDeferredKeyEvents\n`);
           if (!this._deferredKeyEventQueue.length ||
               this._shouldDeferKeyEvent()) {
+            dump(`*****XXXadw maybeReplayDeferredKeyEvents 1\n`);
             return;
           }
           if (this._deferredKeyEventTimeout) {
             clearTimeout(this._deferredKeyEventTimeout);
             this._deferredKeyEventTimeout = null;
           }
           let instance = this._deferredKeyEventQueue.shift();
           // Safety check: handle only if the search string didn't change.
+          dump(`*****XXXadw maybeReplayDeferredKeyEvents 2 this.mController.searchString='${this.mController.searchString}' instance.searchString='${instance.searchString}'\n`);
           if (this.mController.searchString == instance.searchString) {
             this[instance.methodName](instance.event);
           }
           setTimeout(() => {
             this.maybeReplayDeferredKeyEvents();
           });
         ]]></body>
       </method>
@@ -535,16 +538,17 @@ file, You can obtain one at http://mozil
                "where", this method computes the appropriate parameters, but
                any parameters you supply here will override those.
       -->
       <method name="handleCommand">
         <parameter name="event"/>
         <parameter name="openUILinkWhere"/>
         <parameter name="openUILinkParams"/>
         <body><![CDATA[
+        dump("*****XXXadw urlbarBindings handleCommand\n");
           let isMouseEvent = event instanceof MouseEvent;
           if (isMouseEvent && event.button == 2) {
             // Do nothing for right clicks.
             return;
           }
 
           BrowserUsageTelemetry.recordUrlbarSelectedResultMethod(event);
 
@@ -1351,16 +1355,17 @@ file, You can obtain one at http://mozil
           }
           this.resetActionType();
         ]]></body>
       </method>
 
       <method name="handleEnter">
         <parameter name="event"/>
         <body><![CDATA[
+          dump(`*****XXXadw urlbarBindings handleEnter this._deferredKeyEventQueue.length=${this._deferredKeyEventQueue.length} this.popup.selectedIndex=${this.popup.selectedIndex} this.gotResultForCurrentQuery=${this.gotResultForCurrentQuery}\n`);
           // We need to ensure we're using a selected autocomplete result.
           // A result should automatically be selected by default,
           // however autocomplete is async and therefore we may not
           // have a result set relating to the current input yet. If that
           // happens, we need to mark that when the first result does get added,
           // it needs to be handled as if enter was pressed with that first
           // result selected.
           // If anything other than the default (first) result is selected, then
@@ -1371,16 +1376,17 @@ file, You can obtain one at http://mozil
           // ensure that it corresponds to the current input.
 
           // Store the current search string so it can be used in handleCommand,
           // which will be called as a result of mController.handleEnter().
           this.handleEnterSearchString = this.mController.searchString;
 
           if (!this._deferredKeyEventQueue.length &&
               (this.popup.selectedIndex != 0 || this.gotResultForCurrentQuery)) {
+              dump(`*****XXXadw urlbarBindings handleEnter 1\n`);
             let canonizeValue = this.value;
             if (event.shiftKey || (AppConstants.platform === "macosx" ?
                                    event.metaKey :
                                    event.ctrlKey)) {
               let action = this._parseActionUrl(canonizeValue);
               if (action && "searchSuggestion" in action.params) {
                 canonizeValue = action.params.searchSuggestion;
               } else if (this.popup.selectedIndex === 0 &&
@@ -1390,16 +1396,18 @@ file, You can obtain one at http://mozil
             }
             this.maybeCanonizeURL(event, canonizeValue);
             let handled = this.mController.handleEnter(false, event);
             this.handleEnterSearchString = null;
             this.popup.overrideValue = null;
             return handled;
           }
 
+          dump(`*****XXXadw urlbarBindings handleEnter 2\n`);
+
           // Defer the event until the first non-heuristic result comes in.
           this._deferKeyEvent(event, "handleEnter");
           return false;
         ]]></body>
       </method>
 
       <method name="handleDelete">
         <body><![CDATA[
@@ -2137,22 +2145,25 @@ file, You can obtain one at http://mozil
             return parts.filter(str => str).join(" ");
           ]]>
         </body>
       </method>
 
       <method name="maybeSetupSpeculativeConnect">
         <parameter name="aUriString"/>
         <body><![CDATA[
+          dump(`*****XXXadw maybeSetupSpeculativeConnect uri='${aUriString}'\n`);
+          dump((new Error()).stack + "\n");
           try {
             let uri = makeURI(aUriString);
             Services.io.speculativeConnect2(uri, gBrowser.contentPrincipal, null);
           } catch (ex) {
             // Can't setup speculative connection for this uri string for some
             // reason, just ignore it.
+            dump(`*****XXXadw maybeSetupSpeculativeConnect ERROR ${ex}\n`);
           }
         ]]></body>
       </method>
 
       <method name="onResultsAdded">
         <body>
           <![CDATA[
             // If nothing is selected yet, select the first result if it is a
@@ -2169,20 +2180,23 @@ file, You can obtain one at http://mozil
             // connect to the intended site as a performance optimization.
             if (!this.input.gotResultForCurrentQuery &&
                 this.input.speculativeConnectEnabled &&
                 !this.input.inPrivateContext &&
                 this.input.mController.matchCount > 0) {
               let firstStyle = this.input.mController.getStyleAt(0);
               if (firstStyle.includes("autofill")) {
                 let uri = this.input.mController.getFinalCompleteValueAt(0);
+/*XXXadw
                 // "http" will be stripped out, but other scheme won't.
                 if (!uri.includes("://")) {
                   uri = "http://" + uri;
                 }
+*/
+                dump(`*****XXXadw onResultsAdded uri='${uri}'\n`);
                 this.maybeSetupSpeculativeConnect(uri);
               } else if (firstStyle.includes("searchengine") &&
                          this.input.browserSearchSuggestEnabled &&
                          this.input.urlbarSearchSuggestEnabled) {
                 // Preconnect to the current search engine only if the search
                 // suggestions are enabled.
                 let engine = Services.search.currentEngine;
                 engine.speculativeConnect({window,
--- a/netwerk/base/nsIBrowserSearchService.idl
+++ b/netwerk/base/nsIBrowserSearchService.idl
@@ -150,19 +150,19 @@ interface nsISearchEngine : nsISupports
   /**
    * An optional unique identifier for this search engine within the context of
    * the distribution, as provided by the distributing entity.
    */
   readonly attribute AString identifier;
 
   /**
    * Gets a string representing the hostname from which search results for a
-   * given responseType are returned, minus the leading "www." (if present).
-   * This can be specified as an url attribute in the engine description file,
-   * but will default to host from the <Url>'s template otherwise.
+   * given responseType are returned.  This can be specified as an url attribute
+   * in the engine description file, but will default to host from the <Url>'s
+   * template otherwise.
    *
    * @param  responseType [optional]
    *         The MIME type to get resultDomain for.  Defaults to "text/html".
    *
    * @return the resultDomain for the given responseType.
    */
   AString getResultDomain([optional] in AString responseType);
 };
--- a/services/sync/tests/unit/test_history_store.js
+++ b/services/sync/tests/unit/test_history_store.js
@@ -158,18 +158,18 @@ add_task(async function test_invalid_rec
   _("Make sure we handle invalid URLs in places databases gracefully.");
   await PlacesUtils.withConnectionWrapper("test_invalid_record", async function(db) {
     await db.execute(
       "INSERT INTO moz_places "
       + "(url, url_hash, title, rev_host, visit_count, last_visit_date) "
       + "VALUES ('invalid-uri', hash('invalid-uri'), 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"
     );
     // Trigger the update on moz_hosts by deleting the added rows from
-    // moz_updatehostsinsert_temp
-    await db.execute("DELETE FROM moz_updatehostsinsert_temp");
+    // moz_updateoriginsinsert_temp
+    await db.execute("DELETE FROM moz_updateoriginsinsert_temp");
     // Add the corresponding visit to retain database coherence.
     await db.execute(
       "INSERT INTO moz_historyvisits "
       + "(place_id, visit_date, visit_type, session) "
       + "VALUES ((SELECT id FROM moz_places WHERE url_hash = hash('invalid-uri') AND url = 'invalid-uri'), "
       + TIMESTAMP3 + ", " + Ci.nsINavHistoryService.TRANSITION_TYPED + ", 1)"
     );
   });
--- a/toolkit/components/autocomplete/nsAutoCompleteController.cpp
+++ b/toolkit/components/autocomplete/nsAutoCompleteController.cpp
@@ -17,16 +17,24 @@
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 #include "nsIObserverService.h"
 #include "nsIDOMKeyEvent.h"
 #include "mozilla/Services.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/Unused.h"
 
+//XXXadw
+#if defined(_MSC_VER)
+#define PRETTY_FUNCTION_XXXadw __FUNCSIG__
+#else
+#define PRETTY_FUNCTION_XXXadw __PRETTY_FUNCTION__
+#endif
+
+
 static const char *kAutoCompleteSearchCID = "@mozilla.org/autocomplete/search;1?name=";
 
 using namespace mozilla;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsAutoCompleteController)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAutoCompleteController)
   tmp->SetInput(nullptr);
@@ -342,16 +350,18 @@ nsAutoCompleteController::HandleText(boo
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAutoCompleteController::HandleEnter(bool aIsPopupSelection,
                                       nsIDOMEvent *aEvent,
                                       bool *_retval)
 {
+  printf("$$$XXXadw %s\n", PRETTY_FUNCTION_XXXadw);
+
   *_retval = false;
   if (!mInput)
     return NS_OK;
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
 
   // allow the event through unless there is something selected in the popup
   input->GetPopupOpen(_retval);
@@ -1177,30 +1187,36 @@ nsAutoCompleteController::OpenPopup()
   }
 
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::ClosePopup()
 {
+  printf("$$$XXXadw %s\n", PRETTY_FUNCTION_XXXadw);
+
   if (!mInput) {
+    printf("$$$XXXadw %s !mInput\n", PRETTY_FUNCTION_XXXadw);
     return NS_OK;
   }
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
 
   bool isOpen = false;
   input->GetPopupOpen(&isOpen);
-  if (!isOpen)
+  if (!isOpen) {
+    printf("$$$XXXadw %s !isOpen\n", PRETTY_FUNCTION_XXXadw);
     return NS_OK;
+  }
 
   nsCOMPtr<nsIAutoCompletePopup> popup;
   input->GetPopup(getter_AddRefs(popup));
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
+  printf("$$$XXXadw %s SetSelectedIndex(-1)\n", PRETTY_FUNCTION_XXXadw);
   popup->SetSelectedIndex(-1);
   return input->SetPopupOpen(false);
 }
 
 nsresult
 nsAutoCompleteController::BeforeSearches()
 {
   NS_ENSURE_STATE(mInput);
@@ -1359,16 +1375,18 @@ nsAutoCompleteController::MaybeCompleteP
     !mUserClearedAutoFill &&
     !mPlaceholderCompletionString.IsEmpty() &&
     mPlaceholderCompletionString.Length() > mSearchString.Length() &&
     selectionEnd == selectionStart &&
     selectionEnd == (int32_t)mSearchString.Length() &&
     StringBeginsWith(mPlaceholderCompletionString, mSearchString,
                     nsCaseInsensitiveStringComparator());
 
+  printf("$$$XXXadw %s usePlaceholderCompletion=%d\n", PRETTY_FUNCTION_XXXadw, usePlaceholderCompletion);
+
   if (usePlaceholderCompletion) {
     CompleteValue(mPlaceholderCompletionString);
   } else {
     mPlaceholderCompletionString.Truncate();
   }
 }
 
 nsresult
@@ -1438,80 +1456,94 @@ nsAutoCompleteController::EnterMatch(boo
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
   nsCOMPtr<nsIAutoCompletePopup> popup;
   input->GetPopup(getter_AddRefs(popup));
   NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
 
   bool forceComplete;
   input->GetForceComplete(&forceComplete);
 
+  printf("$$$XXXadw %s\n", PRETTY_FUNCTION_XXXadw);
+
   // Ask the popup if it wants to enter a special value into the textbox
   nsAutoString value;
   popup->GetOverrideValue(value);
   if (value.IsEmpty()) {
     bool shouldComplete;
     input->GetCompleteDefaultIndex(&shouldComplete);
     bool completeSelection;
     input->GetCompleteSelectedIndex(&completeSelection);
 
     int32_t selectedIndex;
     popup->GetSelectedIndex(&selectedIndex);
+
+    printf("$$$XXXadw %s selectedIndex=%d shouldComplete=%d completeSelection=%d\n", PRETTY_FUNCTION_XXXadw, selectedIndex, shouldComplete, completeSelection);
+
     if (selectedIndex >= 0) {
       nsAutoString inputValue;
       input->GetTextValue(inputValue);
+      printf("$$$XXXadw %s inputValue=%s\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(inputValue).get());
       if (aIsPopupSelection || !completeSelection) {
         // We need to fill-in the value if:
         //  * completeselectedindex is false
         //  * A row in the popup was confirmed
         //
         // TODO: This is not totally correct, cause it will also confirm
         // a result selected with a simple mouseover, that could also have
         // happened accidentally, maybe touching a touchpad.
         // The reason is that autocomplete.xml sets selectedIndex on mousemove
         // making impossible, in the !completeSelection case, to distinguish if
         // the user wanted to confirm autoFill or the popup entry.
         // The solution may be to change autocomplete.xml to set selectedIndex
         // only on popupClick, but that requires changing the selection behavior.
         GetResultValueAt(selectedIndex, true, value);
+        printf("$$$XXXadw %s A\n", PRETTY_FUNCTION_XXXadw);
       } else if (mDefaultIndexCompleted &&
                  inputValue.Equals(mPlaceholderCompletionString,
                                    nsCaseInsensitiveStringComparator())) {
         // We also need to fill-in the value if the default index completion was
         // confirmed, though we cannot use the selectedIndex cause the selection
         // may have been changed by the mouse in the meanwhile.
         GetFinalDefaultCompleteValue(value);
+        printf("$$$XXXadw %s B\n", PRETTY_FUNCTION_XXXadw);
       } else if (mCompletedSelectionIndex != -1) {
         // If completeselectedindex is true, and EnterMatch was not invoked by
         // mouse-clicking a match (for example the user pressed Enter),
         // don't fill in the value as it will have already been filled in as
         // needed, unless the selected match has a final complete value that
         // differs from the user-facing value.
         nsAutoString finalValue;
         GetResultValueAt(mCompletedSelectionIndex, true, finalValue);
         if (!inputValue.Equals(finalValue)) {
           value = finalValue;
+          printf("$$$XXXadw %s C\n", PRETTY_FUNCTION_XXXadw);
         }
         // Note that if the user opens the popup, mouses over entries without
         // ever selecting one with the keyboard, and then hits enter, none of
         // the above cases will be hit, since mouseover doesn't activate
         // completeselectedindex and thus mCompletedSelectionIndex would be
         // -1.
       }
     } else if (shouldComplete) {
       // We usually try to preserve the casing of what user has typed, but
       // if he wants to autocomplete, we will replace the value with the
       // actual autocomplete result.
       // The user wants explicitely to use that result, so this ensures
       // association of the result with the autocompleted text.
       nsAutoString defaultIndexValue;
-      if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(defaultIndexValue)))
+      if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(defaultIndexValue))) {
         value = defaultIndexValue;
+        printf("$$$XXXadw %s D\n", PRETTY_FUNCTION_XXXadw);
+      }
     }
 
+    printf("$$$XXXadw %s value=%s\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(value).get());
+
     if (forceComplete && value.IsEmpty() && shouldComplete) {
+      printf("$$$XXXadw %s forceComplete A\n", PRETTY_FUNCTION_XXXadw);
       // See if inputValue is one of the autocomplete results. It can be an
       // identical value, or if it matched the middle of a result it can be
       // something like "bar >> foobar" (user entered bar and foobar is
       // the result value).
       // If the current search matches one of the autocomplete results, we
       // should use that result, and not overwrite it with the default value.
       // It's indeed possible EnterMatch gets called a second time (for example
       // by the blur handler) and it should not overwrite the current match.
@@ -1541,16 +1573,17 @@ nsAutoCompleteController::EnterMatch(boo
             }
           }
         }
       }
       // The value should have been set at this point. If not, then it's not
       // a value that should be autocompleted.
     }
     else if (forceComplete && value.IsEmpty() && completeSelection) {
+      printf("$$$XXXadw %s forceComplete B\n", PRETTY_FUNCTION_XXXadw);
       // Since nothing was selected, and forceComplete is specified, that means
       // we have to find the first default match and enter it instead.
       for (uint32_t i = 0; i < mResults.Length(); ++i) {
         nsIAutoCompleteResult *result = mResults[i];
         if (result) {
           int32_t defaultIndex;
           result->GetDefaultIndex(&defaultIndex);
           if (defaultIndex >= 0) {
@@ -1751,16 +1784,17 @@ nsAutoCompleteController::PostSearchClea
 
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::ClearResults(bool aIsSearching)
 {
   int32_t oldRowCount = mRowCount;
+  printf("$$$XXXadw %s oldRowCount=%d\n", PRETTY_FUNCTION_XXXadw, oldRowCount);
   mRowCount = 0;
   mResults.Clear();
   if (oldRowCount != 0) {
     if (mTree) {
       if (aIsSearching) {
         // Delay the notification, so the tree provides a smoother transition to
         // the new result. It will be handled as soon as we add the first result.
         mDelayedRowCountDelta = -oldRowCount;
@@ -1770,16 +1804,17 @@ nsAutoCompleteController::ClearResults(b
       }
     } else if (mInput) {
       nsCOMPtr<nsIAutoCompletePopup> popup;
       mInput->GetPopup(getter_AddRefs(popup));
       NS_ENSURE_TRUE(popup != nullptr, NS_ERROR_FAILURE);
       // if we had a tree, RowCountChanged() would have cleared the selection
       // when the selected row was removed.  But since we don't have a tree,
       // we need to clear the selection manually.
+      printf("$$$XXXadw %s SetSelectedIndex(-1)\n", PRETTY_FUNCTION_XXXadw);
       popup->SetSelectedIndex(-1);
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::CompleteDefaultIndex(int32_t aResultIndex)
@@ -1805,25 +1840,30 @@ nsAutoCompleteController::CompleteDefaul
   // selection is from the current placeholder completion value, then still
   // automatically complete.
   if (!isPlaceholderSelected && (selectionEnd != selectionStart ||
         selectionEnd != (int32_t)mSearchString.Length()))
     return NS_OK;
 
   bool shouldComplete;
   input->GetCompleteDefaultIndex(&shouldComplete);
+  printf("$$$XXXadw %s shouldComplete=%d\n", PRETTY_FUNCTION_XXXadw, shouldComplete);
   if (!shouldComplete)
     return NS_OK;
 
   nsAutoString resultValue;
   if (NS_SUCCEEDED(GetDefaultCompleteValue(aResultIndex, true, resultValue))) {
+    printf("$$$XXXadw %s resultValue=%s\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(resultValue).get());
     CompleteValue(resultValue);
 
     mDefaultIndexCompleted = true;
   }
+  else {
+    printf("$$$XXXadw %s couldn't get resultValue\n", PRETTY_FUNCTION_XXXadw);
+  }
 
   return NS_OK;
 }
 
 nsresult
 nsAutoCompleteController::GetDefaultCompleteResult(int32_t aResultIndex,
                                                    nsIAutoCompleteResult** _result,
                                                    int32_t* _defaultIndex)
@@ -1929,22 +1969,25 @@ nsAutoCompleteController::GetFinalDefaul
   rv = result->GetFinalCompleteValueAt(defaultIndex, finalCompleteValue);
   if (NS_SUCCEEDED(rv)) {
     _retval = finalCompleteValue;
   }
 
   return NS_OK;
 }
 
+// #if 0
 nsresult
 nsAutoCompleteController::CompleteValue(nsString &aValue)
 /* mInput contains mSearchString, which we want to autocomplete to aValue.  If
  * selectDifference is true, select the remaining portion of aValue not
  * contained in mSearchString. */
 {
+  printf("$$$XXXadw %s mSearchString=`%s` aValue=`%s`\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(mSearchString).get(), NS_ConvertUTF16toUTF8(aValue).get());
+
   MOZ_ASSERT(mInput, "Must have a valid input");
 
   nsCOMPtr<nsIAutoCompleteInput> input(mInput);
   const int32_t mSearchStringLength = mSearchString.Length();
   int32_t endSelect = aValue.Length();  // By default, select all of aValue.
 
   if (aValue.IsEmpty() ||
       StringBeginsWith(aValue, mSearchString,
@@ -1995,16 +2038,135 @@ nsAutoCompleteController::CompleteValue(
       mPlaceholderCompletionString.Truncate();
     }
   }
 
   input->SelectTextRange(mSearchStringLength, endSelect);
 
   return NS_OK;
 }
+// #endif
+
+#if 0
+nsresult
+nsAutoCompleteController::CompleteValue(nsString &aValue)
+/* mInput contains mSearchString, which we want to autocomplete to aValue.  If
+ * selectDifference is true, select the remaining portion of aValue not
+ * contained in mSearchString. */
+{
+  printf("$$$XXXadw %s mSearchString=`%s` aValue=`%s`\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(mSearchString).get(), NS_ConvertUTF16toUTF8(aValue).get());
+
+  MOZ_ASSERT(mInput, "Must have a valid input");
+
+  nsCOMPtr<nsIAutoCompleteInput> input(mInput);
+  const int32_t mSearchStringLength = mSearchString.Length();
+  int32_t endSelect = aValue.Length();  // By default, select all of aValue.
+
+  if (aValue.IsEmpty() ||
+      StringBeginsWith(aValue, mSearchString,
+                       nsCaseInsensitiveStringComparator())) {
+    printf("$$$XXXadw %s A\n", PRETTY_FUNCTION_XXXadw);
+    // aValue is empty (we were asked to clear mInput), or mSearchString
+    // matches the beginning of aValue.  In either case we can simply
+    // autocomplete to aValue.
+    mPlaceholderCompletionString = aValue;
+    SetTextValue(input, aValue,
+                 nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
+  } else {
+    nsresult rv;
+    nsCOMPtr<nsIIOService> ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsAutoCString scheme;
+    printf("$$$XXXadw %s aValue=%s\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(aValue).get());
+    if (NS_SUCCEEDED(ios->ExtractScheme(NS_ConvertUTF16toUTF8(aValue), scheme))) {
+
+      printf("$$$XXXadw %s got scheme: %s\n", PRETTY_FUNCTION_XXXadw, scheme.get());
+
+      // Trying to autocomplete a URI from somewhere other than the beginning.
+      // Only succeed if the missing portion is "http://"; otherwise do not
+      // autocomplete.  This prevents us from "helpfully" autocompleting to a
+      // URI that isn't equivalent to what the user expected.
+//       const int32_t findIndex = 7; // length of "http://"
+      int32_t findIndex = 7; // length of "http://"
+
+//       if ((endSelect < findIndex + mSearchStringLength) ||
+//           !scheme.LowerCaseEqualsLiteral("http") ||
+//           !Substring(aValue, findIndex, mSearchStringLength).Equals(
+//             mSearchString, nsCaseInsensitiveStringComparator())) {
+//         return NS_OK;
+//       }
+
+      if ((endSelect < findIndex + mSearchStringLength) ||
+          !scheme.LowerCaseEqualsLiteral("http") ||
+          !Substring(aValue, findIndex, mSearchStringLength).Equals(
+            mSearchString, nsCaseInsensitiveStringComparator())) {
+        printf("$$$XXXadw %s B\n", PRETTY_FUNCTION_XXXadw);
+        findIndex++;
+        if ((endSelect < findIndex + mSearchStringLength) ||
+            !scheme.LowerCaseEqualsLiteral("https") ||
+            !Substring(aValue, findIndex, mSearchStringLength).Equals(
+              mSearchString, nsCaseInsensitiveStringComparator())) {
+          printf("$$$XXXadw %s C\n", PRETTY_FUNCTION_XXXadw);
+          return NS_OK;
+        }
+      }
+
+      printf("$$$XXXadw %s D\n", PRETTY_FUNCTION_XXXadw);
+
+      mPlaceholderCompletionString = mSearchString +
+        Substring(aValue, mSearchStringLength + findIndex, endSelect);
+      SetTextValue(input, mPlaceholderCompletionString,
+                   nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
+
+      endSelect -= findIndex; // We're skipping this many characters of aValue.
+    } else {
+      printf("$$$XXXadw %s did not get scheme\n", PRETTY_FUNCTION_XXXadw);
+      // Autocompleting something other than a URI from the middle.
+      // Use the format "searchstring >> full string" to indicate to the user
+      // what we are going to replace their search string with.
+      SetTextValue(input, mSearchString + NS_LITERAL_STRING(" >> ") + aValue,
+                   nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
+
+      endSelect = mSearchString.Length() + 4 + aValue.Length();
+
+      // Reset the last search completion.
+      mPlaceholderCompletionString.Truncate();
+    }
+  }
+
+  input->SelectTextRange(mSearchStringLength, endSelect);
+
+  return NS_OK;
+}
+#endif
+
+#if 0
+nsresult
+nsAutoCompleteController::CompleteValue(nsString &aValue)
+/* mInput contains mSearchString, which we want to autocomplete to aValue.  If
+ * selectDifference is true, select the remaining portion of aValue not
+ * contained in mSearchString. */
+{
+  printf("$$$XXXadw %s mSearchString=`%s` aValue=`%s`\n", PRETTY_FUNCTION_XXXadw, NS_ConvertUTF16toUTF8(mSearchString).get(), NS_ConvertUTF16toUTF8(aValue).get());
+
+  MOZ_ASSERT(mInput, "Must have a valid input");
+
+  nsCOMPtr<nsIAutoCompleteInput> input(mInput);
+  const int32_t mSearchStringLength = mSearchString.Length();
+  int32_t endSelect = aValue.Length();  // By default, select all of aValue.
+
+  mPlaceholderCompletionString = aValue;
+  SetValueOfInputTo(aValue,
+               nsIAutoCompleteInput::TEXTVALUE_REASON_COMPLETEDEFAULT);
+
+  input->SelectTextRange(mSearchStringLength, endSelect);
+
+  return NS_OK;
+}
+#endif
 
 nsresult
 nsAutoCompleteController::GetResultLabelAt(int32_t aIndex, nsAString & _retval)
 {
   return GetResultValueLabelAt(aIndex, false, false, _retval);
 }
 
 nsresult
--- a/toolkit/components/places/Bookmarks.jsm
+++ b/toolkit/components/places/Bookmarks.jsm
@@ -2358,17 +2358,17 @@ async function maybeInsertPlace(db, url)
   await db.executeCached(
     `INSERT OR IGNORE INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid)
      VALUES (:url, hash(:url), :rev_host, 0, :frecency,
              IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
                     GENERATE_GUID()))
     `, { url: url.href,
          rev_host: PlacesUtils.getReversedHost(url),
          frecency: url.protocol == "place:" ? 0 : -1 });
-  await db.executeCached("DELETE FROM moz_updatehostsinsert_temp");
+  await db.executeCached("DELETE FROM moz_updateoriginsinsert_temp");
 }
 
 /**
  * Tries to insert a new place if it doesn't exist yet.
  * @param db
  *        The database to use
  * @param urls
  *        An array with all the url objects to insert.
@@ -2380,17 +2380,17 @@ async function maybeInsertManyPlaces(db,
      (:url, hash(:url), :rev_host, 0, :frecency,
      IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url), :maybeguid))`,
      urls.map(url => ({
        url: url.href,
        rev_host: PlacesUtils.getReversedHost(url),
        frecency: url.protocol == "place:" ? 0 : -1,
        maybeguid: PlacesUtils.history.makeGuid(),
      })));
-  await db.executeCached("DELETE FROM moz_updatehostsinsert_temp");
+  await db.executeCached("DELETE FROM moz_updateoriginsinsert_temp");
 }
 
 // Indicates whether we should write a tombstone for an item that has been
 // uploaded to the server. We ignore "NEW" and "UNKNOWN" items: "NEW" items
 // haven't been uploaded yet, and "UNKNOWN" items need a full reconciliation
 // with the server.
 function needsTombstone(item) {
   return item._syncStatus == Bookmarks.SYNC_STATUS.NORMAL;
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -1196,64 +1196,82 @@ Database::InitSchema(bool* aDatabaseMigr
 
       if (currentSchemaVersion < 41) {
         rv = MigrateV41Up();
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       // Firefox 58 uses schema version 41.
 
+      if (currentSchemaVersion < 42) {
+        rv = MigrateV42Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      //XXXadw
+      // Firefox XXXadw uses schema version 42.
+
       // Schema Upgrades must add migration code here.
       // >>> IMPORTANT! <<<
       // NEVER MIX UP SYNC AND ASYNC EXECUTION IN MIGRATORS, YOU MAY LOCK THE
       // CONNECTION AND CAUSE FURTHER STEPS TO FAIL.
       // In case, set a bool and do the async work in the ScopeExit guard just
       // before the migration steps.
 
       rv = UpdateBookmarkRootTitles();
       // We don't want a broken localization to cause us to think
       // the database is corrupt and needs to be replaced.
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
   else {
     // This is a new database, so we have to create all the tables and indices.
 
+    // moz_prefixes, moz_hosts, and moz_origins.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_PREFIXES);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_HOSTS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_ORIGINS);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     // moz_places.
     rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_PLACES);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL_HASH);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_REVHOST);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_VISITCOUNT);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FRECENCY);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_LASTVISITDATE);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_GUID);
     NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_ORIGIN_ID);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     // moz_historyvisits.
     rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_HISTORYVISITS);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_FROMVISIT);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_VISITDATE);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // moz_inputhistory.
     rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_INPUTHISTORY);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // moz_hosts.
-    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_HOSTS);
+    // moz_autofill_origins.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_AUTOFILL_ORIGINS);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // moz_bookmarks.
     rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS_DELETED);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACETYPE);
@@ -1413,47 +1431,69 @@ Database::InitFunctions()
   rv = FixupURLFunction::create(mMainConn);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = FrecencyNotificationFunction::create(mMainConn);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = StoreLastInsertedIdFunction::create(mMainConn);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = HashFunction::create(mMainConn);
   NS_ENSURE_SUCCESS(rv, rv);
+  rv = GetPrefixFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = GetHostAndPortFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = StripPrefixFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = UpdateFrecencyStatsFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = IsFrecencyDecayingFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 Database::InitTempEntities()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv = mMainConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERINSERT_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mMainConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERDELETE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Add the triggers that update the moz_hosts table as necessary.
-  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSINSERT_TEMP);
+//   rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSINSERT_TEMP);
+//   NS_ENSURE_SUCCESS(rv, rv);
+//   rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSINSERT_AFTERDELETE_TRIGGER);
+//   NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEORIGINSINSERT_TEMP);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSINSERT_AFTERDELETE_TRIGGER);
+  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEORIGINSINSERT_AFTERDELETE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
+
   rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERINSERT_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSDELETE_TEMP);
+//   rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSDELETE_TEMP);
+//   NS_ENSURE_SUCCESS(rv, rv);
+//   rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSDELETE_AFTERDELETE_TRIGGER);
+//   NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEORIGINSDELETE_TEMP);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEHOSTSDELETE_AFTERDELETE_TRIGGER);
+  rv = mMainConn->ExecuteSimpleSQL(CREATE_UPDATEORIGINSDELETE_AFTERDELETE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
+
   rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERDELETE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_FRECENCY_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_TYPED_TRIGGER);
-  NS_ENSURE_SUCCESS(rv, rv);
+//   rv = mMainConn->ExecuteSimpleSQL(CREATE_PLACES_AFTERUPDATE_TYPED_TRIGGER);
+//   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mMainConn->ExecuteSimpleSQL(CREATE_BOOKMARKS_FOREIGNCOUNT_AFTERDELETE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mMainConn->ExecuteSimpleSQL(CREATE_BOOKMARKS_FOREIGNCOUNT_AFTERINSERT_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mMainConn->ExecuteSimpleSQL(CREATE_BOOKMARKS_FOREIGNCOUNT_AFTERUPDATE_TRIGGER);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1607,33 +1647,34 @@ Database::MigrateV32Up() {
     "WHERE host IN (SELECT host FROM moz_migrate_v32_temp) "
       "AND NOT EXISTS("
         "SELECT 1 FROM moz_places "
           "WHERE rev_host = get_unreversed_host(host || '.') || '.' "
              "OR rev_host = get_unreversed_host(host || '.') || '.www.' "
       "); "
   ), getter_AddRefs(deleteHostsStmt));
   NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<mozIStorageAsyncStatement> updateHostsStmt;
-  rv = mMainConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_hosts "
-    "SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") "
-    "WHERE host IN (SELECT host FROM moz_migrate_v32_temp) "
-  ), getter_AddRefs(updateHostsStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+  //XXXadw
+//   nsCOMPtr<mozIStorageAsyncStatement> updateHostsStmt;
+//   rv = mMainConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+//     "UPDATE moz_hosts "
+//     "SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") "
+//     "WHERE host IN (SELECT host FROM moz_migrate_v32_temp) "
+//   ), getter_AddRefs(updateHostsStmt));
+//   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<mozIStorageAsyncStatement> dropTableStmt;
   rv = mMainConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
     "DROP TABLE IF EXISTS moz_migrate_v32_temp"
   ), getter_AddRefs(dropTableStmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mozIStorageBaseStatement *stmts[] = {
     expireOrphansStmt,
     deleteHostsStmt,
-    updateHostsStmt,
+//     updateHostsStmt,
     dropTableStmt
   };
   nsCOMPtr<mozIStoragePendingStatement> ps;
   rv = mMainConn->ExecuteAsync(stmts, ArrayLength(stmts), nullptr,
                                getter_AddRefs(ps));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
@@ -1949,16 +1990,65 @@ Database::MigrateV41Up() {
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DROP TABLE IF EXISTS moz_favicons"));
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 nsresult
+Database::MigrateV42Up() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv;
+  nsCOMPtr<mozIStorageStatement> stmt;
+
+  // Create the moz_prefixes table if it doesn't already exist.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT * FROM moz_prefixes"
+  ), getter_AddRefs(stmt));
+  if (NS_FAILED(rv)) {
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_PREFIXES);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Create the moz_origins table if it doesn't already exist.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT * FROM moz_origins"
+  ), getter_AddRefs(stmt));
+  if (NS_FAILED(rv)) {
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_ORIGINS);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Create the moz_autofill_origins table if it doesn't already exist.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT * FROM moz_autofill_origins"
+  ), getter_AddRefs(stmt));
+  if (NS_FAILED(rv)) {
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_AUTOFILL_ORIGINS);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Add the moz_places.origin_id column if it doesn't already exist.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT origin_id FROM moz_places"
+  ), getter_AddRefs(stmt));
+  if (NS_FAILED(rv)) {
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "ALTER TABLE moz_places " \
+      "ADD COLUMN origin_id INTEGER REFERENCES moz_origins(id) ON DELETE CASCADE"
+    ));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+nsresult
 Database::GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
                            nsTArray<int64_t>& aItemIds)
 {
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT b.id FROM moz_items_annos a "
     "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
     "JOIN moz_bookmarks b ON b.id = a.item_id "
--- a/toolkit/components/places/Database.h
+++ b/toolkit/components/places/Database.h
@@ -14,17 +14,17 @@
 #include "mozilla/storage/StatementCache.h"
 #include "mozilla/Attributes.h"
 #include "nsIEventTarget.h"
 #include "Shutdown.h"
 #include "nsCategoryCache.h"
 
 // This is the schema version. Update it at any schema change and add a
 // corresponding migrateVxx method below.
-#define DATABASE_SCHEMA_VERSION 41
+#define DATABASE_SCHEMA_VERSION 42
 
 // Fired after Places inited.
 #define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
 // This topic is received when the profile is about to be lost.  Places does
 // initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
 // Any shutdown work that requires the Places APIs should happen here.
 #define TOPIC_PROFILE_CHANGE_TEARDOWN "profile-change-teardown"
 // Fired when Places is shutting down.  Any code should stop accessing Places
@@ -297,16 +297,17 @@ protected:
   nsresult MigrateV34Up();
   nsresult MigrateV35Up();
   nsresult MigrateV36Up();
   nsresult MigrateV37Up();
   nsresult MigrateV38Up();
   nsresult MigrateV39Up();
   nsresult MigrateV40Up();
   nsresult MigrateV41Up();
+  nsresult MigrateV42Up();
 
   nsresult UpdateBookmarkRootTitles();
 
   friend class ConnectionShutdownBlocker;
 
   int64_t CreateMobileRoot();
   nsresult GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
                             nsTArray<int64_t>& aItemIds);
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -106,16 +106,17 @@ struct VisitData {
   , titleChanged(false)
   , shouldUpdateFrecency(true)
   , redirect(false)
   {
     MOZ_ASSERT(aURI);
     if (aURI) {
       (void)aURI->GetSpec(spec);
       (void)GetReversedHostname(aURI, revHost);
+      (void)aURI->GetPrePath(origin);
     }
     if (aReferrer) {
       (void)aReferrer->GetSpec(referrerSpec);
     }
     guid.SetIsVoid(true);
     title.SetIsVoid(true);
   }
 
@@ -132,16 +133,17 @@ struct VisitData {
     transitionType = aTransitionType;
   }
 
   int64_t placeId;
   nsCString guid;
   int64_t visitId;
   nsCString spec;
   nsString revHost;
+  nsCString origin;
   bool hidden;
   bool shouldUpdateHidden;
   bool typed;
   uint32_t transitionType;
   PRTime visitTime;
   int32_t frecency;
   int64_t lastVisitId;
   PRTime lastVisitTime;
@@ -1265,17 +1267,17 @@ public:
 
       // If we get here, we must have been successful adding/updating this
       // visit/place, so update the count:
       mSuccessfulUpdatedCount++;
     }
 
     {
       // Trigger an update for all the hosts of the places we inserted
-      nsAutoCString query("DELETE FROM moz_updatehostsinsert_temp");
+      nsAutoCString query("DELETE FROM moz_updateoriginsinsert_temp");
       nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
       NS_ENSURE_STATE(stmt);
       mozStorageStatementScoper scoper(stmt);
       nsresult rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     nsresult rv = transaction.Commit();
@@ -2060,17 +2062,17 @@ private:
       mozStorageStatementScoper scoper(stmt);
       nsresult rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     {
       // Hosts accumulated during the places delete are updated through a trigger
       // (see nsPlacesTriggers.h).
-      nsAutoCString query("DELETE FROM moz_updatehostsdelete_temp");
+      nsAutoCString query("DELETE FROM moz_updateoriginsdelete_temp");
       nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
       NS_ENSURE_STATE(stmt);
       mozStorageStatementScoper scoper(stmt);
       nsresult rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
@@ -2401,22 +2403,37 @@ History::InsertPlace(VisitData& aPlace, 
   MOZ_ASSERT(!aPlace.shouldUpdateHidden, "We should not need to update hidden");
   MOZ_ASSERT(!NS_IsMainThread(), "must be called off of the main thread!");
 
   nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
       "INSERT INTO moz_places "
         "(url, url_hash, title, rev_host, hidden, typed, frecency, guid) "
       "VALUES (:url, hash(:url), :title, :rev_host, :hidden, :typed, :frecency, :guid) "
     );
+//   nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
+//       "INSERT INTO moz_places "
+//         "(url, url_hash, title, rev_host, origin, hidden, typed, frecency, guid) "
+//       "VALUES (:url, hash(:url), :title, :rev_host, :origin, :hidden, :typed, :frecency, :guid) "
+//     );
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("rev_host"),
                                        aPlace.revHost);
   NS_ENSURE_SUCCESS(rv, rv);
+
+//   //XXXadw can/should origin ever be null?
+//   if (aPlace.origin.IsEmpty()) {
+//     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("origin"));
+//   } else {
+//     rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"),
+//                                     aPlace.origin);
+//   }
+//   NS_ENSURE_SUCCESS(rv, rv);
+
   rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("url"), aPlace.spec);
   NS_ENSURE_SUCCESS(rv, rv);
   nsString title = aPlace.title;
   // Empty strings should have no title, just like nsNavHistory::SetPageTitle.
   if (title.IsEmpty()) {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("title"));
   }
   else {
--- a/toolkit/components/places/History.jsm
+++ b/toolkit/components/places/History.jsm
@@ -764,17 +764,17 @@ var invalidateFrecencies = async functio
 };
 
 // Inner implementation of History.clear().
 var clear = async function(db) {
   await db.executeTransaction(async function() {
     // Remove all non-bookmarked places entries first, this will speed up the
     // triggers work.
     await db.execute(`DELETE FROM moz_places WHERE foreign_count = 0`);
-    await db.execute(`DELETE FROM moz_updatehostsdelete_temp`);
+    await db.execute(`DELETE FROM moz_updateoriginsdelete_temp`);
 
     // Expire orphan icons.
     await db.executeCached(`DELETE FROM moz_pages_w_icons
                             WHERE page_url_hash NOT IN (SELECT url_hash FROM moz_places)`);
     await db.executeCached(`DELETE FROM moz_icons WHERE id IN (
                               SELECT id FROM moz_icons WHERE root = 0
                               EXCEPT
                               SELECT icon_id FROM moz_icons_to_pages
@@ -853,17 +853,17 @@ var cleanupPages = async function(db, pa
   let idsList = sqlList(pagesToRemove.map(p => p.id));
   // Note, we are already in a transaction, since callers create it.
   // Check relations regardless, to avoid creating orphans in case of
   // async race conditions.
   await db.execute(`DELETE FROM moz_places WHERE id IN ( ${ idsList } )
                     AND foreign_count = 0 AND last_visit_date ISNULL`);
   // Hosts accumulated during the places delete are updated through a trigger
   // (see nsPlacesTriggers.h).
-  await db.executeCached(`DELETE FROM moz_updatehostsdelete_temp`);
+  await db.executeCached(`DELETE FROM moz_updateoriginsdelete_temp`);
 
   // Expire orphans.
   let hashesToRemove = pagesToRemove.map(p => p.hash);
   await db.executeCached(`DELETE FROM moz_pages_w_icons
                           WHERE page_url_hash IN (${sqlList(hashesToRemove)})`);
   await db.executeCached(`DELETE FROM moz_icons WHERE id IN (
                             SELECT id FROM moz_icons WHERE root = 0
                             EXCEPT
--- a/toolkit/components/places/PlacesSearchAutocompleteProvider.jsm
+++ b/toolkit/components/places/PlacesSearchAutocompleteProvider.jsm
@@ -228,18 +228,32 @@ this.PlacesSearchAutocompleteProvider = 
    *           iconUrl: Icon associated to the match, or null if not available.
    *         }
    */
   async findMatchByToken(searchToken) {
     await this.ensureInitialized();
 
     // Match at the beginning for now.  In the future, an "options" argument may
     // allow the matching behavior to be tuned.
+//     return SearchAutocompleteProviderInternal.priorityMatches
+//                                              .find(m => m.token.startsWith(searchToken));
+
+//     return SearchAutocompleteProviderInternal.priorityMatches
+//                                              .find(m => {
+//                                                  dump(`+++XXXadw findMatchByToken m.token='${m.token}' searchToken='${searchToken}'\n`);
+//                                                  return m.token.startsWith(searchToken);
+//                                                  });
+
+//     return SearchAutocompleteProviderInternal.priorityMatches
+//                                              .find(m => m.token.startsWith(searchToken)) ||
+//     SearchAutocompleteProviderInternal.priorityMatches
+//                                              .find(m => ("www." + m.token).startsWith(searchToken));
+
     return SearchAutocompleteProviderInternal.priorityMatches
-                                             .find(m => m.token.startsWith(searchToken));
+                                             .find(m => m.token.startsWith(searchToken) || m.token.startsWith("www." + searchToken));
   },
 
   /**
    * Matches a given search string to an item that should be included by
    * components wishing to search using search engine aliases, like
    * autocomple.
    *
    * @param searchToken
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -2249,19 +2249,33 @@ var Keywords = {
           // An entry for the given page could be missing, in such a case we need to
           // create it.  The IGNORE conflict can trigger on `guid`.
           await db.executeTransaction(async function() {
             await db.executeCached(
               `INSERT OR IGNORE INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid)
                VALUES (:url, hash(:url), :rev_host, 0, :frecency,
                        IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
                               GENERATE_GUID()))
-              `, { url: url.href, rev_host: PlacesUtils.getReversedHost(url),
-                   frecency: url.protocol == "place:" ? 0 : -1 });
-            await db.executeCached("DELETE FROM moz_updatehostsinsert_temp");
+              `, {
+              url: url.href,
+              rev_host: PlacesUtils.getReversedHost(url),
+              frecency: url.protocol == "place:" ? 0 : -1,
+            });
+//             await db.executeCached(
+//               `INSERT OR IGNORE INTO moz_places (url, url_hash, rev_host, hidden, frecency, origin, guid)
+//                VALUES (:url, hash(:url), :rev_host, 0, :frecency, :origin,
+//                        IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
+//                               GENERATE_GUID()))
+//               `, {
+//               url: url.href,
+//               rev_host: PlacesUtils.getReversedHost(url),
+//               frecency: url.protocol == "place:" ? 0 : -1,
+//               origin: url.origin,
+//             });
+            await db.executeCached("DELETE FROM moz_updateoriginsinsert_temp");
             await db.executeCached(
               `INSERT INTO moz_keywords (keyword, place_id, post_data)
                VALUES (:keyword, (SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url), :post_data)
               `, { url: url.href, keyword, post_data: postData });
           });
         }
 
         await PlacesSyncUtils.bookmarks.addSyncChangesForBookmarksWithURL(
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -294,19 +294,19 @@ namespace places {
     if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("http://"))) {
       fixedSpec.Rebind(fixedSpec, 7);
     } else if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("https://"))) {
       fixedSpec.Rebind(fixedSpec, 8);
     } else if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("ftp://"))) {
       fixedSpec.Rebind(fixedSpec, 6);
     }
 
-    if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("www."))) {
-      fixedSpec.Rebind(fixedSpec, 4);
-    }
+//     if (StringBeginsWith(fixedSpec, NS_LITERAL_CSTRING("www."))) {
+//       fixedSpec.Rebind(fixedSpec, 4);
+//     }
 
     return fixedSpec;
   }
 
   /* static */
   bool
   MatchAutoCompleteFunction::findAnywhere(const nsDependentCSubstring &aToken,
                                           const nsACString &aSourceString)
@@ -1049,10 +1049,625 @@ namespace places {
     NS_ENSURE_SUCCESS(rv, rv);
     rv = result->SetAsInt64(hash);
     NS_ENSURE_SUCCESS(rv, rv);
 
     result.forget(_result);
     return NS_OK;
   }
 
+////////////////////////////////////////////////////////////////////////////////
+//// Get prefix function
+
+  /* static */
+  nsresult
+  GetPrefixFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<GetPrefixFunction> function = new GetPrefixFunction();
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("get_prefix"), 1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    GetPrefixFunction,
+    mozIStorageFunction
+  )
+
+  NS_IMETHODIMP
+  GetPrefixFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                    nsIVariant **_result)
+  {
+    // Must have non-null function arguments.
+    MOZ_ASSERT(aArguments);
+
+    nsAutoString spec;
+    aArguments->GetString(0, spec);
+
+//     int32_t colonIndex = spec.FindChar(':');
+//     if (colonIndex == kNotFound) {
+//     } else {
+//     }
+
+    RefPtr<nsVariant> result = new nsVariant();
+
+    nsAString::const_iterator iter, end;
+    spec.BeginReading(iter);
+    spec.EndReading(end);
+    if (!FindCharInReadable(':', iter, end)) {
+      result->SetAsVoid();
+    } else {
+      //XXXadw user/pass and port?
+//       if (iter + 1 < end &&
+//           char16_t('/') == *iter &&
+//           char16_t('/') == *(iter + 1)) {
+//         iter += 2;
+//       }
+      iter++;
+      if (iter != end && char16_t('/') == *iter) {
+        nsAString::const_iterator iter2 = iter;
+        iter2++;
+        if (iter2 != end && char16_t('/') == *iter2) {
+          iter2++;
+          iter = iter2;
+        }
+      }
+      nsAString::const_iterator start;
+      spec.BeginReading(start);
+      result->SetAsAString(Substring(start, iter));
+    }
+
+    result.forget(_result);
+    return NS_OK;
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+//// Get host and port function
+
+  /* static */
+  nsresult
+  GetHostAndPortFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<GetHostAndPortFunction> function = new GetHostAndPortFunction();
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("get_host_and_port"), 1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    GetHostAndPortFunction,
+    mozIStorageFunction
+  )
+
+#if 0
+  NS_IMETHODIMP
+  GetHostAndPortFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                         nsIVariant **_result)
+  {
+    // Must have non-null function arguments.
+    MOZ_ASSERT(aArguments);
+
+    nsAutoString src;
+    aArguments->GetString(0, src);
+
+    RefPtr<nsVariant> result = new nsVariant();
+
+    if (StringBeginsWith(src, NS_LITERAL_STRING("http://")))
+      src.Cut(0, 7);
+    else if (StringBeginsWith(src, NS_LITERAL_STRING("https://")))
+      src.Cut(0, 8);
+    else if (StringBeginsWith(src, NS_LITERAL_STRING("ftp://")))
+      src.Cut(0, 6);
+
+    result->SetAsAString(src);
+    result.forget(_result);
+    return NS_OK;
+  }
+#endif
+
+  NS_IMETHODIMP
+  GetHostAndPortFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                         nsIVariant **_result)
+  {
+    // Must have non-null function arguments.
+    MOZ_ASSERT(aArguments);
+
+    nsAutoString spec;
+    aArguments->GetString(0, spec);
+
+//     int32_t colonIndex = spec.FindChar(':');
+//     if (colonIndex == kNotFound) {
+//     } else {
+//     }
+
+    RefPtr<nsVariant> result = new nsVariant();
+
+    nsAString::const_iterator iter, end;
+    spec.BeginReading(iter);
+    spec.EndReading(end);
+    if (!FindCharInReadable(':', iter, end)) {
+      result->SetAsAString(spec);
+    } else {
+      iter++;
+      if (iter != end && char16_t('/') == *iter) {
+        nsAString::const_iterator iter2 = iter;
+        iter2++;
+        if (iter2 != end && char16_t('/') == *iter2) {
+          iter2++;
+          iter = iter2;
+        }
+      }
+      nsAString::const_iterator start = iter;
+      Unused << FindCharInReadable('/', iter, end);
+      result->SetAsAString(Substring(start, iter));
+    }
+
+    result.forget(_result);
+    return NS_OK;
+  }
+
+
+//XXXadw
+////////////////////////////////////////////////////////////////////////////////
+//// Strip prefix function
+
+  /* static */
+  nsresult
+  StripPrefixFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<StripPrefixFunction> function = new StripPrefixFunction();
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("strip_prefix"), 1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    StripPrefixFunction,
+    mozIStorageFunction
+  )
+
+  NS_IMETHODIMP
+  StripPrefixFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                      nsIVariant **_result)
+  {
+    // Must have non-null function arguments.
+    MOZ_ASSERT(aArguments);
+
+    nsAutoString spec;
+    aArguments->GetString(0, spec);
+
+    RefPtr<nsVariant> result = new nsVariant();
+
+    nsAString::const_iterator iter, end;
+    spec.BeginReading(iter);
+    spec.EndReading(end);
+    if (!FindCharInReadable(':', iter, end)) {
+      result->SetAsAString(spec);
+    } else {
+      iter++;
+      if (iter != end && char16_t('/') == *iter) {
+        nsAString::const_iterator iter2 = iter;
+        iter2++;
+        if (iter2 != end && char16_t('/') == *iter2) {
+          iter2++;
+          iter = iter2;
+        }
+      }
+      result->SetAsAString(Substring(iter, end));
+    }
+
+    result.forget(_result);
+    return NS_OK;
+  }
+
+
+//XXXadw
+////////////////////////////////////////////////////////////////////////////////
+//// Update frecency stats function
+
+  /* static */
+  nsresult
+  UpdateFrecencyStatsFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<UpdateFrecencyStatsFunction> function =
+      new UpdateFrecencyStatsFunction();
+    nsresult rv = aDBConn->CreateFunction(
+//       NS_LITERAL_CSTRING("update_frecency_stats"), 2, function
+      NS_LITERAL_CSTRING("update_frecency_stats"), 3, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    UpdateFrecencyStatsFunction,
+    mozIStorageFunction
+  )
+
+  NS_IMETHODIMP
+  UpdateFrecencyStatsFunction::OnFunctionCall(mozIStorageValueArray *aArgs,
+                                              nsIVariant **_result)
+  {
+    uint32_t numArgs;
+    nsresult rv = aArgs->GetNumEntries(&numArgs);
+    NS_ENSURE_SUCCESS(rv, rv);
+//     MOZ_ASSERT(numArgs == 2);
+    MOZ_ASSERT(numArgs == 3);
+
+    int32_t oldFrecency = aArgs->AsInt32(0);
+    int32_t newFrecency = aArgs->AsInt32(1);
+    int64_t placeID = aArgs->AsInt64(2);
+
+    nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
+    NS_ENSURE_STATE(navHistory);
+    navHistory->UpdateFrecencyStats(oldFrecency, newFrecency, placeID);
+
+//     nsNavHistory::UpdateFrecencyStats(oldFrecency, newFrecency, placeID);
+
+    RefPtr<nsVariant> result = new nsVariant();
+    rv = result->SetAsVoid();
+    NS_ENSURE_SUCCESS(rv, rv);
+    result.forget(_result);
+    return NS_OK;
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+//// Is frecency decaying function
+
+  /* static */
+  nsresult
+  IsFrecencyDecayingFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<IsFrecencyDecayingFunction> function =
+      new IsFrecencyDecayingFunction();
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("is_frecency_decaying"), 0, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    IsFrecencyDecayingFunction,
+    mozIStorageFunction
+  )
+
+  NS_IMETHODIMP
+  IsFrecencyDecayingFunction::OnFunctionCall(mozIStorageValueArray *aArgs,
+                                             nsIVariant **_result)
+  {
+    uint32_t numArgs;
+    nsresult rv = aArgs->GetNumEntries(&numArgs);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(numArgs == 0);
+
+    nsNavHistory *navHistory = nsNavHistory::GetHistoryService();
+    NS_ENSURE_STATE(navHistory);
+
+    RefPtr<nsVariant> result = new nsVariant();
+    rv = result->SetAsBool(navHistory->IsFrecencyDecaying());
+    NS_ENSURE_SUCCESS(rv, rv);
+    result.forget(_result);
+    return NS_OK;
+  }
+
+
+#if 0
+//XXXadw
+////////////////////////////////////////////////////////////////////////////////
+//// Update frecency stats function
+
+  /* static */
+  nsresult
+  UpdateFrecencyStatsFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<UpdateFrecencyStatsFunction> function =
+      new UpdateFrecencyStatsFunction();
+    nsresult rv = aDBConn->CreateAggregateFunction(
+      NS_LITERAL_CSTRING("update_frecency_stats"), 1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    UpdateFrecencyStatsFunction,
+    mozIStorageAggregateFunction
+  )
+
+  NS_IMETHODIMP
+  UpdateFrecencyStatsFunction::OnStep(mozIStorageValueArray *aArgs)
+  {
+    uint32_t numArgs;
+    nsresult rv = aArgs->GetNumEntries(&numArgs);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(numArgs == 1);
+
+    int32_t frecency = aArgs->AsInt32(0);
+
+    return NS_OK;
+  }
+
+  NS_IMETHODIMP
+  UpdateFrecencyStatsFunction::OnFinal(nsIVariant **_result)
+  {
+    const nsNavHistory* navHistory = nsNavHistory::GetConstHistoryService();
+    NS_ENSURE_STATE(navHistory);
+    navHistory->UpdateFrecencyStats();
+
+    RefPtr<nsVariant> result = new nsVariant();
+    Unused << result->SetAsVoid();
+    result.forget(_result);
+    return NS_OK;
+  }
+#endif
+
+
+
+#if 0
+////////////////////////////////////////////////////////////////////////////////
+//// XXXadw
+
+  /* static */
+  nsresult
+  CalculateFrecencyFunction::create(mozIStorageConnection *aDBConn)
+  {
+    RefPtr<CalculateFrecencyFunction> function =
+      new CalculateFrecencyFunction();
+
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("calculate_frecency"), -1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_ISUPPORTS(
+    CalculateFrecencyFunction,
+    mozIStorageFunction
+  )
+
+  NS_IMETHODIMP
+  CalculateFrecencyFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                            nsIVariant **_result)
+  {
+    uint32_t numEntries;
+    nsresult rv = aArguments->GetNumEntries(&numEntries);
+    NS_ENSURE_SUCCESS(rv, rv);
+    MOZ_ASSERT(numEntries == 3, "unexpected number of arguments");
+
+    nsAutoString prefix;
+    aArguments->GetString(0, prefix);
+    nsAutoString host;
+    aArguments->GetString(1, host);
+    int64_t placeID = aArguments->AsInt64(2);
+    MOZ_ASSERT(placeID > 0, "Should always pass a valid place ID");
+
+    int64_t prefixID;
+    int64_t hostID;
+
+    RefPtr<Database> DB = Database::GetDatabase();
+    NS_ENSURE_STATE(DB);
+
+    {
+      RefPtr<mozIStorageStatement> stmt = DB->GetStatement(
+        "SELECT "
+          "(SELECT id FROM moz_prefixes WHERE prefix = :prefix) AS prefix_id, "
+          "(SELECT id FROM moz_hosts WHERE host = :host) AS host_id "
+      );
+      NS_ENSURE_STATE(stmt);
+      mozStorageStatementScoper stmtScoper(stmt);
+
+      rv = stmt->BindStringByName(NS_LITERAL_CSTRING("prefix"), prefix);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = stmt->BindStringByName(NS_LITERAL_CSTRING("host"), host);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      bool hasResult = false;
+      rv = stmt->ExecuteStep(&hasResult);
+      NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_UNEXPECTED);
+
+      rv = stmt->GetInt64(0, &prefixID);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = stmt->GetInt64(1, &hostID);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    {
+      RefPtr<mozIStorageStatement> stmt = DB->GetStatement(
+        "INSERT OR REPLACE INTO moz_origins (prefix_id, host_id, frecency) "
+        "VALUES (:prefix_id, :host_id, 0) "
+      );
+      NS_ENSURE_STATE(stmt);
+      mozStorageStatementScoper stmtScoper(stmt);
+
+      rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("prefix_id"), prefixID);
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("host_id"), hostID);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      bool hasResult = false;
+      rv = stmt->ExecuteStep(&hasResult);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    {
+      RefPtr<mozIStorageStatement> stmt = DB->GetStatement(
+        "UPDATE moz_places SET origin_id = last_insert_rowid() "
+        "WHERE id = :place_id; "
+      );
+      NS_ENSURE_STATE(stmt);
+      mozStorageStatementScoper stmtScoper(stmt);
+
+      rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("place_id"), placeID);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      bool hasResult = false;
+      rv = stmt->ExecuteStep(&hasResult);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    {
+      RefPtr<mozIStorageStatement> stmt = DB->GetStatement(
+        "UPDATE moz_origins SET frecency = ( "
+          "SELECT MAX(frecency) FROM moz_places "
+          "WHERE origin_id = moz_origins.id "
+        ") "
+        "WHERE id = last_insert_rowid(); "
+      );
+      NS_ENSURE_STATE(stmt);
+      mozStorageStatementScoper stmtScoper(stmt);
+
+      bool hasResult = false;
+      rv = stmt->ExecuteStep(&hasResult);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+
+
+
+
+    if (visitCount > 0) {
+      // Get a sample of the last visits to the page, to calculate its weight.
+      // In case of a temporary or permanent redirect, calculate the frecency
+      // as if the original page was visited.
+      nsCString redirectsTransitionFragment =
+        nsPrintfCString("%d AND %d ", nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                                      nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY);
+      nsCOMPtr<mozIStorageStatement> getVisits = DB->GetStatement(
+        NS_LITERAL_CSTRING(
+          "/* do not warn (bug 659740 - SQLite may ignore index if few visits exist) */"
+          "SELECT "
+            "ROUND((strftime('%s','now','localtime','utc') - v.visit_date/1000000)/86400), "
+            "origin.visit_type, "
+            "v.visit_type, "
+            "target.id NOTNULL "
+          "FROM moz_historyvisits v "
+          "LEFT JOIN moz_historyvisits origin ON origin.id = v.from_visit "
+                                            "AND v.visit_type BETWEEN "
+            ) + redirectsTransitionFragment + NS_LITERAL_CSTRING(
+          "LEFT JOIN moz_historyvisits target ON v.id = target.from_visit "
+                                            "AND target.visit_type BETWEEN "
+            ) + redirectsTransitionFragment + NS_LITERAL_CSTRING(
+          "WHERE v.place_id = :page_id "
+          "ORDER BY v.visit_date DESC "
+        )
+      );
+      NS_ENSURE_STATE(getVisits);
+      mozStorageStatementScoper visitsScoper(getVisits);
+      rv = getVisits->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      // Fetch only a limited number of recent visits.
+      bool hasResult = false;
+      for (int32_t maxVisits = history->GetNumVisitsForFrecency();
+           numSampledVisits < maxVisits &&
+           NS_SUCCEEDED(getVisits->ExecuteStep(&hasResult)) && hasResult;
+           numSampledVisits++) {
+
+        int32_t visitType;
+        bool isNull = false;
+        rv = getVisits->GetIsNull(1, &isNull);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        if (isRedirect == eIsRedirect || isNull) {
+          // Use the main visit_type.
+          rv = getVisits->GetInt32(2, &visitType);
+          NS_ENSURE_SUCCESS(rv, rv);
+        } else {
+          // This is a redirect target, so use the origin visit_type.
+          rv = getVisits->GetInt32(1, &visitType);
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+
+        RedirectState visitIsRedirect = isRedirect;
+
+        // If we don't know if this is a redirect or not, or this is not the
+        // most recent visit that we're looking at, then we use the redirect
+        // value from the database.
+        if (visitIsRedirect == eRedirectUnknown || numSampledVisits >= 1) {
+          int32_t redirect;
+          rv = getVisits->GetInt32(3, &redirect);
+          NS_ENSURE_SUCCESS(rv, rv);
+          visitIsRedirect = !!redirect ? eIsRedirect : eIsNotRedirect;
+        }
+
+        bonus = history->GetFrecencyTransitionBonus(visitType, true, visitIsRedirect == eIsRedirect);
+
+        // Add the bookmark visit bonus.
+        if (hasBookmark) {
+          bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_BOOKMARK, true);
+        }
+
+        // If bonus was zero, we can skip the work to determine the weight.
+        if (bonus) {
+          int32_t ageInDays = getVisits->AsInt32(0);
+          int32_t weight = history->GetFrecencyAgedWeight(ageInDays);
+          pointsForSampledVisits += (float)(weight * (bonus / 100.0));
+        }
+      }
+    }
+
+    // If we sampled some visits for this page, use the calculated weight.
+    if (numSampledVisits) {
+      // We were unable to calculate points, maybe cause all the visits in the
+      // sample had a zero bonus. Though, we know the page has some past valid
+      // visit, or visit_count would be zero. Thus we set the frecency to
+      // -1, so they are still shown in autocomplete.
+      if (!pointsForSampledVisits) {
+        NS_ADDREF(*_result = new IntegerVariant(-1));
+      }
+      else {
+        // Estimate frecency using the sampled visits.
+        // Use ceilf() so that we don't round down to 0, which
+        // would cause us to completely ignore the place during autocomplete.
+        NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(visitCount * ceilf(pointsForSampledVisits) / numSampledVisits)));
+      }
+      return NS_OK;
+    }
+
+    // Otherwise this page has no visits, it may be bookmarked.
+    if (!hasBookmark || isQuery) {
+      NS_ADDREF(*_result = new IntegerVariant(0));
+      return NS_OK;
+    }
+
+    // For unvisited bookmarks, produce a non-zero frecency, so that they show
+    // up in URL bar autocomplete.
+    visitCount = 1;
+
+    // Make it so something bookmarked and typed will have a higher frecency
+    // than something just typed or just bookmarked.
+    bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_BOOKMARK, false);
+    if (typed) {
+      bonus += history->GetFrecencyTransitionBonus(nsINavHistoryService::TRANSITION_TYPED, false);
+    }
+
+    // Assume "now" as our ageInDays, so use the first bucket.
+    pointsForSampledVisits = history->GetFrecencyBucketWeight(1) * (bonus / (float)100.0);
+
+    // use ceilf() so that we don't round down to 0, which
+    // would cause us to completely ignore the place during autocomplete
+    NS_ADDREF(*_result = new IntegerVariant((int32_t) ceilf(visitCount * ceilf(pointsForSampledVisits))));
+
+    return NS_OK;
+  }
+#endif
+
+
+
 } // namespace places
 } // namespace mozilla
--- a/toolkit/components/places/SQLFunctions.h
+++ b/toolkit/components/places/SQLFunctions.h
@@ -297,16 +297,17 @@ private:
  * Make a given URL more suitable for searches, by removing common prefixes
  * such as "www."
  *
  * @param url
  *        A URL.
  * @return
  *        The same URL, with redundant parts removed.
  */
+//XXXadw still used?
 class FixupURLFunction final : public mozIStorageFunction
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZISTORAGEFUNCTION
 
   /**
    * Registers the function with the specified database connection.
@@ -411,12 +412,144 @@ public:
    * @param aDBConn
    *        The database connection to register with.
    */
   static nsresult create(mozIStorageConnection *aDBConn);
 private:
   ~HashFunction() {}
 };
 
+
+////////////////////////////////////////////////////////////////////////////////
+//// Get prefix function
+
+/**
+ * XXXadw
+ *
+ * @param url
+ *        A URL.
+ * @return
+ *        The same URL, with redundant parts removed.
+ */
+class GetPrefixFunction final : public mozIStorageFunction
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+private:
+  ~GetPrefixFunction() {}
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//// Get host and port function
+
+/**
+ * XXXadw
+ *
+ * @param url
+ *        A URL.
+ * @return
+ *        The same URL, with redundant parts removed.
+ */
+class GetHostAndPortFunction final : public mozIStorageFunction
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+private:
+  ~GetHostAndPortFunction() {}
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//// Strip prefix function
+
+/**
+ * XXXadw
+ *
+ * @param url
+ *        A URL.
+ * @return
+ *        The same URL, with redundant parts removed.
+ */
+class StripPrefixFunction final : public mozIStorageFunction
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+private:
+  ~StripPrefixFunction() {}
+};
+
+
+
+//XXXadw
+////////////////////////////////////////////////////////////////////////////////
+//// Update frecency stats function
+
+class UpdateFrecencyStatsFunction final : public mozIStorageFunction
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+private:
+  ~UpdateFrecencyStatsFunction() {}
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+//// Is frecency decaying function
+
+class IsFrecencyDecayingFunction final : public mozIStorageFunction
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+private:
+  ~IsFrecencyDecayingFunction() {}
+};
+
+
 } // namespace places
 } // namespace mozilla
 
 #endif // mozilla_places_SQLFunctions_h_
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -29,17 +29,16 @@ const INSERTMETHOD = {
   MERGE: 2 // Always merge previous and current results
 };
 
 // Prefs are defined as [pref name, default value].
 const PREF_URLBAR_BRANCH = "browser.urlbar.";
 const PREF_URLBAR_DEFAULTS = new Map([
   ["autocomplete.enabled", true],
   ["autoFill", true],
-  ["autoFill.typed", true],
   ["autoFill.searchEngines", false],
   ["restyleSearches", false],
   ["delay", 50],
   ["matchBehavior", MATCH_BOUNDARY_ANYWHERE],
   ["filter.javascript", true],
   ["maxRichResults", 10],
   ["suggest.history", true],
   ["suggest.bookmark", true],
@@ -56,17 +55,17 @@ const PREF_URLBAR_DEFAULTS = new Map([
 ]);
 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_HOST       = 1;
+const QUERYTYPE_AUTOFILL_ORIGIN     = 1;
 const QUERYTYPE_AUTOFILL_URL        = 2;
 
 // This separator is used as an RTL-friendly way to split the title and tags.
 // It can also be used by an nsIAutoCompleteResult consumer to re-split the
 // "comment" back into the title and the tag.
 const TITLE_TAGS_SEPARATOR = " \u2013 ";
 
 // Telemetry probes.
@@ -238,79 +237,121 @@ const SQL_ADAPTIVE_QUERY =
          AND t.userContextId = :userContextId
    WHERE AUTOCOMPLETE_MATCH(NULL, h.url,
                             IFNULL(btitle, h.title), tags,
                             h.visit_count, h.typed, bookmarked,
                             t.open_count,
                             :matchBehavior, :searchBehavior)
    ORDER BY rank DESC, h.frecency DESC`;
 
+// Result row indexes for originQuery()
+const QUERYINDEX_ORIGIN_AUTOFILLED_VALUE = 1;
+const QUERYINDEX_ORIGIN_URL = 2;
+const QUERYINDEX_ORIGIN_FRECENCY = 3;
 
-function hostQuery(conditions = "") {
-  let query =
-    `/* do not warn (bug NA): not worth to index on (typed, frecency) */
-     SELECT :query_type, host || '/', IFNULL(prefix, 'http://') || host || '/',
-            NULL, NULL, NULL, NULL, NULL, NULL, NULL, frecency
-     FROM moz_hosts
-     WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
-     AND frecency <> 0
-     ${conditions}
-     ORDER BY frecency DESC
-     LIMIT 1`;
-  return query;
+function originQuery(conditions = "", bookmarkedFragment = "NULL") {
+  return `SELECT :query_type,
+                 host || '/',
+                 prefix || host || '/',
+                 frecency,
+                 ${bookmarkedFragment} AS bookmarked,
+                 origin_id
+          FROM moz_autofill_origins
+          WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
+                AND frecency <> 0
+                ${conditions}
+          UNION
+          SELECT :query_type,
+                 fixup_url(host) || '/',
+                 prefix || host || '/',
+                 frecency,
+                 ${bookmarkedFragment} AS bookmarked,
+                 origin_id
+          FROM moz_autofill_origins
+          WHERE host BETWEEN 'www.' || :searchString AND 'www.' || :searchString || X'FFFF'
+                AND frecency <> 0
+                ${conditions}
+          ORDER BY frecency DESC, origin_id DESC
+          LIMIT 1 `;
 }
 
-const SQL_HOST_QUERY = hostQuery();
+const SQL_ORIGIN_QUERY = originQuery();
+
+const SQL_ORIGIN_PREFIX_QUERY = originQuery(
+  `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`
+);
+
+const SQL_ORIGIN_BOOKMARKED_QUERY = originQuery(
+  `AND bookmarked`,
+  `(SELECT foreign_count > 0 FROM moz_places
+    WHERE moz_places.origin_id = moz_autofill_origins.origin_id)`
+);
 
-const SQL_TYPED_HOST_QUERY = hostQuery("AND typed = 1");
+const SQL_ORIGIN_PREFIX_BOOKMARKED_QUERY = originQuery(
+  `AND bookmarked
+   AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
+  `(SELECT foreign_count > 0 FROM moz_places
+    WHERE moz_places.origin_id = moz_autofill_origins.origin_id)`
+);
+
+// Result row indexes for urlQuery()
+const QUERYINDEX_URL_URL = 1;
+const QUERYINDEX_URL_STRIPPED_URL = 2;
+const QUERYINDEX_URL_FRECENCY = 3;
 
-function bookmarkedHostQuery(conditions = "") {
-  let query =
-    `/* do not warn (bug NA): not worth to index on (typed, frecency) */
-     SELECT :query_type, host || '/', IFNULL(prefix, 'http://') || host || '/',
-            ( SELECT foreign_count > 0 FROM moz_places
-              WHERE rev_host = get_unreversed_host(host || '.') || '.'
-                 OR rev_host = get_unreversed_host(host || '.') || '.www.'
-            ) AS bookmarked, NULL, NULL, NULL, NULL, NULL, NULL, frecency
-     FROM moz_hosts
-     WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
-     AND bookmarked
-     AND frecency <> 0
-     ${conditions}
-     ORDER BY frecency DESC
-     LIMIT 1`;
-  return query;
+function urlQuery(conditions1, conditions2) {
+  return `/* do not warn (bug no): cannot use an index to sort */
+          SELECT :query_type,
+                 url,
+                 :strippedURL,
+                 frecency,
+                 foreign_count > 0 AS bookmarked,
+                 id
+          FROM moz_places
+          WHERE rev_host = :revHost
+                AND frecency <> 0
+                ${conditions1}
+          UNION
+          SELECT :query_type,
+                 url,
+                 :strippedURL,
+                 frecency,
+                 foreign_count > 0 AS bookmarked,
+                 id
+          FROM moz_places
+          WHERE rev_host = :revHost || 'www.'
+                AND frecency <> 0
+                ${conditions2}
+          ORDER BY frecency DESC, id DESC
+          LIMIT 1 `;
 }
 
-const SQL_BOOKMARKED_HOST_QUERY = bookmarkedHostQuery();
+const SQL_URL_QUERY = urlQuery(
+  `AND strip_prefix(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
+  `AND strip_prefix(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
+);
 
-const SQL_BOOKMARKED_TYPED_HOST_QUERY = bookmarkedHostQuery("AND typed = 1");
+const SQL_URL_PREFIX_QUERY = urlQuery(
+  `AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
+  `AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
+);
 
-function urlQuery(conditions = "") {
-  return `/* do not warn (bug no): cannot use an index to sort */
-          SELECT :query_type, h.url, NULL,
-            foreign_count > 0 AS bookmarked,
-            NULL, NULL, NULL, NULL, NULL, NULL, h.frecency
-          FROM moz_places h
-          WHERE (rev_host = :revHost OR rev_host = :revHost || "www.")
-          AND h.frecency <> 0
-          AND fixup_url(h.url) BETWEEN :searchString AND :searchString || X'FFFF'
-          ${conditions}
-          ORDER BY h.frecency DESC, h.id DESC
-          LIMIT 1`;
-}
+const SQL_URL_BOOKMARKED_QUERY = urlQuery(
+  `AND bookmarked
+   AND strip_prefix(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
+  `AND bookmarked
+   AND strip_prefix(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
+);
 
-const SQL_URL_QUERY = urlQuery();
-
-const SQL_TYPED_URL_QUERY = urlQuery("AND h.typed = 1");
-
-// TODO (bug 1045924): use foreign_count once available.
-const SQL_BOOKMARKED_URL_QUERY = urlQuery("AND bookmarked");
-
-const SQL_BOOKMARKED_TYPED_URL_QUERY = urlQuery("AND bookmarked AND h.typed = 1");
+const SQL_URL_PREFIX_BOOKMARKED_QUERY = urlQuery(
+  `AND bookmarked
+   AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
+  `AND bookmarked
+   AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
+);
 
 // Getters
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 Cu.importGlobalProperties(["fetch"]);
 
@@ -670,39 +711,102 @@ XPCOMUtils.defineLazyGetter(this, "Profi
  *       empty string.  We don't want that, as it'll break our logic, so return
  *       an empty array then.
  */
 function getUnfilteredSearchTokens(searchString) {
   return searchString.length ? searchString.split(REGEXP_SPACES) : [];
 }
 
 /**
- * Strip prefixes from the URI that we don't care about for searching.
+ * Strips the "prefix" -- the scheme and its slashes, if any -- from a URL and
+ * returns the prefix and the remainder of the URL.  If the given string is not
+ * actually a URL, then an empty prefix and the string itself is returned.
  *
- * @param spec
- *        The text to modify.
- * @return the modified spec.
+ * @param  str
+ *         The potential URL to strip.
+ * @return If `str` is a URL, then [prefix, remainder].  Otherwise, ["", str].
  */
-function stripPrefix(spec) {
+function stripPrefix(str) {
+  let match = /^[a-zA-Z]+:(?:\/\/)?/.exec(str);
+  if (!match) {
+    return ["", str];
+  }
+  let prefix = match[0];
+  if (prefix.length < str.length && str[prefix.length] == " ") {
+    return ["", str];
+  }
+  return [prefix, str.substr(prefix.length)];
+}
+
+// function stripPrefix(str) {
+//   let match = /^[a-zA-Z]+:(?:\/\/)?/.exec(str);
+// //   let match = /^[a-zA-Z]+:(?:\/\/(?:www\.)?)?/.exec(str);
+//   if (!match) {
+
+
+//     if (str.startsWith("www.")) {
+//       str = str.substr(4);
+//     }
+
+//     return ["", str];
+//   }
+//   let prefix = match[0];
+//   if (prefix.length < str.length && str[prefix.length] == " ") {
+
+//     if (str.startsWith("www.")) {
+//       str = str.substr(4);
+//     }
+
+//     return ["", str];
+//   }
+// //   return [prefix, str.substr(prefix.length)];
+
+//     str = str.substr(prefix.length);
+//     if (str.startsWith("www.")) {
+//       str = str.substr(4);
+//     }
+
+//     return [prefix, str];
+// }
+
+// function stripPrefix(spec) {
+//   ["http://", "https://", "ftp://"].some(scheme => {
+//     // Strip protocol if not directly followed by a space
+//     if (spec.startsWith(scheme) && spec[scheme.length] != " ") {
+//       spec = spec.slice(scheme.length);
+//       return true;
+//     }
+//     return false;
+//   });
+
+//   // Strip www. if not directly followed by a space
+//   if (spec.startsWith("www.") && spec[4] != " ") {
+//     spec = spec.slice(4);
+//   }
+//   return spec;
+// }
+
+function stripPrefix_originalXXXadw(spec) {
   ["http://", "https://", "ftp://"].some(scheme => {
     // Strip protocol if not directly followed by a space
     if (spec.startsWith(scheme) && spec[scheme.length] != " ") {
       spec = spec.slice(scheme.length);
       return true;
     }
     return false;
   });
-
   // Strip www. if not directly followed by a space
   if (spec.startsWith("www.") && spec[4] != " ") {
     spec = spec.slice(4);
   }
   return spec;
 }
 
+
+
 /**
  * Strip http and trailing separators from a spec.
  *
  * @param spec
  *        The text to modify.
  * @param trimSlash
  *        Whether to trim the trailing slash.
  * @return the modified spec.
@@ -802,26 +906,23 @@ function looksLikeUrl(str, ignoreAlphanu
  * @param [optional] previousResult
  *        The result object from the previous search. if available.
  */
 function Search(searchString, searchParam, autocompleteListener,
                 autocompleteSearch, prohibitSearchSuggestions, previousResult) {
   // We want to store the original string for case sensitive searches.
   this._originalSearchString = searchString;
   this._trimmedOriginalSearchString = searchString.trim();
-  let strippedOriginalSearchString =
-    stripPrefix(this._trimmedOriginalSearchString.toLowerCase());
-  this._searchString =
-    textURIService.unEscapeURIForUI("UTF-8", strippedOriginalSearchString);
 
-  // The protocol and the host are lowercased by nsIURI, so it's fine to
-  // lowercase the typed prefix, to add it back to the results later.
-  this._strippedPrefix = this._trimmedOriginalSearchString.slice(
-    0, this._trimmedOriginalSearchString.length - strippedOriginalSearchString.length
-  ).toLowerCase();
+  let [prefix, suffix] = stripPrefix(this._trimmedOriginalSearchString);
+  this._searchString = textURIService.unEscapeURIForUI("UTF-8", suffix);
+//   this._searchString = suffix;
+  this._strippedPrefix = prefix.toLowerCase();
+
+  dump(`+++XXXadw Search ctor suffix='${suffix}' this._searchString='${this._searchString}' this._strippedPrefix='${this._strippedPrefix}'\n`);
 
   this._matchBehavior = Prefs.get("matchBehavior");
   // Set the default behavior for this search.
   this._behavior = this._searchString ? Prefs.get("defaultBehavior")
                                       : Prefs.get("emptySearchDefaultBehavior");
 
   let params = new Set(searchParam.split(" "));
   this._enableActions = params.has("enable-actions");
@@ -832,16 +933,24 @@ function Search(searchString, searchPara
   let userContextId = searchParam.match(REGEXP_USER_CONTEXT_ID);
   this._userContextId = userContextId ?
                           parseInt(userContextId[1], 10) :
                           Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
 
   this._searchTokens =
     this.filterTokens(getUnfilteredSearchTokens(this._searchString));
 
+//   let strippedOriginalSearchString =
+//     stripPrefix_originalXXXadw(this._trimmedOriginalSearchString.toLowerCase());
+//   let searchStringXXXadw =
+//     textURIService.unEscapeURIForUI("UTF-8", strippedOriginalSearchString);
+//   this._searchTokens =
+//     this.filterTokens(getUnfilteredSearchTokens(searchStringXXXadw));
+
+
   this._prohibitSearchSuggestions = prohibitSearchSuggestions;
 
   this._listener = autocompleteListener;
   this._autocompleteSearch = autocompleteSearch;
 
   // Create a new result to add eventual matches.  Note we need a result
   // regardless having matches.
   let result = previousResult ||
@@ -883,24 +992,16 @@ function Search(searchString, searchPara
 
   // These are used to avoid adding duplicate entries to the results.
   this._usedURLs = new Set();
   this._usedPlaceIds = new Set();
 
   // Counters for the number of matches per MATCHTYPE.
   this._counts = Object.values(MATCHTYPE)
                        .reduce((o, p) => { o[p] = 0; return o; }, {});
-
-  this._searchStringHasWWW = this._strippedPrefix.endsWith("www.");
-  this._searchStringWWW = this._searchStringHasWWW ? "www." : "";
-  this._searchStringFromWWW = this._searchStringWWW + this._searchString;
-
-  this._searchStringSchemeFound = this._strippedPrefix.match(/^(\w+):/i);
-  this._searchStringScheme = this._searchStringSchemeFound ?
-                             this._searchStringSchemeFound[1].toLowerCase() : "";
 }
 
 Search.prototype = {
   /**
    * Enables the desired AutoComplete behavior.
    *
    * @param type
    *        The behavior type to set.
@@ -1024,16 +1125,18 @@ Search.prototype = {
   pending: true,
 
   /**
    * Execute the search and populate results.
    * @param conn
    *        The Sqlite connection.
    */
   async execute(conn) {
+    dump(`+++XXXadw UnifiedComplete execute\n`);
+
     // A search might be canceled before it starts.
     if (!this.pending)
       return;
 
     // Used by stop() to interrupt an eventual running statement.
     this.interrupt = () => {
       // Interrupt any ongoing statement to run the search sooner.
       if (!SwitchToTabStorage.updating) {
@@ -1048,17 +1151,17 @@ Search.prototype = {
     // wait for the initialization of PlacesSearchAutocompleteProvider first.
     await PlacesSearchAutocompleteProvider.ensureInitialized();
     if (!this.pending)
       return;
 
     // For any given search, we run many queries/heuristics:
     // 1) by alias (as defined in SearchService)
     // 2) inline completion from search engine resultDomains
-    // 3) inline completion for hosts (this._hostQuery) or urls (this._urlQuery)
+    // 3) inline completion for origins (this._originQuery) or urls (this._urlQuery)
     // 4) directly typed in url (ie, can be navigated to as-is)
     // 5) submission for the current search engine
     // 6) Places keywords
     // 7) adaptive learning (this._adaptiveQuery)
     // 8) open pages not supported by history (this._switchToTabQuery)
     // 9) query based on match behavior
     //
     // (6) only gets ran if we get any filtered tokens, since if there are no
@@ -1142,16 +1245,17 @@ Search.prototype = {
       }
     }
     // In any case, clear previous suggestions.
     searchSuggestionsCompletePromise.then(() => {
       this._cleanUpNonCurrentMatches(MATCHTYPE.SUGGESTION);
     });
 
     for (let [query, params] of queries) {
+      dump(`+++XXXadw execute A params=${JSON.stringify(params)}\n`);
       await conn.executeCached(query, params, this._onResultRow.bind(this));
       if (!this.pending)
         return;
     }
 
     if (this._enableActions && this.hasBehavior("openpage")) {
       await this._matchRemoteTabs();
       if (!this.pending)
@@ -1163,19 +1267,21 @@ Search.prototype = {
     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[MATCHTYPE.GENERAL] + this._counts[MATCHTYPE.HEURISTIC];
     if (this._matchBehavior == MATCH_BOUNDARY_ANYWHERE &&
         count < Prefs.get("maxRichResults")) {
+      dump(`+++XXXadw execute B\n`);
       this._matchBehavior = MATCH_ANYWHERE;
       for (let [query, params] of [ this._adaptiveQuery,
                                     this._searchQuery ]) {
+        dump(`+++XXXadw execute C params=${JSON.stringify(params)}\n`);
         await conn.executeCached(query, params, this._onResultRow.bind(this));
         if (!this.pending)
           return;
       }
     }
 
     this._matchPreloadedSites();
 
@@ -1189,120 +1295,69 @@ Search.prototype = {
       return;
     let profileCreationDate = await ProfileAgeCreatedPromise;
     let daysSinceProfileCreation = (Date.now() - profileCreationDate) / MS_PER_DAY;
     if (daysSinceProfileCreation > Prefs.get("usepreloadedtopurls.expire_days"))
       Services.prefs.setBoolPref("browser.urlbar.usepreloadedtopurls.enabled", false);
   },
 
   _matchPreloadedSites() {
-    if (!Prefs.get("usepreloadedtopurls.enabled"))
+    if (!Prefs.get("usepreloadedtopurls.enabled")) {
       return;
-
-    // In case user typed just "https://" or "www." or "https://www."
-    // - we do not put out the whole lot of sites
-    if (!this._searchString)
-      return;
+    }
 
-    if (!(this._searchStringScheme === "" ||
-          this._searchStringScheme === "https" ||
-          this._searchStringScheme === "http"))
+    if (!this._searchString) {
+      // The user hasn't typed anything, or they've only typed a scheme.
       return;
-
-    let strictMatches = [];
-    let looseMatches = [];
+    }
 
     for (let site of PreloadedSiteStorage.sites) {
-      if (this._searchStringScheme && this._searchStringScheme !== site.uri.scheme)
-        continue;
-      let match = {
-        value: site.uri.spec,
-        comment: site.title,
-        style: "preloaded-top-site",
-        frecency: FRECENCY_DEFAULT - 1,
-      };
-      if (site.uri.host.includes(this._searchStringFromWWW) ||
-          site._matchTitle.includes(this._searchStringFromWWW)) {
-        strictMatches.push(match);
-      } else if (site.uri.host.includes(this._searchString) ||
-                 site._matchTitle.includes(this._searchString)) {
-        looseMatches.push(match);
+      let url = site.uri.spec;
+      if ((!this._strippedPrefix || url.startsWith(this._strippedPrefix)) &&
+          (site.uri.host.includes(this._searchString) ||
+           site._matchTitle.includes(this._searchString))) {
+        this._addMatch({
+          value: url,
+          comment: site.title,
+          style: "preloaded-top-site",
+          frecency: FRECENCY_DEFAULT - 1,
+        });
       }
     }
-    for (let match of [...strictMatches, ...looseMatches]) {
-      this._addMatch(match);
-    }
   },
 
   _matchPreloadedSiteForAutofill() {
-    if (!Prefs.get("usepreloadedtopurls.enabled"))
-      return false;
-
-    if (!(this._searchStringScheme === "" ||
-          this._searchStringScheme === "https" ||
-          this._searchStringScheme === "http"))
+    if (!Prefs.get("usepreloadedtopurls.enabled")) {
       return false;
-
-    let searchStringSchemePrefix = this._searchStringScheme
-                                   ? (this._searchStringScheme + "://")
-                                   : "";
-
-    // If search string has scheme - we'll match it strictly
-    function matchScheme(site, search) {
-      return !search._searchStringScheme ||
-             search._searchStringScheme === site.uri.scheme;
     }
 
-    // First we try to strict-match
-    // If search string has "www."- we try to strict-match it along with "www."
-    function matchStrict(site) {
-      return site.uri.host.startsWith(this._searchStringFromWWW)
-             && matchScheme(site, this);
-    }
-    let site = PreloadedSiteStorage.sites.find(matchStrict, this);
-    if (site) {
-      let match = {
-        // We keep showing prefix that user typed, then what we match on
-        value: searchStringSchemePrefix + site.uri.host + "/",
-        style: "autofill preloaded-top-site",
-        finalCompleteValue: site.uri.spec,
-        frecency: Infinity
-      };
-      this._result.setDefaultIndex(0);
-      this._addMatch(match);
-      return true;
+    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));
+    });
+    if (!matchedSite) {
+      return false;
     }
 
-    // If no strict result found - we try loose match
-    // regardless of "www." in Preloaded-sites or search string
-    function matchLoose(site) {
-      return site._hostWithoutWWW.startsWith(this._searchString)
-             && matchScheme(site, this);
-    }
-    site = PreloadedSiteStorage.sites.find(matchLoose, this);
-    if (site) {
-      let match = {
-        // We keep showing prefix that user typed, then what we match on
-        value: searchStringSchemePrefix + this._searchStringWWW +
-               site._hostWithoutWWW + "/",
-        style: "autofill preloaded-top-site",
-        // On loose match, result should always have "www."
-        finalCompleteValue: site.uri.scheme + "://www." +
-                            site._hostWithoutWWW + "/",
-        frecency: Infinity
-      };
-      this._result.setDefaultIndex(0);
-      this._addMatch(match);
-      return true;
-    }
+    this._result.setDefaultIndex(0);
 
-    return false;
+    let url = matchedSite.uri.spec;
+    dump(`+++XXXadw _matchPreloadedSiteForAutofill url=${url}\n`);
+    return this._addAutofillMatch(
+      url.substr(url.indexOf(this._searchString)),
+      url,
+      Infinity,
+      ["preloaded-top-site"]
+    );
   },
 
   async _matchFirstHeuristicResult(conn) {
+    dump(`+++XXXadw _matchFirstHeuristicResult _enableActions=${this._enableActions} _searchString='${this._searchString}'\n`);
     // We always try to make the first result a special "heuristic" result.  The
     // heuristics below determine what type of result it will be, if any.
 
     let hasSearchTerms = this._searchTokens.length > 0;
 
     if (hasSearchTerms) {
       // It may be a keyword registered by an extension.
       let matched = await this._matchExtensionHeuristicResult();
@@ -1322,25 +1377,30 @@ Search.prototype = {
     if (this.pending && hasSearchTerms) {
       // It may be a Places keyword.
       let matched = await this._matchPlacesKeyword();
       if (matched) {
         return true;
       }
     }
 
+    dump(`+++XXXadw _matchFirstHeuristicResult A\n`);
+
     let shouldAutofill = this._shouldAutofill;
+    dump(`+++XXXadw this.pending=${this.pending} shouldAutofill=${shouldAutofill}\n`);
     if (this.pending && shouldAutofill) {
       // It may also look like a URL we know from the database.
       let matched = await this._matchKnownUrl(conn);
       if (matched) {
         return true;
       }
     }
 
+    dump(`+++XXXadw _matchFirstHeuristicResult B\n`);
+
     if (this.pending && shouldAutofill) {
       // Or it may look like a URL we know about from search engines.
       let matched = await this._matchSearchEngineUrl();
       if (matched) {
         return true;
       }
     }
 
@@ -1444,44 +1504,49 @@ Search.prototype = {
     }
 
     // Disallow fetching search suggestions for strings looking like URLs, to
     // avoid disclosing information about networks or passwords.
     return this._searchTokens.some(looksLikeUrl);
   },
 
   async _matchKnownUrl(conn) {
-    // Hosts have no "/" in them.
+    let gotResult = false;
+
+    dump(`+++XXXadw _matchKnownUrl _searchString='${this._searchString}'\n`);
+
+    // If search string has a slash in it, then treat it as a potential URL and
+    // try to autofill against URLs.  Otherwise treat it as a potential origin
+    // and try to autofill against origins.  One exception:  When the string has
+    // only one slash and it's at the end, treat it as potential origin, not a
+    // URL.
+    let query, params;
+    let firstSlashIndex = this._searchString.indexOf("/");
     let lastSlashIndex = this._searchString.lastIndexOf("/");
-    // Search only URLs if there's a slash in the search string...
-    if (lastSlashIndex != -1) {
-      // ...but not if it's exactly at the end of the search string.
-      if (lastSlashIndex < this._searchString.length - 1) {
-        // We don't want to execute this query right away because it needs to
-        // search the entire DB without an index, but we need to know if we have
-        // a result as it will influence other heuristics. So we guess by
-        // assuming that if we get a result from a *host* query and it *looks*
-        // like a URL, then we'll probably have a result.
-        let gotResult = false;
-        let [ query, params ] = this._urlQuery;
-        await conn.executeCached(query, params, (row, cancel) => {
-          gotResult = true;
-          this._onResultRow(row, cancel);
-        });
-        return gotResult;
-      }
-      return false;
+    if (firstSlashIndex >= 0 &&
+        (firstSlashIndex != lastSlashIndex ||
+         firstSlashIndex < this._searchString.length - 1)) {
+      dump(`+++XXXadw _matchKnownUrl _urlQuery _searchString='${this._searchString}'\n`);
+      [query, params] = this._urlQuery;
+    } else {
+      dump(`+++XXXadw _matchKnownUrl _originQuery _searchString='${this._searchString}'\n`);
+      [query, params] = this._originQuery;
     }
 
-    let gotResult = false;
-    let [ query, params ] = this._hostQuery;
-    await conn.executeCached(query, params, (row, cancel) => {
-      gotResult = true;
-      this._onResultRow(row, cancel);
-    });
+    if (query) {
+      dump(`+++XXXadw _matchKnownUrl params='${JSON.stringify(params)}'\n`);
+      await conn.executeCached(query, params, (row, cancel) => {
+//         gotResult = true;
+        dump(`+++XXXadw _matchKnownUrl query got result\n`);
+//         this._onResultRow(row, cancel);
+        if (this._onResultRow(row, cancel)) {
+          gotResult = true;
+        }
+      });
+    }
     return gotResult;
   },
 
   _matchExtensionHeuristicResult() {
     if (ExtensionSearchHandler.isKeywordRegistered(this._searchTokens[0]) &&
         this._originalSearchString.length > this._searchTokens[0].length) {
       let description = ExtensionSearchHandler.getDescription(this._searchTokens[0]);
       this._addExtensionMatch(this._originalSearchString, description);
@@ -1534,59 +1599,106 @@ Search.prototype = {
     });
     return true;
   },
 
   async _matchSearchEngineUrl() {
     if (!Prefs.get("autoFill.searchEngines"))
       return false;
 
-    let match = await PlacesSearchAutocompleteProvider.findMatchByToken(
-                                                           this._searchString);
-    if (!match)
+    dump(`+++XXXadw _matchSearchEngineUrl A _searchString='${this._searchString}'\n`);
+
+    if (!this._searchString) {
+      dump(`+++XXXadw _matchSearchEngineUrl er A\n`);
+      return false;
+    }
+
+    let firstSlashIndex = this._searchString.indexOf("/");
+    let lastSlashIndex = this._searchString.lastIndexOf("/");
+    if (firstSlashIndex != lastSlashIndex) {
+      dump(`+++XXXadw _matchSearchEngineUrl er B\n`);
       return false;
+    }
+
+    let searchStr = this._searchString;
+    if (firstSlashIndex >= 0) {
+      if (firstSlashIndex != searchStr.length - 1) {
+        return;
+      }
+      searchStr = searchStr.substr(0, searchStr.length - 1);
+    }
+
+    let match =
+      await PlacesSearchAutocompleteProvider.findMatchByToken(searchStr);
+    if (!match) {
+      return false;
+    }
+
+    dump(`+++XXXadw _matchSearchEngineUrl B\n`);
 
     // The match doesn't contain a 'scheme://www.' prefix, but since we have
     // stripped it from the search string, here we could still be matching
     // 'https://www.g' to 'google.com'.
     // There are a couple cases where we don't want to match though:
     //
     //  * If the protocol differs we should not match. For example if the user
     //    searched https we should not return http.
-    try {
-      let prefixURI = Services.io.newURI(this._strippedPrefix + match.token);
-      let finalURI = Services.io.newURI(match.url);
-      if (prefixURI.scheme != finalURI.scheme)
-        return false;
-    } catch (e) {}
+//     try {
+//       let prefixURI = Services.io.newURI(this._strippedPrefix + match.token);
+//       let finalURI = Services.io.newURI(match.url);
+//       if (prefixURI.scheme != finalURI.scheme)
+//         return false;
+//     } catch (e) {}
+
+    if (this._strippedPrefix && !match.url.startsWith(this._strippedPrefix)) {
+      return false;
+    }
+
+    dump(`+++XXXadw _matchSearchEngineUrl C\n`);
 
-    //  * If the user typed "www." but the final url doesn't have it, we
-    //    should not match as well, the two urls may point to different pages.
-    if (this._strippedPrefix.endsWith("www.") &&
-        !stripHttpAndTrim(match.url).startsWith("www."))
-      return false;
+//     //  * If the user typed "www." but the final url doesn't have it, we
+//     //    should not match as well, the two urls may point to different pages.
+//     if (this._strippedPrefix.endsWith("www.") &&
+//         !stripHttpAndTrim(match.url).startsWith("www."))
+//       return false;
 
-    let value = this._strippedPrefix + match.token;
+//     let value = this._strippedPrefix + match.token;
+
+//     dump(`+++XXXadw _matchSearchEngineUrl D value='${value}'\n`);
+
+    let value = this._strippedPrefix + match.token.substr(match.token.indexOf(searchStr)) + "/";
+    dump(`+++XXXadw _matchSearchEngineUrl D value2='${value}'\n`);
 
     // In any case, we should never arrive here with a value that doesn't
     // match the search string.  If this happens there is some case we
     // are not handling properly yet.
-    if (!value.startsWith(this._originalSearchString)) {
-      Components.utils.reportError(`Trying to inline complete in-the-middle
-                                    ${this._originalSearchString} to ${value}`);
-      return false;
-    }
+//     if (!value.startsWith(this._originalSearchString)) {
+//       Components.utils.reportError(`Trying to inline complete in-the-middle
+//                                     ${this._originalSearchString} to ${value}`);
+//       return false;
+//     }
+
+    dump(`+++XXXadw _matchSearchEngineUrl E\n`);
+
+    let finalCompleteValue = match.url;
+    try {
+      let fixupInfo = Services.uriFixup.getFixupURIInfo(match.url, 0);
+      if (fixupInfo.fixedURI) {
+        finalCompleteValue = fixupInfo.fixedURI.spec;
+      }
+    } catch (ex) {}
 
     this._result.setDefaultIndex(0);
     this._addMatch({
       value,
       comment: match.engineName,
       icon: match.iconUrl,
       style: "priority-search",
-      finalCompleteValue: match.url,
+//       finalCompleteValue: match.url+"",
+      finalCompleteValue,
       frecency: Infinity
     });
     return true;
   },
 
   async _matchSearchEngineAlias() {
     if (this._searchTokens.length < 1)
       return false;
@@ -1788,37 +1900,43 @@ Search.prototype = {
       match.icon = `page-icon:${uri.prePath}/`;
     }
 
     this._addMatch(match);
     return true;
   },
 
   _onResultRow(row, cancel) {
+    dump(`+++XXXadw _onResultRow\n`);
+    let added = false;
+    let defaultIndex = -1;
     let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);
-    let match;
     switch (queryType) {
-      case QUERYTYPE_AUTOFILL_HOST:
-        this._result.setDefaultIndex(0);
-        match = this._processHostRow(row);
+      case QUERYTYPE_AUTOFILL_ORIGIN:
+        added = this._addOriginAutofillMatch(row);
+        defaultIndex = 0;
         break;
       case QUERYTYPE_AUTOFILL_URL:
-        this._result.setDefaultIndex(0);
-        match = this._processUrlRow(row);
+        added = this._addURLAutofillMatch(row);
+        defaultIndex = 0;
         break;
       case QUERYTYPE_FILTERED:
-        match = this._processRow(row);
+        added = this._addFilteredQueryMatch(row);
         break;
     }
-    this._addMatch(match);
+    if (defaultIndex >= 0) {
+      this._result.setDefaultIndex(defaultIndex);
+    }
     // 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[MATCHTYPE.GENERAL] + this._counts[MATCHTYPE.HEURISTIC];
-    if (!this.pending || count >= Prefs.get("maxRichResults"))
+    if (!this.pending || count >= Prefs.get("maxRichResults")) {
       cancel();
+    }
+    return added;
   },
 
   _maybeRestyleSearchMatch(match) {
     // Return if the URL does not represent a search result.
     let parseResult =
       PlacesSearchAutocompleteProvider.parseSubmissionURL(match.value);
     if (!parseResult) {
       return;
@@ -1841,16 +1959,17 @@ Search.prototype = {
       searchQuery: parseResult.terms,
     });
     match.comment = parseResult.engineName;
     match.icon = match.icon || match.iconUrl;
     match.style = "action searchengine favicon";
   },
 
   _addMatch(match) {
+    dump(`****XXXadw _addMatch match=${JSON.stringify(match)}\n`);
     if (typeof match.frecency != "number")
       throw new Error("Frecency not provided");
 
     if (this._addingHeuristicFirstMatch)
       match.type = MATCHTYPE.HEURISTIC;
     else if (typeof match.type != "string")
       match.type = MATCHTYPE.GENERAL;
 
@@ -1866,17 +1985,26 @@ Search.prototype = {
     // This must happen before generating the dedupe key.
     if (match.hasOwnProperty("style") && match.style.includes("autofill")) {
       // We fallback to match.value, as that's what autocomplete does if
       // finalCompleteValue is null.
       // Trim only if the value looks like a domain, we want to retain the
       // trailing slash if we're completing a url to the next slash.
       match.comment = stripHttpAndTrim(match.finalCompleteValue || match.value,
                                        !this._searchString.includes("/"));
-    }
+
+//       match.comment = match.finalCompleteValue;
+
+//       // We fallback to match.value, as that's what autocomplete does if
+//       // finalCompleteValue is null.
+//       // Trim only if the value looks like a domain, we want to retain the
+//       // trailing slash if we're completing a url to the next slash.
+//       match.comment = stripHttpAndTrim(match.finalCompleteValue || match.value,
+//                                        false);
+   }
 
     // Must check both id and url, cause keywords dynamically modify the url.
     let urlMapKey = makeKeyForURL(match);
     if ((match.placeId && this._usedPlaceIds.has(match.placeId)) ||
         this._usedURLs.has(urlMapKey)) {
       return;
     }
 
@@ -1900,16 +2028,19 @@ Search.prototype = {
     if (this._addingHeuristicFirstMatch) {
       match.style += " heuristic";
     }
 
     match.icon = match.icon || "";
     match.finalCompleteValue = match.finalCompleteValue || "";
 
     let {index, replace} = this._getInsertIndexForMatch(match);
+
+    dump(`****XXXadw _addMatch OK! replace=${replace} match=${JSON.stringify(match)}\n`);
+
     if (replace) { // Replacing an existing match from the previous search.
       this._result.removeMatchAt(index);
     }
     this._result.insertMatchAt(index,
                                match.value,
                                match.comment,
                                match.icon,
                                match.style,
@@ -1995,17 +2126,18 @@ Search.prototype = {
     if (this._previousSearchMatchTypes.length == 0 || !this.pending)
       return;
 
     let index = 0;
     let changed = false;
     if (!this._buckets) {
       // No match arrived yet, so any match of the given type should be removed
       // from the top.
-      while (this._previousSearchMatchTypes[0] == type) {
+      while (this._previousSearchMatchTypes.length &&
+             this._previousSearchMatchTypes[0] == type) {
         this._previousSearchMatchTypes.shift();
         this._result.removeMatchAt(0);
         changed = true;
       }
     } else {
       for (let bucket of this._buckets) {
         if (bucket.type != type) {
           index += bucket.count;
@@ -2034,79 +2166,59 @@ Search.prototype = {
         if (this._counts[type] == 0) {
           // Don't notify, since we are about to notify completion.
           this._cleanUpNonCurrentMatches(type, false);
         }
       }
     }
   },
 
-  _processHostRow(row) {
-    let match = {};
-    let strippedHost = row.getResultByIndex(QUERYINDEX_URL);
-    let url = row.getResultByIndex(QUERYINDEX_TITLE);
-    let unstrippedHost = stripHttpAndTrim(url, false);
-    let frecency = row.getResultByIndex(QUERYINDEX_FRECENCY);
+  _addOriginAutofillMatch(row) {
+    return this._addAutofillMatch(
+      row.getResultByIndex(QUERYINDEX_ORIGIN_AUTOFILLED_VALUE),
+      row.getResultByIndex(QUERYINDEX_ORIGIN_URL),
+      row.getResultByIndex(QUERYINDEX_ORIGIN_FRECENCY)
+    );
+  },
 
-    // If the unfixup value doesn't preserve the user's input just
-    // ignore it and complete to the found host.
-    if (!unstrippedHost.toLowerCase().includes(this._trimmedOriginalSearchString.toLowerCase())) {
-      unstrippedHost = null;
-    }
-
-    match.value = this._strippedPrefix + strippedHost;
-    match.finalCompleteValue = unstrippedHost;
-
-    match.icon = "page-icon:" + url;
-
-    // Although this has a frecency, this query is executed before any other
-    // queries that would result in frecency matches.
-    match.frecency = frecency;
-    match.style = "autofill";
-    return match;
+  _addURLAutofillMatch(row) {
+    let url = row.getResultByIndex(QUERYINDEX_URL_URL);
+    let strippedURL = row.getResultByIndex(QUERYINDEX_URL_STRIPPED_URL);
+    return this._addAutofillMatch(
+      url.substr(url.indexOf(strippedURL)),
+      url,
+      row.getResultByIndex(QUERYINDEX_URL_FRECENCY)
+    );
   },
 
-  _processUrlRow(row) {
-    let url = row.getResultByIndex(QUERYINDEX_URL);
-    let strippedUrl = stripPrefix(url);
-    let prefix = url.substr(0, url.length - strippedUrl.length);
-    let frecency = row.getResultByIndex(QUERYINDEX_FRECENCY);
-
-    // We must complete the URL up to the next separator (which is /, ? or #).
-    let searchString = stripPrefix(this._trimmedOriginalSearchString);
-    let separatorIndex = strippedUrl.slice(searchString.length)
-                                    .search(/[\/\?\#]/);
-    if (separatorIndex != -1) {
-      separatorIndex += searchString.length;
-      if (strippedUrl[separatorIndex] == "/") {
-        separatorIndex++; // Include the "/" separator
-      }
-      strippedUrl = strippedUrl.slice(0, separatorIndex);
+  _addAutofillMatch(autofilledValue, finalCompleteValue, frecency, styles = []) {
+    dump(`****XXXadw _addAutofillMatch autofilledValue='${autofilledValue}' finalCompleteValue='${finalCompleteValue}' frecency=${frecency} mean=${PlacesUtils.history.frecencyMean} stddev=${PlacesUtils.history.frecencyStandardDeviation}\n`);
+    let stddevMultiplier = 1.0;
+    let threshold =
+      PlacesUtils.history.frecencyMean +
+      (stddevMultiplier * PlacesUtils.history.frecencyStandardDeviation);
+    if (frecency < threshold) {
+      //XXXadw if we're currently adding the heuristic result (and i think we
+      // always are at this point), and we get here, then we should probably
+      // add/fall back to some other kind of heuristic result, right?  this
+      // method needs to return a bool or something to signal success.  and need
+      // to test that.
+      return false;
     }
-
-    let match = {
-      value: this._strippedPrefix + strippedUrl,
-      // Although this has a frecency, this query is executed before any other
-      // queries that would result in frecency matches.
+    this._addMatch({
+      value: this._strippedPrefix + autofilledValue,
+      finalCompleteValue,
       frecency,
-      style: "autofill"
-    };
-
-    // Complete to the found url only if its untrimmed value preserves the
-    // user's input.
-    if (url.toLowerCase().includes(this._trimmedOriginalSearchString.toLowerCase())) {
-      match.finalCompleteValue = prefix + strippedUrl;
-    }
-
-    match.icon = "page-icon:" + (match.finalCompleteValue || match.value);
-
-    return match;
+      style: ["autofill"].concat(styles).join(" "),
+      icon: "page-icon:" + finalCompleteValue,
+    });
+    return true;
   },
 
-  _processRow(row) {
+  _addFilteredQueryMatch(row) {
     let match = {};
     match.placeId = row.getResultByIndex(QUERYINDEX_PLACEID);
     let escapedURL = row.getResultByIndex(QUERYINDEX_URL);
     let openPageCount = row.getResultByIndex(QUERYINDEX_SWITCHTAB) || 0;
     let historyTitle = row.getResultByIndex(QUERYINDEX_TITLE) || "";
     let bookmarked = row.getResultByIndex(QUERYINDEX_BOOKMARKED);
     let bookmarkTitle = bookmarked ?
       row.getResultByIndex(QUERYINDEX_BOOKMARKTITLE) : null;
@@ -2162,17 +2274,18 @@ Search.prototype = {
     if (action)
       match.style = "action " + action;
 
     match.value = url;
     match.comment = title;
     match.icon = "page-icon:" + escapedURL;
     match.frecency = frecency;
 
-    return match;
+    this._addMatch(match);
+    return true;
   },
 
   /**
    * @return a string consisting of the search query to be used based on the
    * previously set urlbar suggestion preferences.
    */
   get _suggestionPrefQuery() {
     if (!this.hasBehavior("restrict") && this.hasBehavior("history") &&
@@ -2303,80 +2416,125 @@ Search.prototype = {
 
     if (this._prohibitAutoFill)
       return false;
 
     return true;
   },
 
   /**
-   * Obtains the query to search for autoFill host results.
+   * Obtains the query to search for autofill origin results.
    *
    * @return an array consisting of the correctly optimized query to search the
    *         database with and an object containing the params to bound.
    */
-  get _hostQuery() {
-    let typed = Prefs.get("autoFill.typed") || this.hasBehavior("typed");
-    let bookmarked = this.hasBehavior("bookmark") && !this.hasBehavior("history");
+  get _originQuery() {
+    let bookmarked = this.hasBehavior("bookmark") &&
+                     !this.hasBehavior("history");
+
+    // At this point, _searchString is not a URL with a path; it does not
+    // contain a slash, except for possibly at the very end.  If there is
+    // trailing slash, remove it when searching here to match the rest of the
+    // string because it may be an origin.
+    let searchStr =
+      !this._searchString.endsWith("/") ?
+      this._searchString :
+      this._searchString.substr(0, this._searchString.length - 1);
 
     let query = [];
-    if (bookmarked) {
-      query.push(typed ? SQL_BOOKMARKED_TYPED_HOST_QUERY
-                       : SQL_BOOKMARKED_HOST_QUERY);
+    let opts = {
+      query_type: QUERYTYPE_AUTOFILL_ORIGIN,
+      searchString: searchStr.toLowerCase(),
+    };
+
+    if (this._strippedPrefix) {
+      if (bookmarked) {
+        query.push(SQL_ORIGIN_PREFIX_BOOKMARKED_QUERY);
+      } else {
+        query.push(SQL_ORIGIN_PREFIX_QUERY);
+      }
+      opts.prefix = this._strippedPrefix;
     } else {
-      query.push(typed ? SQL_TYPED_HOST_QUERY
-                       : SQL_HOST_QUERY);
+      if (bookmarked) {
+        query.push(SQL_ORIGIN_BOOKMARKED_QUERY);
+      } else {
+        query.push(SQL_ORIGIN_QUERY);
+      }
     }
 
-    query.push({
-      query_type: QUERYTYPE_AUTOFILL_HOST,
-      searchString: this._searchString.toLowerCase()
-    });
+    query.push(opts);
 
     return query;
   },
 
   /**
    * Obtains the query to search for autoFill url results.
    *
    * @return an array consisting of the correctly optimized query to search the
    *         database with and an object containing the params to bound.
    */
   get _urlQuery() {
-    // We expect this to be a full URL, not just a host. We want to extract the
-    // host and use that as a guess for whether we'll get a result from a URL
-    // query.
-    // The URIs in the database are fixed-up, so we can match on a lowercased
-    // host, but the path must be matched in a case sensitive way.
-    let pathIndex = this._trimmedOriginalSearchString.indexOf("/", this._strippedPrefix.length);
-    let revHost = this._trimmedOriginalSearchString
-                      .substring(this._strippedPrefix.length, pathIndex)
-                      .toLowerCase().split("").reverse().join("") + ".";
-    let searchString = stripPrefix(
-      this._trimmedOriginalSearchString.slice(0, pathIndex).toLowerCase() +
-      this._trimmedOriginalSearchString.slice(pathIndex)
-    );
+    // Assuming the search string is a URL, get the hostname, the part of the
+    // search string up to either the path slash or the port colon.
+    let hostMatch = /^[^/:]+/.exec(this._searchString);
+    if (!hostMatch) {
+      return [null, null];
+    }
+
+    let bookmarked = this.hasBehavior("bookmark") &&
+                     !this.hasBehavior("history");
+
+    let host = hostMatch[0].toLowerCase();
+    let revHost = host.split("").reverse().join("") + ".";
+//     let strippedURL = host + this._searchString.substr(host.length);
+
 
-    let typed = Prefs.get("autoFill.typed") || this.hasBehavior("typed");
-    let bookmarked = this.hasBehavior("bookmark") && !this.hasBehavior("history");
+//     // this._searchString has had unEscapeURIForUI() called on it; it's not
+//     // necessarily the actual URL.  Use _trimmedOriginalSearchString instead.
+//     let strippedURL = this._trimmedOriginalSearchString;
+//     if (this._strippedPrefix) {
+//       strippedURL = strippedURL.substr(this._strippedPrefix.length);
+//     }
+// //     strippedURL = host + strippedURL.substr(host.length);
+
+
+    // this._searchString has had unEscapeURIForUI() called on it; it's not
+    // necessarily the actual URL.  Use _trimmedOriginalSearchString instead.
+    let strippedURL = this._trimmedOriginalSearchString;
+    if (this._strippedPrefix) {
+      strippedURL = strippedURL.substr(this._strippedPrefix.length);
+    }
+    strippedURL = host + strippedURL.substr(host.length);
+
+
+    dump(`+++XXXadw _urlQuery strippedURL=${strippedURL}\n`);
 
     let query = [];
-    if (bookmarked) {
-      query.push(typed ? SQL_BOOKMARKED_TYPED_URL_QUERY
-                       : SQL_BOOKMARKED_URL_QUERY);
+    let opts = {
+      query_type: QUERYTYPE_AUTOFILL_URL,
+      revHost,
+      strippedURL,
+    };
+
+    if (this._strippedPrefix) {
+      if (bookmarked) {
+        query.push(SQL_URL_PREFIX_BOOKMARKED_QUERY);
+      } else {
+        query.push(SQL_URL_PREFIX_QUERY);
+      }
+      opts.prefix = this._strippedPrefix;
     } else {
-      query.push(typed ? SQL_TYPED_URL_QUERY
-                       : SQL_URL_QUERY);
+      if (bookmarked) {
+        query.push(SQL_URL_BOOKMARKED_QUERY);
+      } else {
+        query.push(SQL_URL_QUERY);
+      }
     }
 
-    query.push({
-      query_type: QUERYTYPE_AUTOFILL_URL,
-      searchString,
-      revHost
-    });
+    query.push(opts);
 
     return query;
   },
 
   // The result is notified to the search listener on a timer, to chunk multiple
   // match updates together and avoid rebuilding the popup at every new match.
   _notifyTimer: null,
 
@@ -2515,16 +2673,17 @@ UnifiedComplete.prototype = {
 
   populatePreloadedSiteStorage(json) {
     PreloadedSiteStorage.populate(json);
   },
 
   // nsIAutoCompleteSearch
 
   startSearch(searchString, searchParam, acPreviousResult, listener) {
+    dump(`+++XXXadw UnifiedComplete startSearch\n`);
     // Stop the search in case the controller has not taken care of it.
     if (this._currentSearch) {
       this.stopSearch();
     }
 
     // If the previous search didn't fetch enough search suggestions, it's
     // unlikely a longer text would do.
     let prohibitSearchSuggestions =
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -1205,17 +1205,17 @@ interface nsINavHistoryQueryOptions : ns
   attribute boolean asyncEnabled;
 
   /**
    * Creates a new options item with the same parameters of this one.
    */
   nsINavHistoryQueryOptions clone();
 };
 
-[scriptable, uuid(8a1f527e-c9d7-4a51-bf0c-d86f0379b701)]
+[scriptable, uuid(20c974ff-ee16-4828-9326-1b7c9e036622)]
 interface nsINavHistoryService : nsISupports
 {
   /**
    * System Notifications:
    *
    * places-init-complete - Sent once the History service is completely
    *                        initialized successfully.
    * places-database-locked - Sent if initialization of the History service
@@ -1459,16 +1459,19 @@ interface nsINavHistoryService : nsISupp
    * Returns a 48-bit hash for a URI spec.
    *
    * @param aSpec
    *        The URI spec to hash.
    * @param aMode
    *        The hash mode: `""` (default), `"prefix_lo"`, or `"prefix_hi"`.
    */
   unsigned long long hashURL(in ACString aSpec, [optional] in ACString aMode);
+
+  readonly attribute double frecencyMean;
+  readonly attribute double frecencyStandardDeviation;
 };
 
 /**
  * @see runInBatchMode of nsINavHistoryService/nsINavBookmarksService
  */
 [scriptable, function, uuid(5a5a9154-95ac-4e3d-90df-558816297407)]
 interface nsINavHistoryBatchCallback : nsISupports {
   void runBatched(in nsISupports aUserData);
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -40,16 +40,24 @@
 #include "mozilla/Preferences.h"
 #include <algorithm>
 
 #ifdef MOZ_XUL
 #include "nsIAutoCompleteInput.h"
 #include "nsIAutoCompletePopup.h"
 #endif
 
+//XXXadw
+#if defined(_MSC_VER)
+#define PRETTY_FUNCTION_XXXadw __FUNCSIG__
+#else
+#define PRETTY_FUNCTION_XXXadw __PRETTY_FUNCTION__
+#endif
+
+
 using namespace mozilla;
 using namespace mozilla::places;
 
 // The maximum number of things that we will store in the recent events list
 // before calling ExpireNonrecentEvents. This number should be big enough so it
 // is very difficult to get that many unconsumed events (for example, typed but
 // never visited) in the RECENT_EVENT_THRESHOLD. Otherwise, we'll start
 // checking each one for every page visit, which will be somewhat slower.
@@ -282,16 +290,17 @@ nsNavHistory::nsNavHistory()
   , mHistoryEnabled(true)
   , mNumVisitsForFrecency(10)
   , mTagsFolder(-1)
   , mDaysOfHistory(-1)
   , mLastCachedStartOfDay(INT64_MAX)
   , mLastCachedEndOfDay(0)
   , mCanNotify(true)
   , mCacheObservers("history-observers")
+  , mIsFrecencyDecaying(false)
 #ifdef XP_WIN
   , mCryptoProviderInitialized(false)
 #endif
 {
   NS_ASSERTION(!gHistoryService,
                "Attempting to create two instances of the service!");
 #ifdef XP_WIN
   BOOL cryptoAcquired = CryptAcquireContext(&mCryptoProvider, 0, 0, PROV_RSA_FULL,
@@ -325,16 +334,23 @@ nsNavHistory::~nsNavHistory()
 nsresult
 nsNavHistory::Init()
 {
   LoadPrefs();
 
   mDB = Database::GetDatabase();
   NS_ENSURE_STATE(mDB);
 
+
+  mFrecencyStatsCount = Preferences::GetUint("places.frecency.stats.count", 0U);
+  mFrecencyStatsSum = Preferences::GetUint("places.frecency.stats.sum", 0U);
+  mFrecencyStatsSumOfSquares = Preferences::GetUint("places.frecency.stats.sumOfSquares", 0U);
+
+
+
   /*****************************************************************************
    *** IMPORTANT NOTICE!
    ***
    *** Nothing after these add observer calls should return anything but NS_OK.
    *** If a failure code is returned, this nsNavHistory object will be held onto
    *** by the observer service and the preference service.
    ****************************************************************************/
 
@@ -429,31 +445,46 @@ nsNavHistory::GetOrCreateIdForPage(nsIUR
   }
 
   {
     // Create a new hidden, untyped and unvisited entry.
     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
       "INSERT INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid) "
       "VALUES (:page_url, hash(:page_url), :rev_host, :hidden, :frecency, :guid) "
     );
+//     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+//       "INSERT INTO moz_places (url, url_hash, rev_host, origin, hidden, frecency, guid) "
+//       "VALUES (:page_url, hash(:page_url), :rev_host, :origin, :hidden, :frecency, :guid) "
+//     );
     NS_ENSURE_STATE(stmt);
     mozStorageStatementScoper scoper(stmt);
 
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
     NS_ENSURE_SUCCESS(rv, rv);
     // host (reversed with trailing period)
     nsAutoString revHost;
     rv = GetReversedHostname(aURI, revHost);
+    //XXXadw see this comment
     // Not all URI types have hostnames, so this is optional.
     if (NS_SUCCEEDED(rv)) {
       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("rev_host"), revHost);
     } else {
       rv = stmt->BindNullByName(NS_LITERAL_CSTRING("rev_host"));
     }
     NS_ENSURE_SUCCESS(rv, rv);
+
+//     nsAutoCString origin;
+//     rv = aURI->GetPrePath(origin);
+//     if (NS_SUCCEEDED(rv) && !origin.IsEmpty()) {
+//       rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"), origin);
+//     } else {
+//       rv = stmt->BindNullByName(NS_LITERAL_CSTRING("origin"));
+//     }
+//     NS_ENSURE_SUCCESS(rv, rv);
+
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), 1);
     NS_ENSURE_SUCCESS(rv, rv);
     nsAutoCString spec;
     rv = aURI->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("frecency"),
                                IsQueryURI(spec) ? 0 : -1);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -466,17 +497,17 @@ nsNavHistory::GetOrCreateIdForPage(nsIUR
     NS_ENSURE_SUCCESS(rv, rv);
 
     *_pageId = sLastInsertedPlaceId;
   }
 
   {
     // Trigger the updates to moz_hosts
     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
-      "DELETE FROM moz_updatehostsinsert_temp"
+      "DELETE FROM moz_updateoriginsinsert_temp"
     );
     NS_ENSURE_STATE(stmt);
     mozStorageStatementScoper scoper(stmt);
   }
 
   return NS_OK;
 }
 
@@ -614,31 +645,257 @@ public:
 private:
   nsCString mSpec;
   int32_t mNewFrecency;
   nsCString mGUID;
   bool mHidden;
   PRTime mLastVisitDate;
 };
 
+
+
+//XXXadw reason for this is:
+// Assertion failure: sInServoTraversal || NS_IsMainThread(), at /Users/adw/mc/obj-debug/dist/include/mozilla/ServoStyleSet.h:98
+// #01: mozilla::ServoStyleSet::IsInServoTraversal()[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x26824d]
+// #02: mozilla::Preferences::InitStaticMembers()[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x2680bf]
+// #03: mozilla::Preferences::SetIntInAnyProcess(char const*, int, mozilla::PrefValueKind)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x26e25b]
+// #04: mozilla::Preferences::SetInt(char const*, int, mozilla::PrefValueKind)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x25e7fe]
+// #05: mozilla::Preferences::SetUint(char const*, unsigned int, mozilla::PrefValueKind)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x23d262a]
+// [Parent 18408, Main Thread] WARNING: NS_ENSURE_SUCCESS(rv, rv) failed with result 0x80070057: file /Users/adw/mc/netwerk/base/nsChannelClassifier.cpp, line 344
+// #06: nsNavHistory::UpdateFrecencyStats(int, int, long long)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x84924ec]
+// #07: mozilla::places::UpdateFrecencyStatsFunction::OnFunctionCall(mozIStorageValueArray*, nsIVariant**)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x8492133]
+// #08: mozilla::storage::(anonymous namespace)::basicFunctionHelper(sqlite3_context*, int, sqlite3_value**)[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/XUL +0x17c90a8]
+// #09: sqlite3VdbeExec[/Users/adw/mc/obj-debug/dist/NightlyDebug.app/Contents/MacOS/libnss3.dylib +0x6d9c3]
+class SaveFrecencyStatsRunnable : public Runnable
+{
+public:
+  SaveFrecencyStatsRunnable()
+    : mozilla::Runnable("SaveFrecencyStatsRunnable")
+  {
+  }
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "Must be called on the main thread");
+    nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
+    if (navHistory) {
+      navHistory->SaveFrecencyStats();
+    }
+    return NS_OK;
+  }
+};
+
+
 } // namespace
 
 void
 nsNavHistory::DispatchFrecencyChangedNotification(const nsACString& aSpec,
                                                   int32_t aNewFrecency,
                                                   const nsACString& aGUID,
                                                   bool aHidden,
                                                   PRTime aLastVisitDate) const
 {
   nsCOMPtr<nsIRunnable> notif = new FrecencyNotification(aSpec, aNewFrecency,
                                                          aGUID, aHidden,
                                                          aLastVisitDate);
   (void)NS_DispatchToMainThread(notif);
 }
 
+#if 0
+//XXXadw need to store these somewhere (prefs?)
+Atomic<uint64_t> nsNavHistory::sFrecencyStatsCount(0);
+// Atomic<uint64_t> nsNavHistory::sFrecencyStatsFirst(0);
+Atomic<uint64_t> nsNavHistory::sFrecencyStatsSum(0);
+Atomic<uint64_t> nsNavHistory::sFrecencyStatsSumOfSquares(0);
+
+// void // static
+// nsNavHistory::UpdateFrecencyStats(int32_t aOldFrecency,
+//                                   int32_t aNewFrecency)
+// {
+//   if (aOldFrecency >= 0) {
+//     MOZ_ASSERT(sFrecencyStatsCount > 0);
+//     sFrecencyStatsCount--;
+//     int64_t diff = aOldFrecency - sFrecencyStatsFirst;
+//     sFrecencyStatsSum -= diff;
+//     sFrecencyStatsSumOfSquares -= diff * diff;
+//   }
+//   if (aNewFrecency >= 0) {
+//     if (sFrecencyStatsCount == 0) {
+//       sFrecencyStatsFirst = aNewFrecency;
+//     }
+//     sFrecencyStatsCount++;
+//     int64_t diff = aNewFrecency - sFrecencyStatsFirst;
+//     sFrecencyStatsSum += diff;
+//     sFrecencyStatsSumOfSquares += diff * diff;
+//   }
+// }
+
+// void // static
+// nsNavHistory::UpdateFrecencyStats(int32_t aOldFrecency,
+//                                   int32_t aNewFrecency)
+// {
+//   if (aOldFrecency >= 0) {
+//     MOZ_ASSERT(sFrecencyStatsCount > 0);
+//     sFrecencyStatsCount--;
+//     int64_t diff = aOldFrecency - sFrecencyStatsFirst;
+//     MOZ_ASSERT(sFrecencyStatsSum >= diff);
+//     sFrecencyStatsSum -= diff;
+//     MOZ_ASSERT(sFrecencyStatsSumOfSquares >= diff * diff);
+//     sFrecencyStatsSumOfSquares -= diff * diff;
+//   }
+//   if (aNewFrecency >= 0) {
+//     if (sFrecencyStatsCount == 0) {
+//       sFrecencyStatsFirst = aNewFrecency;
+//     }
+//     sFrecencyStatsCount++;
+//     int64_t diff = aNewFrecency - sFrecencyStatsFirst;
+//     sFrecencyStatsSum += diff;
+//     sFrecencyStatsSumOfSquares += diff * diff;
+//   }
+// }
+
+void // static
+nsNavHistory::UpdateFrecencyStats(int32_t aOldFrecency,
+                                  int32_t aNewFrecency,
+                                  int64_t aPlaceID)
+{
+  printf("$$$XXXadw %s starting aPlaceID=%d old=%d new=%d sFrecencyStatsCount=%d\n", PRETTY_FUNCTION_XXXadw, (int32_t) aPlaceID, aOldFrecency, aNewFrecency, (int32_t)sFrecencyStatsCount);
+  //XXXadw all these static vars should be non-static vars instead, and then
+  // this gets/uses the nsNavHistory singleton (GetHistoryService())?
+//   if (aOldFrecency >= 0) {
+  if (aOldFrecency > 0) {
+    MOZ_ASSERT(sFrecencyStatsCount > 0);
+    if (sFrecencyStatsCount > 0) {
+    sFrecencyStatsCount--;
+    uint64_t uold = (uint64_t) aOldFrecency;
+    MOZ_ASSERT(sFrecencyStatsSum >= uold);
+    sFrecencyStatsSum -= uold;
+    uint64_t square = uold * uold;
+    MOZ_ASSERT(sFrecencyStatsSumOfSquares >= square);
+    sFrecencyStatsSumOfSquares -= square;
+    }
+  }
+//   if (aNewFrecency >= 0) {
+  if (aNewFrecency > 0) {
+    sFrecencyStatsCount++;
+    uint64_t unew = (uint64_t) aNewFrecency;
+    sFrecencyStatsSum += unew;
+    sFrecencyStatsSumOfSquares += unew * unew;
+  }
+
+  static mozilla::Atomic<uint64_t> sFrecencyStatsCount;
+//   static mozilla::Atomic<uint64_t> sFrecencyStatsFirst;
+  static mozilla::Atomic<uint64_t> sFrecencyStatsSum;
+  static mozilla::Atomic<uint64_t> sFrecencyStatsSumOfSquares;
+
+  Preferences::SetUint("places.frecency.stats.count", (uint32_t)sFrecencyStatsCount);
+  Preferences::SetUint("places.frecency.stats.sum", (uint32_t)sFrecencyStatsSum);
+  Preferences::SetUint("places.frecency.stats.sumOfSquares", (uint32_t)sFrecencyStatsSumOfSquares);
+
+  double mean, stddev;
+  Unused << GetHistoryService()->GetFrecencyMean(&mean);
+  Unused << GetHistoryService()->GetFrecencyStandardDeviation(&stddev);
+  printf("$$$XXXadw %s aOldFrecency=%d aNewFrecency=%d newMean=%f newStddev=%f sFrecencyStatsCount=%d\n", PRETTY_FUNCTION_XXXadw, aOldFrecency, aNewFrecency, mean, stddev, (int32_t)sFrecencyStatsCount);
+}
+#endif
+
+
+void
+nsNavHistory::UpdateFrecencyStats(int32_t aOldFrecency,
+                                  int32_t aNewFrecency,
+                                  int64_t aPlaceID)
+{
+  printf("$$$XXXadw %s starting aPlaceID=%d old=%d new=%d mFrecencyStatsCount=%d\n", PRETTY_FUNCTION_XXXadw, (int32_t) aPlaceID, aOldFrecency, aNewFrecency, (int32_t)mFrecencyStatsCount);
+  //XXXadw all these static vars should be non-static vars instead, and then
+  // this gets/uses the nsNavHistory singleton (GetHistoryService())?
+//   if (aOldFrecency >= 0) {
+  if (aOldFrecency > 0) {
+    MOZ_ASSERT(mFrecencyStatsCount > 0);
+//     if (mFrecencyStatsCount > 0) {
+    mFrecencyStatsCount--;
+    uint64_t uold = (uint64_t) aOldFrecency;
+    MOZ_ASSERT(mFrecencyStatsSum >= uold);
+    mFrecencyStatsSum -= uold;
+    uint64_t square = uold * uold;
+    MOZ_ASSERT(mFrecencyStatsSumOfSquares >= square);
+    mFrecencyStatsSumOfSquares -= square;
+//     }
+  }
+//   if (aNewFrecency >= 0) {
+  if (aNewFrecency > 0) {
+    mFrecencyStatsCount++;
+    uint64_t unew = (uint64_t) aNewFrecency;
+    mFrecencyStatsSum += unew;
+    mFrecencyStatsSumOfSquares += unew * unew;
+  }
+
+  nsCOMPtr<nsIRunnable> runnable = new SaveFrecencyStatsRunnable();
+  (void)NS_DispatchToMainThread(runnable);
+
+  double mean, stddev;
+  Unused << GetFrecencyMean(&mean);
+  Unused << GetFrecencyStandardDeviation(&stddev);
+  printf("$$$XXXadw %s aOldFrecency=%d aNewFrecency=%d newMean=%f newStddev=%f mFrecencyStatsCount=%d\n", PRETTY_FUNCTION_XXXadw, aOldFrecency, aNewFrecency, mean, stddev, (int32_t)mFrecencyStatsCount);
+}
+
+void
+nsNavHistory::SaveFrecencyStats()
+{
+  Preferences::SetUint("places.frecency.stats.count", (uint32_t)mFrecencyStatsCount);
+  Preferences::SetUint("places.frecency.stats.sum", (uint32_t)mFrecencyStatsSum);
+  Preferences::SetUint("places.frecency.stats.sumOfSquares", (uint32_t)mFrecencyStatsSumOfSquares);
+}
+
+// NS_IMETHODIMP
+// nsNavHistory::GetFrecencyMean(double *_retval)
+// {
+//   NS_ENSURE_ARG_POINTER(_retval);
+//   *_retval = (double) (sFrecencyStatsFirst + sFrecencyStatsSum) /
+//              (double) sFrecencyStatsCount;
+//   return NS_OK;
+// }
+
+NS_IMETHODIMP
+nsNavHistory::GetFrecencyMean(double *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  if (mFrecencyStatsCount == 0) {
+    *_retval = 0.0;
+    return NS_OK;
+  }
+  *_retval = (double) mFrecencyStatsSum / (double) mFrecencyStatsCount;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNavHistory::GetFrecencyStandardDeviation(double *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  if (mFrecencyStatsCount <= 1) {
+    *_retval = 0.0;
+    return NS_OK;
+  }
+  *_retval = sqrt(
+    ((double) mFrecencyStatsSumOfSquares -
+     ((double) (mFrecencyStatsSum * mFrecencyStatsSum) /
+      (double) mFrecencyStatsCount)) /
+    //XXXadw ???
+//     (double) (mFrecencyStatsCount - 1)
+    (double) mFrecencyStatsCount
+  );
+  return NS_OK;
+}
+
+// bool // static
+bool
+nsNavHistory::IsFrecencyDecaying()
+{
+  return mIsFrecencyDecaying;
+}
+
 Atomic<int64_t> nsNavHistory::sLastInsertedPlaceId(0);
 Atomic<int64_t> nsNavHistory::sLastInsertedVisitId(0);
 
 void // static
 nsNavHistory::StoreLastInsertedId(const nsACString& aTable,
                                   const int64_t aLastInsertedId) {
   if (aTable.EqualsLiteral("moz_places")) {
     nsNavHistory::sLastInsertedPlaceId = aLastInsertedId;
@@ -2529,20 +2786,38 @@ nsNavHistory::CleanupPlacesOnVisitsDelet
   ));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = conn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DELETE FROM moz_icons "
     "WHERE root = 0 AND id NOT IN (SELECT icon_id FROM moz_icons_to_pages) "
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
+
+//   printf("****XXXadw dumping moz_updateoriginsdelete_temp\n");
+  nsCOMPtr<mozIStorageStatement> stmt2 = mDB->GetStatement(NS_LITERAL_CSTRING(
+    "SELECT * FROM moz_updateoriginsdelete_temp"
+  ));
+  NS_ENSURE_STATE(stmt2);
+  mozStorageStatementScoper scoper2(stmt2);
+  while (NS_SUCCEEDED(stmt2->ExecuteStep(&hasMore)) && hasMore) {
+    int64_t originID;
+    nsresult rv = stmt2->GetInt64(0, &originID);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsAutoCString host;
+    rv = stmt2->GetUTF8String(1, host);
+    NS_ENSURE_SUCCESS(rv, rv);
+//     printf("****XXXadw moz_updateoriginsdelete_temp: origin_id=%lld host=%s\n", originID, host.get());
+  }
+
+
   // Hosts accumulated during the places delete are updated through a trigger
   // (see nsPlacesTriggers.h).
   rv = conn->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DELETE FROM moz_updatehostsdelete_temp")
+    NS_LITERAL_CSTRING("DELETE FROM moz_updateoriginsdelete_temp")
   );
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Invalidate frecencies of touched places, since they need recalculation.
   rv = invalidateFrecencies(aPlaceIdsQueryString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Finally notify about the removed URIs.
@@ -3074,20 +3349,22 @@ nsNavHistory::DecayFrecency()
   float decayRate = Preferences::GetFloat(PREF_FREC_DECAY_RATE, PREF_FREC_DECAY_RATE_DEF);
 
   // Globally decay places frecency rankings to estimate reduced frecency
   // values of pages that haven't been visited for a while, i.e., they do
   // not get an updated frecency.  A scaling factor of .975 results in .5 the
   // original value after 28 days.
   // When changing the scaling factor, ensure that the barrier in
   // moz_places_afterupdate_frecency_trigger still ignores these changes.
+  mIsFrecencyDecaying = true;
   nsCOMPtr<mozIStorageAsyncStatement> decayFrecency = mDB->GetAsyncStatement(
     "UPDATE moz_places SET frecency = ROUND(frecency * :decay_rate) "
     "WHERE frecency > 0"
   );
+  mIsFrecencyDecaying = false;
   NS_ENSURE_STATE(decayFrecency);
 
   rv = decayFrecency->BindDoubleByName(NS_LITERAL_CSTRING("decay_rate"),
                                        static_cast<double>(decayRate));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Decay potentially unused adaptive entries (e.g. those that are at 1)
   // to allow better chances for new entries that will start at 1.
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -466,16 +466,38 @@ public:
    * Posts a runnable to the main thread that calls NotifyFrecencyChanged.
    */
   void DispatchFrecencyChangedNotification(const nsACString& aSpec,
                                            int32_t aNewFrecency,
                                            const nsACString& aGUID,
                                            bool aHidden,
                                            PRTime aLastVisitDate) const;
 
+// //   static void UpdateFrecencyStats(int32_t aOldFrecency,
+// //                                   int32_t aNewFrecency);
+//   static void UpdateFrecencyStats(int32_t aOldFrecency,
+//                                   int32_t aNewFrecency,
+//                                   int64_t placeID);
+//   static mozilla::Atomic<uint64_t> sFrecencyStatsCount;
+// //   static mozilla::Atomic<uint64_t> sFrecencyStatsFirst;
+//   static mozilla::Atomic<uint64_t> sFrecencyStatsSum;
+//   static mozilla::Atomic<uint64_t> sFrecencyStatsSumOfSquares;
+
+  void UpdateFrecencyStats(int32_t aOldFrecency,
+                           int32_t aNewFrecency,
+                           int64_t placeID);
+  mozilla::Atomic<uint64_t> mFrecencyStatsCount;
+  mozilla::Atomic<uint64_t> mFrecencyStatsSum;
+  mozilla::Atomic<uint64_t> mFrecencyStatsSumOfSquares;
+
+  void SaveFrecencyStats();
+
+//   static bool IsFrecencyDecaying();
+  bool IsFrecencyDecaying();
+
   /**
    * Store last insterted id for a table.
    */
   static mozilla::Atomic<int64_t> sLastInsertedPlaceId;
   static mozilla::Atomic<int64_t> sLastInsertedVisitId;
 
   static void StoreLastInsertedId(const nsACString& aTable,
                                   const int64_t aLastInsertedId);
@@ -645,16 +667,18 @@ protected:
   int32_t mDaysOfHistory;
   int64_t mLastCachedStartOfDay;
   int64_t mLastCachedEndOfDay;
 
   // Used to enable and disable the observer notifications
   bool mCanNotify;
   nsCategoryCache<nsINavHistoryObserver> mCacheObservers;
 
+  bool mIsFrecencyDecaying;
+
   // Used to cache the call to CryptAcquireContext, which is expensive
   // when called thousands of times
 #ifdef XP_WIN
   HCRYPTPROV mCryptoProvider;
   bool mCryptoProviderInitialized;
 #endif
 };
 
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -230,17 +230,17 @@ const EXPIRATION_QUERIES = {
           ) AND foreign_count = 0 AND last_visit_date ISNULL`,
     actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
              ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Hosts accumulated during the places delete are updated through a trigger
   // (see nsPlacesTriggers.h).
   QUERY_UPDATE_HOSTS: {
-    sql: `DELETE FROM moz_updatehostsdelete_temp`,
+    sql: `DELETE FROM moz_updateoriginsdelete_temp`,
     actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
              ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire orphan pages from the icons database.
   QUERY_EXPIRE_FAVICONS_PAGES: {
     sql: `DELETE FROM moz_pages_w_icons
           WHERE page_url_hash NOT IN (
--- a/toolkit/components/places/nsPlacesIndexes.h
+++ b/toolkit/components/places/nsPlacesIndexes.h
@@ -46,16 +46,21 @@
     "lastvisitdateindex", "moz_places", "last_visit_date", "" \
   )
 
 #define CREATE_IDX_MOZ_PLACES_GUID \
   CREATE_PLACES_IDX( \
     "guid_uniqueindex", "moz_places", "guid", "UNIQUE" \
   )
 
+#define CREATE_IDX_MOZ_PLACES_ORIGIN_ID \
+  CREATE_PLACES_IDX( \
+    "originidindex", "moz_places", "origin_id", "" \
+  )
+
 /**
  * moz_historyvisits
  */
 
 #define CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE \
   CREATE_PLACES_IDX( \
     "placedateindex", "moz_historyvisits", "place_id, visit_date", "" \
   )
@@ -66,16 +71,27 @@
   )
 
 #define CREATE_IDX_MOZ_HISTORYVISITS_VISITDATE \
   CREATE_PLACES_IDX( \
     "dateindex", "moz_historyvisits", "visit_date", "" \
   )
 
 /**
+ * moz_hosts
+ */
+
+#if 0
+#define CREATE_IDX_MOZ_HOSTS_HOST \
+  CREATE_PLACES_IDX( \
+    "hostindex", "moz_hosts", "host", "" \
+  )
+#endif
+
+/**
  * moz_bookmarks
  */
 
 #define CREATE_IDX_MOZ_BOOKMARKS_PLACETYPE \
   CREATE_PLACES_IDX( \
     "itemindex", "moz_bookmarks", "fk, type", "" \
   )
 
--- a/toolkit/components/places/nsPlacesTables.h
+++ b/toolkit/components/places/nsPlacesTables.h
@@ -2,48 +2,47 @@
  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #ifndef __nsPlacesTables_h__
 #define __nsPlacesTables_h__
 
-
 #define CREATE_MOZ_PLACES NS_LITERAL_CSTRING( \
     "CREATE TABLE moz_places ( " \
     "  id INTEGER PRIMARY KEY" \
     ", url LONGVARCHAR" \
     ", title LONGVARCHAR" \
     ", rev_host LONGVARCHAR" \
     ", visit_count INTEGER DEFAULT 0" \
     ", hidden INTEGER DEFAULT 0 NOT NULL" \
     ", typed INTEGER DEFAULT 0 NOT NULL" \
     ", frecency INTEGER DEFAULT -1 NOT NULL" \
     ", last_visit_date INTEGER " \
     ", guid TEXT" \
     ", foreign_count INTEGER DEFAULT 0 NOT NULL" \
     ", url_hash INTEGER DEFAULT 0 NOT NULL " \
     ", description TEXT" \
     ", preview_image_url TEXT" \
+    ", origin_id INTEGER REFERENCES moz_origins(id) ON DELETE CASCADE" \
   ")" \
 )
 
 #define CREATE_MOZ_HISTORYVISITS NS_LITERAL_CSTRING( \
   "CREATE TABLE moz_historyvisits (" \
     "  id INTEGER PRIMARY KEY" \
     ", from_visit INTEGER" \
     ", place_id INTEGER" \
     ", visit_date INTEGER" \
     ", visit_type INTEGER" \
     ", session INTEGER" \
   ")" \
 )
 
-
 #define CREATE_MOZ_INPUTHISTORY NS_LITERAL_CSTRING( \
   "CREATE TABLE moz_inputhistory (" \
     "  place_id INTEGER NOT NULL" \
     ", input LONGVARCHAR NOT NULL" \
     ", use_count INTEGER" \
     ", PRIMARY KEY (place_id, input)" \
   ")" \
 )
@@ -131,53 +130,80 @@
   "CREATE TABLE moz_keywords (" \
     "  id INTEGER PRIMARY KEY AUTOINCREMENT" \
     ", keyword TEXT UNIQUE" \
     ", place_id INTEGER" \
     ", post_data TEXT" \
   ")" \
 )
 
+#define CREATE_MOZ_PREFIXES NS_LITERAL_CSTRING( \
+  "CREATE TABLE moz_prefixes ( " \
+    "id INTEGER PRIMARY KEY, " \
+    "prefix TEXT NOT NULL UNIQUE " \
+  ")" \
+)
+
 #define CREATE_MOZ_HOSTS NS_LITERAL_CSTRING( \
-  "CREATE TABLE moz_hosts (" \
-    "  id INTEGER PRIMARY KEY" \
-    ", host TEXT NOT NULL UNIQUE" \
-    ", frecency INTEGER" \
-    ", typed INTEGER NOT NULL DEFAULT 0" \
-    ", prefix TEXT" \
+  "CREATE TABLE moz_hosts ( " \
+    "id INTEGER PRIMARY KEY, " \
+    "host TEXT NOT NULL UNIQUE " \
   ")" \
 )
 
+#define CREATE_MOZ_ORIGINS NS_LITERAL_CSTRING( \
+  "CREATE TABLE moz_origins ( " \
+    "id INTEGER PRIMARY KEY, " \
+    "prefix_id INTEGER REFERENCES moz_prefixes(id) ON DELETE CASCADE, " \
+    "host_id INTEGER REFERENCES moz_hosts(id) ON DELETE CASCADE, " \
+    "UNIQUE (prefix_id, host_id) " \
+  ")" \
+)
+
+#define CREATE_MOZ_AUTOFILL_ORIGINS NS_LITERAL_CSTRING( \
+  "CREATE TABLE moz_autofill_origins ( " \
+    "origin_id INTEGER PRIMARY KEY REFERENCES moz_origins(id) ON DELETE CASCADE, " \
+    "prefix TEXT NOT NULL, " \
+    "host TEXT NOT NULL, " \
+    "frecency INTEGER NOT NULL " \
+  ") " \
+  "WITHOUT ROWID" \
+)
+
 // Note: this should be kept up-to-date with the definition in
 //       nsPlacesAutoComplete.js.
 #define CREATE_MOZ_OPENPAGES_TEMP NS_LITERAL_CSTRING( \
   "CREATE TEMP TABLE moz_openpages_temp (" \
     "  url TEXT" \
     ", userContextId INTEGER" \
     ", open_count INTEGER" \
     ", PRIMARY KEY (url, userContextId)" \
   ")" \
 )
 
 // This table is used, along with moz_places_afterdelete_trigger, to update
 // hosts after places removals. During a DELETE FROM moz_places, hosts are
-// accumulated into this table, then a DELETE FROM moz_updatehostsdelete_temp
+// accumulated into this table, then a DELETE FROM moz_updateoriginsdelete_temp
 // will take care of updating the moz_hosts table for every modified host. See
 // CREATE_PLACES_AFTERDELETE_TRIGGER in nsPlacestriggers.h for details.
-#define CREATE_UPDATEHOSTSDELETE_TEMP NS_LITERAL_CSTRING( \
-  "CREATE TEMP TABLE moz_updatehostsdelete_temp (" \
-    "  host TEXT PRIMARY KEY " \
+#define CREATE_UPDATEORIGINSDELETE_TEMP NS_LITERAL_CSTRING( \
+  "CREATE TEMP TABLE moz_updateoriginsdelete_temp ( " \
+    "origin_id INTEGER PRIMARY KEY, " \
+    "host TEXT " \
   ") WITHOUT ROWID " \
 )
 
-// This table is used in a similar way to moz_updatehostsdelete_temp, but for
+// This table is used in a similar way to moz_updateoriginsdelete_temp, but for
 // inserts, and triggered via moz_places_afterinsert_trigger.
-#define CREATE_UPDATEHOSTSINSERT_TEMP NS_LITERAL_CSTRING( \
-  "CREATE TEMP TABLE moz_updatehostsinsert_temp (" \
-    "  host TEXT PRIMARY KEY " \
+#define CREATE_UPDATEORIGINSINSERT_TEMP NS_LITERAL_CSTRING( \
+  "CREATE TEMP TABLE moz_updateoriginsinsert_temp ( " \
+    "place_id INTEGER PRIMARY KEY, " \
+    "prefix TEXT NOT NULL, " \
+    "host TEXT NOT NULL, " \
+    "frecency INTEGER NOT NULL " \
   ") WITHOUT ROWID " \
 )
 
 // This table would not be strictly needed for functionality since it's just
 // mimicking moz_places, though it's great for database portability.
 // With this we don't have to take care into account a bunch of database
 // mismatch cases, where places.sqlite could be mixed up with a favicons.sqlite
 // created with a different places.sqlite (not just in case of a user messing
--- a/toolkit/components/places/nsPlacesTriggers.h
+++ b/toolkit/components/places/nsPlacesTriggers.h
@@ -43,177 +43,276 @@
       "visit_count = visit_count - (SELECT OLD.visit_type NOT IN (" EXCLUDED_VISIT_TYPES ")), "\
       "last_visit_date = (SELECT visit_date FROM moz_historyvisits " \
                          "WHERE place_id = OLD.place_id " \
                          "ORDER BY visit_date DESC LIMIT 1) " \
     "WHERE id = OLD.place_id;" \
   "END" \
 )
 
-/**
- * A predicate matching pages on rev_host, based on a given host value.
- * 'host' may be either the moz_hosts.host column or an alias representing an
- * equivalent value.
- */
-#define HOST_TO_REVHOST_PREDICATE \
-  "rev_host = get_unreversed_host(host || '.') || '.' " \
-  "OR rev_host = get_unreversed_host(host || '.') || '.www.'"
-
-#define OLDHOST_TO_REVHOST_PREDICATE \
-  "rev_host = get_unreversed_host(OLD.host || '.') || '.' " \
-  "OR rev_host = get_unreversed_host(OLD.host || '.') || '.www.'"
-
-/**
- * Select the best prefix for a host, based on existing pages registered for it.
- * Prefixes have a priority, from the top to the bottom, so that secure pages
- * have higher priority, and more generically "www." prefixed hosts come before
- * unprefixed ones.
- * Given a host, examine associated pages and:
- *  - if at least half the typed pages start with https://www. return https://www.
- *  - if at least half the typed pages start with https:// return https://
- *  - if all of the typed pages start with ftp: return ftp://
- *     - This is because mostly people will want to visit the http version
- *       of the site.
- *  - if at least half the typed pages start with www. return www.
- *  - otherwise don't use any prefix
- */
-#define HOSTS_PREFIX_PRIORITY_FRAGMENT \
-  "SELECT CASE " \
-    "WHEN ( " \
-      "SELECT round(avg(substr(url,1,12) = 'https://www.')) FROM moz_places h " \
-      "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \
-    ") THEN 'https://www.' " \
-    "WHEN ( " \
-      "SELECT round(avg(substr(url,1,8) = 'https://')) FROM moz_places h " \
-      "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \
-    ") THEN 'https://' " \
-    "WHEN 1 = ( " \
-      "SELECT min(substr(url,1,4) = 'ftp:') FROM moz_places h " \
-      "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \
-    ") THEN 'ftp://' " \
-    "WHEN ( " \
-      "SELECT round(avg(substr(url,1,11) = 'http://www.')) FROM moz_places h " \
-      "WHERE (" HOST_TO_REVHOST_PREDICATE ") AND +h.typed = 1 " \
-    ") THEN 'www.' " \
-  "END "
-
 // The next few triggers are a workaround for the lack of FOR EACH STATEMENT in
 // Sqlite, until bug 871908 can be fixed properly.
 // While doing inserts or deletes into moz_places, we accumulate the affected
-// hosts into a temp table. Afterwards, we delete everything from the temp
+// origins into a temp table. Afterwards, we delete everything from the temp
 // table, causing the AFTER DELETE trigger to fire for it, which will then
-// update the moz_hosts table.
+// update origin-related tables.
 // Note this way we lose atomicity, crashing between the 2 queries may break the
-// hosts table coherency. So it's better to run those DELETE queries in a single
+// tables' coherency. So it's better to run those DELETE queries in a single
 // transaction.
 // Regardless, this is still better than hanging the browser for several minutes
 // on a fast machine.
 #define CREATE_PLACES_AFTERINSERT_TRIGGER NS_LITERAL_CSTRING( \
   "CREATE TEMP TRIGGER moz_places_afterinsert_trigger " \
   "AFTER INSERT ON moz_places FOR EACH ROW " \
   "BEGIN " \
     "SELECT store_last_inserted_id('moz_places', NEW.id); " \
-    "INSERT OR IGNORE INTO moz_updatehostsinsert_temp (host)" \
-    "VALUES (fixup_url(get_unreversed_host(NEW.rev_host)));" \
+    "INSERT OR IGNORE INTO moz_updateoriginsinsert_temp (place_id, prefix, host, frecency) " \
+    "VALUES (NEW.id, get_prefix(NEW.url), get_host_and_port(NEW.url), NEW.frecency); " \
   "END" \
 )
 
 // See CREATE_PLACES_AFTERINSERT_TRIGGER. For each delete in moz_places we
-// add the host to moz_updatehostsdelete_temp - we then delete everything
-// from moz_updatehostsdelete_temp, allowing us to run a trigger only once
-// per host.
+// add the origin to moz_updateoriginsdelete_temp - we then delete everything
+// from moz_updateoriginsdelete_temp, allowing us to run a trigger only once
+// per origin.
 #define CREATE_PLACES_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
   "CREATE TEMP TRIGGER moz_places_afterdelete_trigger " \
   "AFTER DELETE ON moz_places FOR EACH ROW " \
   "BEGIN " \
-    "INSERT OR IGNORE INTO moz_updatehostsdelete_temp (host)" \
-    "VALUES (fixup_url(get_unreversed_host(OLD.rev_host)));" \
+    "INSERT OR IGNORE INTO moz_updateoriginsdelete_temp (origin_id, host) " \
+    "VALUES ( " \
+      "OLD.origin_id, " \
+      "( " \
+        "SELECT host " \
+        "FROM moz_hosts " \
+        "JOIN moz_origins ON host_id = moz_hosts.id " \
+        "WHERE moz_origins.id = OLD.origin_id " \
+      ") " \
+    "); " \
+    "SELECT update_frecency_stats(OLD.frecency, -1, OLD.id); " \
   "END" \
 )
 
+
+
 // See CREATE_PLACES_AFTERINSERT_TRIGGER. This is the trigger that we want
-// to ensure gets run for each distinct host that we insert into moz_places.
-#define CREATE_UPDATEHOSTSINSERT_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
-  "CREATE TEMP TRIGGER moz_updatehostsinsert_afterdelete_trigger " \
-  "AFTER DELETE ON moz_updatehostsinsert_temp FOR EACH ROW " \
+// to ensure gets run for each origin that we insert into moz_places.
+#if 0
+#define CREATE_UPDATEORIGINSINSERT_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_updateoriginsinsert_afterdelete_trigger " \
+  "AFTER DELETE ON moz_updateoriginsinsert_temp FOR EACH ROW " \
   "BEGIN " \
-    "INSERT OR REPLACE INTO moz_hosts (id, host, frecency, typed, prefix) " \
-    "SELECT " \
-        "(SELECT id FROM moz_hosts WHERE host = OLD.host), " \
-        "OLD.host, " \
-        "MAX(IFNULL((SELECT frecency FROM moz_hosts WHERE host = OLD.host), -1), " \
-          "(SELECT MAX(frecency) FROM moz_places h " \
-            "WHERE (" OLDHOST_TO_REVHOST_PREDICATE "))), " \
-        "MAX(IFNULL((SELECT typed FROM moz_hosts WHERE host = OLD.host), 0), " \
-          "(SELECT MAX(typed) FROM moz_places h " \
-            "WHERE (" OLDHOST_TO_REVHOST_PREDICATE "))), " \
-        "(" HOSTS_PREFIX_PRIORITY_FRAGMENT \
-         "FROM ( " \
-            "SELECT OLD.host AS host " \
-          ")" \
+    "INSERT OR IGNORE INTO moz_prefixes (prefix) VALUES (OLD.prefix); " \
+    "INSERT OR IGNORE INTO moz_hosts (host) VALUES (OLD.host); " \
+    "INSERT OR IGNORE INTO moz_origins (prefix_id, host_id) VALUES ( " \
+      "(SELECT id FROM moz_prefixes WHERE prefix = OLD.prefix), " \
+      "(SELECT id FROM moz_hosts WHERE host = OLD.host) " \
+    "); " \
+    "UPDATE moz_places SET origin_id = ( " \
+      "SELECT moz_origins.id " \
+      "FROM moz_origins " \
+      "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+      "JOIN moz_hosts ON moz_hosts.id = host_id " \
+      "WHERE prefix = OLD.prefix AND host = OLD.host " \
+    ") " \
+    "WHERE id = OLD.place_id; " \
+    "INSERT OR IGNORE INTO moz_autofill_origins (origin_id, prefix, host, frecency) " \
+    "VALUES ( " \
+      "( " \
+        "SELECT moz_origins.id " \
+        "FROM moz_origins " \
+        "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+        "JOIN moz_hosts ON moz_hosts.id = host_id " \
+        "WHERE prefix = OLD.prefix AND host = OLD.host " \
+      "), " \
+      "OLD.prefix, " \
+      "OLD.host, " \
+      "( " \
+        "SELECT MAX(frecency) FROM moz_places WHERE origin_id = ( " \
+          "SELECT moz_origins.id " \
+          "FROM moz_origins " \
+          "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+          "JOIN moz_hosts ON moz_hosts.id = host_id " \
+          "WHERE prefix = OLD.prefix AND host = OLD.host " \
         ") " \
-    " WHERE LENGTH(OLD.host) > 1; " \
+      ") " \
+    "); " \
+  "END" \
+)
+#endif
+
+//XXXadw the "UPDATE moz_autofill_origins " at the end needs to happen because
+// when moz_places_afterupdate_frecency_trigger is called, its NEW.origin_id can
+// be null, so the frecency of the relevant row in moz_autofill_origins isn't
+// updated.  run browser_autocomplete_enter_race.js to see.  that's how i found
+// this.
+#define CREATE_UPDATEORIGINSINSERT_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_updateoriginsinsert_afterdelete_trigger " \
+  "AFTER DELETE ON moz_updateoriginsinsert_temp FOR EACH ROW " \
+  "BEGIN " \
+    "INSERT OR IGNORE INTO moz_prefixes (prefix) VALUES (OLD.prefix); " \
+    "INSERT OR IGNORE INTO moz_hosts (host) VALUES (OLD.host); " \
+    "INSERT OR IGNORE INTO moz_origins (prefix_id, host_id) VALUES ( " \
+      "(SELECT id FROM moz_prefixes WHERE prefix = OLD.prefix), " \
+      "(SELECT id FROM moz_hosts WHERE host = OLD.host) " \
+    "); " \
+    "UPDATE moz_places SET origin_id = ( " \
+      "SELECT moz_origins.id " \
+      "FROM moz_origins " \
+      "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+      "JOIN moz_hosts ON moz_hosts.id = host_id " \
+      "WHERE prefix = OLD.prefix AND host = OLD.host " \
+    ") " \
+    "WHERE id = OLD.place_id; " \
+    "INSERT OR IGNORE INTO moz_autofill_origins (origin_id, prefix, host, frecency) " \
+    "VALUES ( " \
+      "( " \
+        "SELECT moz_origins.id " \
+        "FROM moz_origins " \
+        "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+        "JOIN moz_hosts ON moz_hosts.id = host_id " \
+        "WHERE prefix = OLD.prefix AND host = OLD.host " \
+      "), " \
+      "OLD.prefix, " \
+      "OLD.host, " \
+      "( " \
+        "SELECT MAX(frecency) FROM moz_places WHERE origin_id = ( " \
+          "SELECT moz_origins.id " \
+          "FROM moz_origins " \
+          "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+          "JOIN moz_hosts ON moz_hosts.id = host_id " \
+          "WHERE prefix = OLD.prefix AND host = OLD.host " \
+        ") " \
+      ") " \
+    "); " \
+    "UPDATE moz_autofill_origins " \
+    "SET frecency = ( " \
+      "SELECT MAX(frecency) FROM moz_places WHERE origin_id = ( " \
+        "SELECT moz_origins.id " \
+        "FROM moz_origins " \
+        "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+        "JOIN moz_hosts ON moz_hosts.id = host_id " \
+        "WHERE prefix = OLD.prefix AND host = OLD.host " \
+      ") "\
+    ") " \
+    "WHERE origin_id = ( " \
+      "SELECT moz_origins.id " \
+      "FROM moz_origins " \
+      "JOIN moz_prefixes ON moz_prefixes.id = prefix_id " \
+      "JOIN moz_hosts ON moz_hosts.id = host_id " \
+      "WHERE prefix = OLD.prefix AND host = OLD.host " \
+    "); " \
   "END" \
 )
 
+
+
 // See CREATE_PLACES_AFTERINSERT_TRIGGER. This is the trigger that we want
-// to ensure gets run for each distinct host that we delete from moz_places.
-#define CREATE_UPDATEHOSTSDELETE_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
-  "CREATE TEMP TRIGGER moz_updatehostsdelete_afterdelete_trigger " \
-  "AFTER DELETE ON moz_updatehostsdelete_temp FOR EACH ROW " \
+// to ensure gets run for each origin that we delete from moz_places.
+#if 0
+#define CREATE_UPDATEORIGINSDELETE_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_updateoriginsdelete_afterdelete_trigger " \
+  "AFTER DELETE ON moz_updateoriginsdelete_temp FOR EACH ROW " \
   "BEGIN " \
-    "DELETE FROM moz_hosts " \
-    "WHERE host = OLD.host " \
-      "AND NOT EXISTS(" \
-        "SELECT 1 FROM moz_places " \
-          "WHERE rev_host = get_unreversed_host(host || '.') || '.' " \
-             "OR rev_host = get_unreversed_host(host || '.') || '.www.' " \
-      "); " \
-    "UPDATE moz_hosts " \
-    "SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") " \
-    "WHERE host = OLD.host; " \
+    "DELETE FROM moz_origins " \
+    "WHERE id = OLD.origin_id AND NOT EXISTS( " \
+      "SELECT 1 FROM moz_places WHERE origin_id = OLD.origin_id " \
+    "); " \
     "DELETE FROM moz_icons " \
     "WHERE fixed_icon_url_hash = hash(fixup_url(OLD.host || '/favicon.ico')) " \
       "AND fixup_url(icon_url) = fixup_url(OLD.host || '/favicon.ico') "\
       "AND NOT EXISTS (SELECT 1 FROM moz_hosts WHERE host = OLD.host " \
                                                  "OR host = fixup_url(OLD.host));" \
   "END" \
 )
+#endif
 
-// For performance reasons the host frecency is updated only when the page
-// frecency changes by a meaningful percentage.  This is because the frecency
-// decay algorithm requires to update all the frecencies at once, causing a
-// too high overhead, while leaving the ordering unchanged.
+#if 0
+//XXXadw probably because i changed this to delete from moz_origins, not hosts,
+// and hosts is updated via a trigger, and that trigger doesn't run until after
+// this does.
+#define CREATE_UPDATEORIGINSDELETE_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_updateoriginsdelete_afterdelete_trigger " \
+  "AFTER DELETE ON moz_updateoriginsdelete_temp FOR EACH ROW " \
+  "BEGIN " \
+    "DELETE FROM moz_origins " \
+    "WHERE id = OLD.origin_id AND NOT EXISTS( " \
+      "SELECT 1 FROM moz_places WHERE origin_id = OLD.origin_id " \
+    "); " \
+    "DELETE FROM moz_icons " \
+    "WHERE fixed_icon_url_hash = hash(fixup_url(OLD.host || '/favicon.ico')) " \
+      "AND fixup_url(icon_url) = fixup_url(OLD.host || '/favicon.ico') "\
+      "AND NOT EXISTS (SELECT 1 FROM moz_hosts WHERE host = OLD.host " \
+                                                 "OR host = 'www.' || OLD.host);" \
+  "END" \
+)
+#endif
+
+#define CREATE_UPDATEORIGINSDELETE_AFTERDELETE_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_updateoriginsdelete_afterdelete_trigger " \
+  "AFTER DELETE ON moz_updateoriginsdelete_temp FOR EACH ROW " \
+  "BEGIN " \
+    "DELETE FROM moz_origins " \
+    "WHERE id = OLD.origin_id " \
+      "AND id NOT IN (SELECT origin_id FROM moz_places); " \
+    "DELETE FROM moz_hosts " \
+    "WHERE id NOT IN (SELECT host_id FROM moz_origins); " \
+    "DELETE FROM moz_prefixes " \
+    "WHERE id NOT IN (SELECT prefix_id FROM moz_origins); " \
+    "DELETE FROM moz_icons " \
+    "WHERE fixed_icon_url_hash = hash(fixup_url(OLD.host || '/favicon.ico')) " \
+      "AND fixup_url(icon_url) = fixup_url(OLD.host || '/favicon.ico') "\
+      "AND NOT EXISTS (SELECT 1 FROM moz_hosts WHERE host = OLD.host " \
+                                                 "OR host = fixup_url(OLD.host)); " \
+  "END" \
+)
+
+
+
+// This trigger keeps frecencies in the autofill_origins table in sync with
+// frecencies in moz_places.  However, we skip this when frecency changes are
+// due to frecency decay since (1) decay updates all frecencies at once, so this
+// trigger would run for each moz_place, which would be expensive; and (2) decay
+// does not change the ordering of frecencies since all frecencies decay by the
+// same percentage.
+
 #define CREATE_PLACES_AFTERUPDATE_FRECENCY_TRIGGER NS_LITERAL_CSTRING( \
   "CREATE TEMP TRIGGER moz_places_afterupdate_frecency_trigger " \
   "AFTER UPDATE OF frecency ON moz_places FOR EACH ROW " \
-  "WHEN NEW.frecency >= 0 " \
-    "AND ABS(" \
-      "IFNULL((NEW.frecency - OLD.frecency) / CAST(NEW.frecency AS REAL), " \
-             "(NEW.frecency - OLD.frecency))" \
-    ") > .05 " \
+  "WHEN NEW.frecency >= 0 AND NOT is_frecency_decaying() " \
   "BEGIN " \
-    "UPDATE moz_hosts " \
-    "SET frecency = (SELECT MAX(frecency) FROM moz_places " \
-                    "WHERE rev_host = get_unreversed_host(host || '.') || '.' " \
-                       "OR rev_host = get_unreversed_host(host || '.') || '.www.') " \
-    "WHERE host = fixup_url(get_unreversed_host(NEW.rev_host)); " \
+    "UPDATE moz_autofill_origins " \
+    "SET frecency = ( " \
+      "SELECT MAX(frecency) " \
+      "FROM moz_places " \
+      "WHERE moz_places.origin_id = moz_autofill_origins.origin_id " \
+    ") " \
+    "WHERE origin_id = NEW.origin_id; " \
+    "SELECT update_frecency_stats(OLD.frecency, NEW.frecency, NEW.id); " \
   "END" \
 )
 
-#define CREATE_PLACES_AFTERUPDATE_TYPED_TRIGGER NS_LITERAL_CSTRING( \
-  "CREATE TEMP TRIGGER moz_places_afterupdate_typed_trigger " \
-  "AFTER UPDATE OF typed ON moz_places FOR EACH ROW " \
-  "WHEN NEW.typed = 1 " \
+
+#if 0
+#define CREATE_PLACES_AFTERUPDATE_FRECENCY_TRIGGER NS_LITERAL_CSTRING( \
+  "CREATE TEMP TRIGGER moz_places_afterupdate_frecency_trigger " \
+  "AFTER UPDATE OF frecency ON moz_places FOR EACH ROW " \
+  "WHEN NEW.frecency >= 0 AND NOT is_frecency_decaying() " \
   "BEGIN " \
-    "UPDATE moz_hosts " \
-    "SET typed = 1 " \
-    "WHERE host = fixup_url(get_unreversed_host(NEW.rev_host)); " \
+    "UPDATE moz_autofill_origins " \
+    "SET frecency = ( " \
+      "SELECT MAX(frecency) " \
+      "FROM moz_places p " \
+      "WHERE p.origin_id = 11 " \
+    ") " \
+    "WHERE origin_id = NEW.origin_id; " \
+    "SELECT update_frecency_stats(OLD.frecency, NEW.frecency); " \
   "END" \
 )
+#endif
 
 /**
  * This trigger removes a row from moz_openpages_temp when open_count reaches 0.
  *
  * @note this should be kept up-to-date with the definition in
  *       nsPlacesAutoComplete.js
  */
 #define CREATE_REMOVEOPENPAGE_CLEANUP_TRIGGER NS_LITERAL_CSTRING( \
--- a/toolkit/components/places/tests/PlacesTestUtils.jsm
+++ b/toolkit/components/places/tests/PlacesTestUtils.jsm
@@ -90,16 +90,19 @@ this.PlacesTestUtils = Object.freeze({
     if (lastStoredVisit) {
       await TestUtils.waitForCondition(
         () => PlacesUtils.history.fetch(lastStoredVisit.url),
         "Ensure history has been updated and is visible to read-only connections"
       );
     }
   },
 
+//   async function removeVisits(placeInfo) {
+//   },
+
    /*
     * Add Favicons
     *
     * @param {Map} faviconURLs  keys are page URLs, values are their
     *                           associated favicon URLs.
     */
 
   async addFavicons(faviconURLs) {
--- a/toolkit/components/places/tests/favicons/test_root_icons.js
+++ b/toolkit/components/places/tests/favicons/test_root_icons.js
@@ -33,22 +33,57 @@ add_task(async function() {
   await PlacesTestUtils.addVisits("http://places.test/page2/");
   await PlacesUtils.history.remove(pageURI);
 
   // Still works since the icon has not been removed.
   Assert.equal(await getFaviconUrlForPage(pageURI), faviconURI.spec);
 
   // Remove all the pages for the given domain.
   await PlacesUtils.history.remove("http://places.test/page2/");
+
+//   await new Promise(r => {
+//     Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).init(r,
+//       1000, Ci.nsITimer.TYPE_ONE_SHOT);
+//   });
+
   // The icon should be removed along with the domain.
-  rows = await db.execute("SELECT * FROM moz_icons");
+//   rows = await db.execute("SELECT * FROM moz_icons");
+  rows = await db.execute("SELECT icon_url, fixup_url(icon_url) FROM moz_icons");
+  dump(`****XXXadw dumping moz_icons rows (${rows.length})...\n`);
+  for (let row of rows) {
+    dump(`  * ${row.getResultByIndex(0)} -- ${row.getResultByIndex(1)}\n`);
+  }
+
+//   let rows2 = await db.execute("SELECT host FROM moz_hosts");
+//   dump(`****XXXadw dumping moz_hosts rows (${rows2.length})...\n`);
+//   for (let row of rows2) {
+//     dump(`  * ${row.getResultByIndex(0)}\n`);
+//   }
+
+//   let rows2 = await db.execute("SELECT host FROM moz_orignhosts");
+//   dump(`****XXXadw dumping moz_hosts rows (${rows2.length})...\n`);
+//   for (let row of rows2) {
+//     dump(`  * ${row.getResultByIndex(0)}\n`);
+//   }
+
+  dump_table("moz_icons");
+  dump_table("moz_hosts");
+  dump_table("moz_origins");
+
   Assert.equal(rows.length, 0, "The icon should have been removed");
 });
 
 add_task(async function test_removePagesByTimeframe() {
+    dump("****************************XXXadw A\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_icons");
+    dump_table("moz_places");
+
   // Add a visit in the past with no directly associated icon.
   await PlacesTestUtils.addVisits({uri: "http://www.places.test/old/", visitDate: new Date(Date.now() - 86400000)});
   let pageURI = NetUtil.newURI("http://www.places.test/page/");
   await PlacesTestUtils.addVisits({uri: pageURI, visitDate: new Date(Date.now() - 7200000)});
   let faviconURI = NetUtil.newURI("http://www.places.test/page/favicon.ico");
   let rootIconURI = NetUtil.newURI("http://www.places.test/favicon.ico");
   PlacesUtils.favicons.replaceFaviconDataFromDataURL(
     faviconURI, SMALLSVG_DATA_URI.spec, 0, systemPrincipal);
@@ -60,40 +95,78 @@ add_task(async function test_removePages
   // Sanity checks.
   Assert.equal(await getFaviconUrlForPage(pageURI),
                faviconURI.spec, "Should get the biggest icon");
   Assert.equal(await getFaviconUrlForPage(pageURI, 1),
                rootIconURI.spec, "Should get the smallest icon");
   Assert.equal(await getFaviconUrlForPage("http://www.places.test/old/"),
                rootIconURI.spec, "Should get the root icon");
 
+    dump("****************************XXXadw B\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_icons");
+    dump_table("moz_places");
+
   PlacesUtils.history.removePagesByTimeframe(
     PlacesUtils.toPRTime(Date.now() - 14400000),
     PlacesUtils.toPRTime(new Date())
   );
 
+    dump("****************************XXXadw C\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_icons");
+    dump_table("moz_places");
+
   // Check database entries.
   await PlacesTestUtils.promiseAsyncUpdates();
   let db = await PlacesUtils.promiseDBConnection();
   let rows = await db.execute("SELECT * FROM moz_icons");
   Assert.equal(rows.length, 1, "There should only be 1 icon entry");
   Assert.equal(rows[0].getResultByName("root"), 1, "It should be marked as a root icon");
   rows = await db.execute("SELECT * FROM moz_pages_w_icons");
   Assert.equal(rows.length, 0, "There should be no page entry");
   rows = await db.execute("SELECT * FROM moz_icons_to_pages");
   Assert.equal(rows.length, 0, "There should be no relation entry");
 
   PlacesUtils.history.removePagesByTimeframe(0, PlacesUtils.toPRTime(new Date()));
   await PlacesTestUtils.promiseAsyncUpdates();
+
+
+    dump("****************************XXXadw D\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_icons");
+    dump_table("moz_places");
+
+//   await new Promise(r => {
+//     Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).init(r,
+//       1000, Ci.nsITimer.TYPE_ONE_SHOT);
+//   });
+
+    dump("****************************XXXadw E\n");
+    dump_table("moz_origins");
+    dump_table("moz_prefixes");
+    dump_table("moz_hosts");
+    dump_table("moz_icons");
+    dump_table("moz_places");
+
   rows = await db.execute("SELECT * FROM moz_icons");
   // Debug logging for possible intermittent failure (bug 1358368).
-  if (rows.length != 0) {
-    dump_table("moz_icons");
-    dump_table("moz_hosts");
-  }
+//   if (rows.length != 0) {
+//     dump_table("moz_icons");
+//     dump_table("moz_hosts");
+//     dump_table("moz_origins");
+//     dump_table("moz_prefixes");
+//     dump_table("moz_places");
+//   }
   Assert.equal(rows.length, 0, "There should be no icon entry");
 });
 
 add_task(async function test_different_host() {
   let pageURI = NetUtil.newURI("http://places.test/page/");
   await PlacesTestUtils.addVisits(pageURI);
   let faviconURI = NetUtil.newURI("http://mozilla.test/favicon.ico");
   PlacesUtils.favicons.replaceFaviconDataFromDataURL(
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -1,17 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 // It is expected that the test files importing this file define Cu etc.
 /* global Cu, Ci, Cc, Cr */
 
-const CURRENT_SCHEMA_VERSION = 41;
+const CURRENT_SCHEMA_VERSION = 42;
 const FIRST_UPGRADABLE_SCHEMA_VERSION = 30;
 
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
 
 // Shortcuts to transitions type.
 const TRANSITION_LINK = Ci.nsINavHistoryService.TRANSITION_LINK;
 const TRANSITION_TYPED = Ci.nsINavHistoryService.TRANSITION_TYPED;
@@ -942,8 +942,56 @@ function mapItemIdToInternalRootName(aIt
       return "toolbarFolder";
     case PlacesUtils.unfiledBookmarksFolderId:
       return "unfiledBookmarksFolder";
     case PlacesUtils.mobileFolderId:
       return "mobileFolder";
   }
   return null;
 }
+
+
+// async function cleanup() {
+//   Services.prefs.clearUserPref("browser.urlbar.autocomplete.enabled");
+//   Services.prefs.clearUserPref("browser.urlbar.autoFill");
+//   Services.prefs.clearUserPref("browser.urlbar.autoFill.typed");
+//   Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines");
+//   let suggestPrefs = [
+//     "history",
+//     "bookmark",
+//     "history.onlyTyped",
+//     "openpage",
+//     "searches",
+//   ];
+//   for (let type of suggestPrefs) {
+//     Services.prefs.clearUserPref("browser.urlbar.suggest." + type);
+//   }
+//   Services.prefs.clearUserPref("browser.search.suggest.enabled");
+//   await PlacesUtils.bookmarks.eraseEverything();
+//   await PlacesTestUtils.clearHistory();
+// }
+// registerCleanupFunction(cleanup);
+
+var addBookmark = async function(aBookmarkObj) {
+  Assert.ok(!!aBookmarkObj.uri, "Bookmark object contains an uri");
+  let parentId = aBookmarkObj.parentId ? aBookmarkObj.parentId
+                                       : PlacesUtils.unfiledBookmarksFolderId;
+
+  let bm = await PlacesUtils.bookmarks.insert({
+    parentGuid: (await PlacesUtils.promiseItemGuid(parentId)),
+    title: aBookmarkObj.title || "A bookmark",
+    url: aBookmarkObj.uri
+  });
+  await PlacesUtils.promiseItemId(bm.guid);
+
+  if (aBookmarkObj.keyword) {
+    await PlacesUtils.keywords.insert({ keyword: aBookmarkObj.keyword,
+                                        url: aBookmarkObj.uri.spec,
+                                        postData: aBookmarkObj.postData
+                                      });
+  }
+
+  if (aBookmarkObj.tags) {
+    PlacesUtils.tagging.tagURI(aBookmarkObj.uri, aBookmarkObj.tags);
+  }
+
+  return bm;
+};
new file mode 100644
index 0000000000000000000000000000000000000000..122e7d5233c33fd4b43be4c6a34df3d02f937b8e
GIT binary patch
literal 5242880
zc%1CreUO~zK^X9Nzi;n+*4d7^IF9Wzwrn4=PL?HEl2c*J(ph%&8QsaYRGVY(ZgscP
z-tBpJPtqxt9xF+wGmKl>lz|4ykWQLrJdjjS;tVZmDGU@+$~U2q63V2IFhGDf;F9K#
zzPo#O+WV5oOj{-P?>D#a^FH5S@5kQ#b3^YrP^uUEPFAW@g?itX=;bJxj2`dni=rqQ
zf9{X2xGVmo+v17%^BvLEC8L42|6+IeU(tP~?NQhl{^P}ug|}V!^_M<-{=c7}I-i~U
z!MP3Re)Qayvp;v{Z_kX({_gBh{rK$7)xW4_tN-f7fA-?rW?r62RxV6`q_TJVJyZXt
z{M%ELr+@VHZKco0jR61v00000000000000000000000000002rYA)S-U#|B(8xog}
zm!`*y=cX#>M@seLRBfa%Jzc3a&kOZ>wKO_gFRoVN{yj$rcMlKt9Xs^&dyWnEJ$-2J
z;B$S~Zl&+=q2;Ce9%w{HO5+dqHR2<S72>4+_w87p>)o&+@qzp6h0$_xS=D9H`{u_q
zy!(j*gDbn~>nn}N105dRH+Zz~$kC?{?ml|FZ~x%&2m9s+u$X!1@NnOuV+RhbGNOet
z5B7~!rt8J&df$P=hxR?Q`{<shcE^b)%Y}*BVmo^WpWJ=yz;NF~5B3$$&6KKzdZ{wK
zT5f%Arnp-Ac%fe0Jw9F>UoEp-sMQZv#!DwltL67!T6b@*ci&x!OM{F1*V>hta$&5v
za&w!R>(|=WHLEV{==>r#ORTk-_urH2z3Z;T2kuzh%*AbNp4_`)1FyMt3;n&x_O9pd
zT<?}GiA(#Itkjj+)K*FQ_ElG}t-#gRak?;7?3-VT2ev%izi<UCENB1Vw`Y5gZ%IVW
zO|QLJj_;X~!fd_LjE}6++sNis67RWmS6{C8`1-`9gNqm5>EhhkN_Bkx>YAz4>haPQ
zMrNl=FU}TMl)8JZEA-mUEL^G!CEKsoM){FOh5jRVWgAbN<IR<ypJ=TZw=q4oJleNp
z#g}D1&{)z3<5>TtJMYN#u8-#&7I$-D2<_*0uGqgT16^z5`gR{1KK%5dxaPsZL&FdD
z&DZD~9(-<ieu-AzBW<&77VO`CXSR3$`m62j;^J;@kKJ`C`OaML)AuJX-MzR^qm|0(
zsY3O1ZDeA$G`@Tn7jy4eYa7?Dzp#CaCHfv{6zPBI_FV5^Jcip=8AIbHEHrMym3i-+
zAHix}FRivp$BQ?2|D~JWk?S3byWh4-_l*}z<5r)VztvY3x&11mShe;lgE@J6=>w(z
z!fm<U$JW@DnL;&w@~zBx$5jT>R%ey&Te;1Ps?>N$_P_Y{T<^Q$?z`7mk(J4}U1Jrl
zHuJ{wxBt@Z-<Ip$zCCg2*y1hLwwuLrv0fZsHL-WaO}C;*<L+x*Xsw%S$y2j&861s!
zJ5yZw0&07lKi!+{ePR36?ynV{wr;c)$!~w(#I3pB`|nTugYK0RT@v}WwI_D9_dxsG
zEPf@PUh#5jy<1y*zT|;YYJWk-4VCKU;?fuF{9|LuljvlnJYKAhG`nrA?<()j)!&v6
zUfGie`)YI3V?*^qeYSR$ZD<wSGg+9PDDJ7u#@_&{YnR^Kf9a81a=jZjCf;|~m9L)D
zGqd%{QmtO8&Ml9>ZRMBGw%o>&U*)SxvuOKbwdKv$iX&r<;a-_}`wO7$9oB56zyGnf
zWqXG<UhQgYA6e@{YfriLQtIYh@19NV&yV@6Go^T&TaU-pvu;^&Bd<|&;bvZv-S<E<
zY?kW3l)CBaqc~ZuOs$@E^EF1XSaXe0H1bE9k^W1)J-Ob4@hBc!V-(HhUwc7ry2enJ
zR$pU0SGKr)efF)(^={gfc;BwY>vKu96$w2nuFz%Oto>BDvLJ1@{EBZCR|dB{ZRt~`
zR;<<9o)!JmH|BbG-JQ79wYY@MwreAmYH6Z0T^e7OzHY^uu2z0wEn9hg5418HzlWUZ
zjxVgZzgw60x7s(BR@RMceO+0j=JL*)UsNvM5dT7Ucl!lBU%T;qYcAB1>!_94z1Cz`
zR$AU^qr^zt6*JY<TIc-o{!dnmWARtkxn=1$tkw0B^2>W&$m~DW8NZTO>#jMZ<|FM&
zV%J)IT`9c0qt?utS^dR)u6JA9S7Lczlkqp*Woeyjb+uS_c~8~inPz7HRL2@CI9n}`
zOcrXB%hK~}b+x4Y^6nNg``>>ym+QUz?!-Ubxp<4W%3L|?SaDM?w9>cs?HqTo^v%4=
z%X(qXOH<p{e6?R|Crj~*dzIgk+g@jlN5Lw;^0t*&xPVp^+PJx`)Uu0vvG9`b1t%-j
zVrgP}tpT^cW#`xYDuv>v$BVVGYH6nVO{dkvOuSB|;@OeXRAHjn*w*><#iz|;gGUFS
z96UOBXwTqKbDLTPY7fNEg~tBx9Xv1?Z{wcbLwk1b9qhk!E*oFa+Y;};<;oub;#c^|
zQn|cPbG5YG%0B@tD-mB8D~Hzpec~G#W^?){OXphOjIS(a^SW7<wqjQom$kp|*{6q}
zI(%%n@95!YpWb_ED3j~G=bps-rWU8(Hskrz?23tAnctd!Dr%1PDqGSjP+W7ejcHw_
zdLw&{x_$kpQ_VkpU0Q$TW!)&gc#>ZEa&9DFWjZStdExEUzd4=l9lYym-vFD9x4!x{
zPcvr{tv^w0y7Hu%Uyb(j<jSYbe9kr3eT|`RPhRU!4+}lCM!OJ8MN!nz_(OJg{7Hr1
zkHYKWOK|`I00000000000000000000000000000000000003`3`BW;pZKhlpD?XY}
z#;1kR%5447u0$%jW3pbKsXe-BQ)gT(6+Rz@KM7xr0{{R300000000000000000000
z000000000000000coXVO-Ikas7siT@rW&V((aLQ7(PUTZj{Ic3K2v*i)28mYR6aZ!
zg)fB9gv;SW;U9&IVImC0NdN!<00000000000000000000000000000000000@ORLg
zPet2mm1=$0j{Bwx=Z+R@v*mhi*XD<A?np%&&YnFxFjYBUDwhibmFmQ;xm2`yrd*gV
z*4vZ2v#IFrsnY0ZsXj1Pnd;1>qT9!+h1z7Xc56DWQ5YYuOxN0LygikQwvQLj6w8&F
zVzoV|HyMv-batYZ(3Wv~A{Ff#EmtN6rb`o(_3~VMW@kK;e0WzBelYyc@L$3|4nH13
zm<;a<!`FL#0RR910000000000000000000000000000000002^7V-AfwnVK`t?$}#
z-&En;(PC}3T(9lg{80Xu)P}^_vu6jUD(6e(a$%rSo#^<s)aJxYxiDR<w<qUrOx>NB
zDvgeo>H}kysccv3_QY7VP@62)GL0IA@$t%Zt-VJ2w$%2-c=1fJT$w3W+jCNl@r=$+
zv=Z7flDDUJ<wwhviGk_T#ALlZ*PhuOPoyjSL=?UjUJrj3{wVx@_-y#q@QdL;g`bL(
z0RR910000000000000000000000000000000002sn^dMN9pw`p+0Jy7NTl+ad^4Kq
zXa%`OkjrEnK{lIdlu2eX=|(i2Ni~90CfNv*=|mjlJHuU3{^Cz2FaCA-T=-=8V0bAM
z!gpT$?TbHoz2^x4000000000000000000000000000000000000Km2MWfHe->*$;*
z7siT@)+*Kdt{wMH70w+k)@IA~+OEwH-IYn)u_4(pS+CF39^JI*?AfyeQ<d|ja=9>2
zsZK<%+@Hzcu`9WdJzB0z3{00MChO(7rRAEv-F20be0$u{=45W6rFcZs#ro1V-VqnM
zJDFW5GF2KKE!79cDpS!bx5o3hJ(($tR%Yvuj#Ue_$zm;frPXG7p+aGNyfR%|+UEMW
z$o6Dvp~!ggOtD;<DOQ)3x;HMhEqP^{vlFe%C55_QnuxmIyDfU@7cS;5{AjrE!s8cT
zyI6SdzkDh2(g)&X00000000000000000000000000000000000006kQQ(Zk#DcYFt
z=tyMOcVwa{vBtj|-&CC5cx-6XOto~TFgCa8WT{#_Svj|9qFNa!l*^^_m8pS7jqxZm
z`uydcue~w2dCSoqCr%CRJ219&!_6l@x$}6(cXjkcBhki=j*eusK7Z}L#wyeGYH4(~
zUR=>l^vdZ+%BP+w?i(K2HZl^o{~I5EZ^wAPCwd{COa7X3xz;RhYtCZFtHU#Ap4_+b
ziMgkqn64h#aC3Iu2j@C2+!x)k=5jvX*%R%K)^)_|8BZ}A4`J<p?LKh6THJf+-7iia
z*>YfG6n%B;BcFTq2Rgqi(Gwkx9=ozg`D^`i_a&pBE7vC{O49=qmGWr3N<$mB&mKAb
z^w{>vV-Ih*`4eBi^w|q%qj#)6_HCJ-=>B-@t)3fWU-IwV<JR_Xd#JE?XwTsIw&@d5
z^dlerc;C-n&V-LfTffn(?nJ65dOF(K>MGH`Q>*?1_$4!}7H2BuxYT$&puJPG&pmT+
zW~#nr@>p`i%^&%`$xo!7OZG(jqV21+z1qKxU($3loS1Dc+}YB>iQ$LqTTbjAj9dP#
zFQ0lLIh5;(_C#A&xqjnKo-WqcY`0#VE|h2DR-Za`;>Ft7!MWLUQ}K2jx^U~gx#{dp
z(WP8;&nm4>l}1NP^?|X<)TYO3#p;=2byul6*51o~W0QsH>0)`;`iHm7Ul~)Cv4MJ{
z;#Az<@S(z);_Sf#W0le24L3h_{GH#Cy^xOkyLHuB6voFZ)3sG@#D&|WSzyzAM;q(K
zTD@4^Sg%ydwI$Q7O;^Up3vu_)9XUHOcH+c|u@f`rHr)KmLr)E+<IVs3-{{rychnhw
zy21yd@Grur!%u_{gpY;a4*w(kP59IBi{X3!A9V@<0000000000000000000000000
z00000000000067#Ol1-qZa(?RoyWUwNM#dI^wq78eD2jB=xn8D*L`p<KVRfGKK$N}
z*6E=Ox89p;oj!K_o!^mdRs4~Ue!TBzFK1fmuRQeBV7hhsk?))QM5=ZATVFo)LNcGq
z<Tu>>iLYP!Y-ikmSGXq%|0L`PzZ5<ZzCTQcq41sIp74e6^7URB000000000000000
z000000000000000000000002KiM%bfF)>lC3>3=c()r5Nz}d5B2f8w;b%}w_)w1%d
zC3f_twk%1k7pDv5nStE8)IEu*%Gf}?G&)+E8pt-=%`7ino34zH7Y5SrNbOvbUM<d4
z%EdFq@qyHBsqIU$n&HIk=s@zFsmJo|IdkRu<V0zDV4_kU9q5cF*cCn#g|CM<!dJqd
zhcAUMgwKcH4Zj+GD^3Og000000000000000000000000000000000000Dx~X=~O<^
zl}>deIvZ#C##u+>kZT;WjYFn!NH-3t#vz$Xb>utanqA??bK&R1e+WMwem(qc_)7Rp
z_)_@8@O$A?*LzL?00000000000000000000000000000000000006LtOe&EW@5-i<
ziRhJ%M&!19lumUdI$KHUOe&d=UWp5~;<;9kZ3UUd^i(TIcE%}P;on8!>*0;?mGI}`
zOW_OQ^Wk^He-6JKCj$Tg00000000000000000000000000000000000z&E)YQrSe5
z8GZip&ez`PN~fYk=VHo^SBLYBl#a$B*EnPwhfL#;ZX8mLLo$_$@||%@UE#?n{7QH-
zd{6kX@R#8a!ViT{hq*8rp1t041ONa40000000000000000000000000000000002s
zTT4%BePVF)mZLjPoEqA9U~FqwBjJ3txcAVzUz|L$<-o?yM#9XQC--f9V(zIYrmIKt
zjfB&WlutcV+&4V3ZDgdQk?_>16ED`r4$jS<n|e6cNEkj;I8&TGcwnqDI-G4J?BDiK
zVeinM!SQX=Co+wM=Z>767&~#|#Mp_MbLmFH-l^H=o;f%(Ro^msEY(ODI$Jt8G5m0S
z%Zc5C$#tpq`Js*5XOEnIdTjgTv4=auPe)zhwQTr$_;2BF!e55p2wx0;7=AhYLim~R
z+Vx&n000000000000000000000000000000000000002EnoKH@=<JM7(v7o@uI4e{
zJa#mWnM~uDOwJe0<r>Fqc0QVJ)=I_l`R+I^89o<<FUJP}00000000000000000000
z000000000000000004ONxha{8@`-GsqbtgcK7V=VYj0$F61k`&k<EAHn@Kxf9qx<^
zCc_t^@Rj%g000000000000000000000000000000000000001QUN@!_*+f^A8GZip
z&ez^ZcE{0tz8T%|>TqXVAQ|3>!q?*i00000000000000000000000000000000000
z0002IwWL$|L^74?$alt(WcXqfz8W6@00000000000000000000000000000000000
z007|4?S@n~5oJc7zr6FcH<DecY`z)U@#=7QBlqR&JURdX00000000000000000000
z0000000000000000JzRN8;6&#^B@2K00000000000000000000000000000000000
z0N^_7zR(}_ywsNrzZrhu;<@m^#YZo`e&O{CKk-uEh0;rZ{L;r>8Vx5dY`XYU*L$1*
z000000000000000000000000000000000000PxM=@%)WZK9R_8iK1+FeMcghJ6Jhi
zDwhj=Ps~pA4Oa_er;F7nGy44Ht?%zy2#3y{8h!V<1G6(*=8h!ybT?Z_>}<7=&*n0F
zOSQ4tTCML;X=1Wop6jbj_dR`d&+=BLwoV@1ck*cA$d3B4T{pBE**M=wCYRn_F89q<
zW~+T;)k1BuSX*BG;MDQb{_5}(Q_npzvb(EQecOEXbS|~f_i(XRFIM}8E0yw!Cf;+f
zu;tlPvj>LuoPH)=i)<9_Sl3#P_45sNr1ll-eNRuHsg%zY$D8%Gf9ksz!Yw1UQ{}x|
zkMEs3wSQk{YY30cFJvm0Tv*Ay#WTfnWhNfQp<?}PrFwe#IJQ1KRIF})W^(VIk)h;c
z9dSeXM90Eha!;13#gmnDi>o<Wu1qX%;oaw-92~6eJF$QN{-MF#jZq>>bj*(=pG+=q
z;b^fIFYMULHLV?;JG^zeJiG7I{_($;X*82hY-l!<Pb5=^>yz;uo~Tq#PZg@CTb1wp
z(B)>h<&S@DcKT$gTpS;1NbX8CYv(sD)LyLC+=|gcbxHM|FFamvB{!?5<DKYfu4hMU
zC-V8u)WJ%v-uFzYR;thML|kbhJb7&Ij$^aW?HS&&bK{n5Yv8vnbe*26jK(8dKHgU9
zNNc<grCXJ5o$oH094<^Oonjo;<Ft`^@4B(I;r$Eyl*=9|7pCLOWq#k6FYfNclN+Bp
z`Rw7s=()X*CY#-L^sii=gT?9DCH*#Tl{jso-_(Xgqi#n>_rg$@uVl4SsV|i7ZrtQA
zU*Bg80000000000000000000000000000000000000017Z=H?9%h!1j0000000000
z00000000000000000000000000001Ropr{ap76mad@Z~l{w(}a_<Z=C@N3~S;pf6n
zhfju2gpY*}hY!UC000000000000000000000000000000000000002s|Ep{|kxz8?
zG=q+H%^-JUGst!~gUk)hAl=mrQk~5pna`y2afNI;N+goGR*-E4nO2Z)1*uk$%)~)H
z*%|lP6TUYJ|2zD3_>1tR@Q2~|!f%G}4c{MrIsAP1bogZWc=%}e;p@FB0000000000
z00000000000000000000000000002IrDW5Ijzp>_4)TfAx?DPuNaV6Nw!%zzD@@<e
z3R7LJFxlBGp365Y=Q^4}GM7!~6Nz-T8Kg4JAeqjj^KrxRF)oo#cXZ@C<4$|RZBh88
z@bAON!ykno39pCW3I8;_FVw<#I2N7^+rtBK0RR910000000000000000000000000
z0000000000-kNSqC$fpoC^P!}<()4)-qVbBG^5);_1){5(OfgS_5D3JHlx{vXm>N3
zS%}`yjHVZ&UCn4}A==rDCKsal?sPtzScr9Wr=u&e+?CjtKmN7sl33<S?9LBePG5<|
zgHJ7KC3!;}%P-`0##8MHo1^g6@Wt?Z;lGBT3I8_y>+qrQN(iAEis8AiKYV9g00000
z00000000000000000000000000000000000+TD=KCZf#f^OtwN@OaN+Wc#PSd);DW
z>-&3dY>#xeM{a13bhSr1+avk*NJo1lw-~weLzlDdkxY9e-5yD`N0MEsY<?lq8BeL_
z;$KA}8J-Qdgt@RSJQ*f0{#Cd){6YAk@R#9x!l%Qpgde-!%MJhl000000000000000
z00000000000000000000!2e}Esr8AI$M)_xHv8P3;T=0S_B0Z<jMPq*_ijDDcka~w
zb&Z7GhbK2ab@JK6h0$|+Z)_w?ZJj*2@8r?KksbA8-Hn8UQ^!mDtHV!BJ@?4S4UL5N
z94u^k_SEcwp*^Rc>1rfweR!x?-Tutv-aR8josEQ{bEih%eeS^Q%$B($`9{LK&p$ah
zSlf4E|Ni|$9gT$A(YeE0r^~bZPVFDhHM^~hmdeGErfef&cKT$TFy2haG!p8CiQ34#
zbTgq+DUTMa&4g65jpFp|LW$(M)cSn2QmHQ_bjM4Q41XGhzlje3000000000000000
z00000000000000000000008jjmrrJ*TN2UK_;jixk%?|fM5E`EopDAod?gBBiw^(*
z000000000000000000000000000000000000PvQPOWl%~8lO&PQa9yC&v(ZuiSXqp
z{s90000000000000000000000000000000000000fVYUAL~4Cvs&anhbaC!%r8-_q
zcE+j6@Ol)!79Rir000000000000000000000000000000000000N|}7n@&WDR5B9>
z`DAyTkO*Il;vWD2000000000000000000000000000000000000C=<OO{Ai2Q<c$D
zxwvVxQaL?UsGhDJtyJorab_ZXDT;pp00000000000000000000000000000000000
z007`kuQ#<VKUEnmm5ZB3E0xnzh3e_r(MqM>-N=0TIu8y200000000000000000000
z000000000000000006GD&c@;8>pTbm00000000000000000000000000000000000
z006koy5mnG{7Dr5000000000000000000000000000000000000002Mo8PU8&M1*z
z*OADl)7j1G%Xj|pKW}_G<E%vZS`_~P00000000000000000000000000000000000
z006*SP$r$o=d;&)6aWAK000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z0000000000000000000000000000000000000030r#(0%000005cL1GFH8Uc00000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
z00000000000000000000000000000000000000000000000000000000000000000
b0000000000000000000000000008g{przYz
--- a/toolkit/components/places/tests/migration/xpcshell.ini
+++ b/toolkit/components/places/tests/migration/xpcshell.ini
@@ -3,16 +3,17 @@ head = head_migration.js
 
 support-files =
   places_outdated.sqlite
   places_v31.sqlite
   places_v34.sqlite
   places_v35.sqlite
   places_v36.sqlite
   places_v38.sqlite
+  places_v42.sqlite
 
 [test_current_from_downgraded.js]
 [test_current_from_outdated.js]
 [test_current_from_v31.js]
 [test_current_from_v34.js]
 [test_current_from_v34_no_roots.js]
 [test_current_from_v35.js]
 [test_current_from_v36.js]
--- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
@@ -108,41 +108,54 @@ AutoCompleteInput.prototype = {
  * A helper for check_autocomplete to check a specific match against data from
  * the controller.
  *
  * @param {Object} match The expected match for the result, in the following form:
  * {
  *   uri: {nsIURI} The expected uri.
  *   title: {String} The title of the entry.
  *   tags: {String} The tags for the entry.
- *   style: {String} The style of the entry.
+ *   style: {Array} The style of the entry.
  * }
  * @param {Object} result The result to compare the result against with the same
  *                        properties as the match param.
  * @returns {boolean} Returns true if the result matches.
  */
 async function _check_autocomplete_matches(match, result) {
-  let { uri, title, tags, style } = match;
+  let { uri, tags, style } = match;
+  let title = match.comment || match.title;
+
   if (tags)
     title += " \u2013 " + tags.sort().join(", ");
   if (style)
     style = style.sort();
   else
     style = ["favicon"];
 
-  info(`Checking against expected "${uri.spec}", "${title}"`);
-  // Got a match on both uri and title?
-  if (stripPrefix(uri.spec) != stripPrefix(result.value) || title != result.comment) {
-    return false;
+  if ("value" in match) {
+    let value = match.value;
+    info(`Checking match: actual=${JSON.stringify({ value: result.value, comment: result.comment })} ... expected=${JSON.stringify({ value, comment: title })}`);
+    Assert.equal(result.value, value, "Expected value");
+    Assert.equal(result.comment, title, "Expected comment");
+    if (result.value != value || result.comment != title) {
+      return false;
+    }
+  } else {
+    info(`Checking match. Actual: value/uri="${result.value}" comment/title="${result.comment}" ... Expected: uri="${uri.spec}" title="${title}"`);
+
+    // Got a match on both uri and title?
+    if (stripPrefix(uri.spec) != stripPrefix(result.value) || title != result.comment) {
+      return false;
+    }
   }
 
   let actualStyle = result.style.split(/\s+/).sort();
   if (style)
     Assert.equal(actualStyle.toString(), style.toString(), "Match should have expected style");
-  if (uri.spec.startsWith("moz-action:")) {
+  if (uri && uri.spec.startsWith("moz-action:")) {
     Assert.ok(actualStyle.includes("action"), "moz-action results should always have 'action' in their style");
   }
 
   if (match.icon) {
     await compareFavicons(result.image, match.icon, "Match should have the expected icon");
   }
 
   return true;
@@ -234,17 +247,17 @@ async function check_autocomplete(test) 
 
       for (let i = firstIndexToCheck; i < controller.matchCount; i++) {
         let result = {
           value: controller.getValueAt(i),
           comment: controller.getCommentAt(i),
           style: controller.getStyleAt(i),
           image: controller.getImageAt(i),
         };
-        info(`Found value: "${result.value}", comment: "${result.comment}", style: "${result.style}" in results...`);
+        info(`Actual result at index ${i}: ${JSON.stringify(result)}`);
         let lowerBound = test.checkSorting ? i : firstIndexToCheck;
         let upperBound = test.checkSorting ? i + 1 : matches.length;
         let found = false;
         for (let j = lowerBound; j < upperBound; ++j) {
           // Skip processed expected results
           if (matches[j] == undefined)
             continue;
           if (await _check_autocomplete_matches(matches[j], result)) {
@@ -266,53 +279,30 @@ async function check_autocomplete(test) 
 
     // If we expect results, make sure we got matches.
     Assert.equal(controller.searchStatus, matches.length ?
                  Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH :
                  Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH);
   }
 
   if (test.autofilled) {
+    dump("***XXXadw.......................\n" + (new Error()).stack + "\n");
     // Check the autoFilled result.
     Assert.equal(input.textValue, test.autofilled,
                  "Autofilled value is correct");
 
     // Now force completion and check correct casing of the result.
     // This ensures the controller is able to do its magic case-preserving
     // stuff and correct replacement of the user's casing with result's one.
     controller.handleEnter(false);
     Assert.equal(input.textValue, test.completed,
                  "Completed value is correct");
   }
 }
 
-var addBookmark = async function(aBookmarkObj) {
-  Assert.ok(!!aBookmarkObj.uri, "Bookmark object contains an uri");
-  let parentId = aBookmarkObj.parentId ? aBookmarkObj.parentId
-                                       : PlacesUtils.unfiledBookmarksFolderId;
-
-  let bm = await PlacesUtils.bookmarks.insert({
-    parentGuid: (await PlacesUtils.promiseItemGuid(parentId)),
-    title: aBookmarkObj.title || "A bookmark",
-    url: aBookmarkObj.uri
-  });
-  await PlacesUtils.promiseItemId(bm.guid);
-
-  if (aBookmarkObj.keyword) {
-    await PlacesUtils.keywords.insert({ keyword: aBookmarkObj.keyword,
-                                        url: aBookmarkObj.uri.spec,
-                                        postData: aBookmarkObj.postData
-                                      });
-  }
-
-  if (aBookmarkObj.tags) {
-    PlacesUtils.tagging.tagURI(aBookmarkObj.uri, aBookmarkObj.tags);
-  }
-};
-
 function addOpenPages(aUri, aCount = 1, aUserContextId = 0) {
   let ac = Cc["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
              .getService(Ci.mozIPlacesAutoComplete);
   for (let i = 0; i < aCount; i++) {
     ac.registerOpenPage(aUri, aUserContextId);
   }
 }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autofill.js
@@ -0,0 +1,656 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+function addAutofillTasks(origins) {
+  // Helpful reminder of the `autofilled` and `completed` properties in the
+  // object passed to check_autocomplete:
+  //
+  //   autofilled: expected input.value after autofill
+  //    completed: expected input.value after autofill and enter is pressed
+  //
+  // `completed` is the URL that the controller sets to input.value, and the URL
+  // that will ultimately be loaded when you press enter.  When you press enter,
+  // the code path is:
+  //
+  //   (1) urlbar.handleEnter
+  //   (2) nsAutoCompleteController::HandleEnter
+  //   (3) nsAutoCompleteController::EnterMatch (sets input.value)
+  //   (4) input.onTextEntered
+  //   (5) urlbar.handleCommand (loads input.value)
+
+  let path;
+  let search;
+  let searchCase;
+  let comment;
+  if (origins) {
+    path = "/";
+    search = "ex";
+    searchCase = "EX";
+    comment = "example.com";
+  } else {
+    path = "/foo";
+    search = "example.com/f";
+    searchCase = "EXAMPLE.COM/f";
+    comment = "example.com/foo";
+  }
+
+  let host = "example.com";
+  let url = host + path;
+
+  add_task(async function init() {
+    await cleanup();
+  });
+
+  // "ex" should match http://example.com/.
+  add_task(async function basic() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [{
+        value: url,
+        comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "EX" should match http://example.com/.
+  add_task(async function basicCase() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: searchCase,
+      autofilled: searchCase + url.substr(searchCase.length),
+      completed: "http://" + url,
+      matches: [{
+        value: url,
+        comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "ex" should match http://www.example.com/.
+  add_task(async function noWWWShouldMatchWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://www." + url),
+    }]);
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://www." + url,
+      matches: [{
+        value: url,
+        comment: "www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "EX" should match http://www.example.com/.
+  add_task(async function noWWWShouldMatchWWWCase() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://www." + url),
+    }]);
+    await check_autocomplete({
+      search: searchCase,
+      autofilled: searchCase + url.substr(searchCase.length),
+      completed: "http://www." + url,
+      matches: [{
+        value: url,
+        comment: "www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "www.ex" should *not* match http://example.com/.
+  add_task(async function wwwShouldNotMatchNoWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "www." + search,
+      matches: [],
+    });
+    await cleanup();
+  });
+
+  // "http://ex" should match http://example.com/.
+  add_task(async function prefix() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "http://" + search,
+      autofilled: "http://" + url,
+      completed: "http://" + url,
+      matches: [{
+        value: "http://" + url,
+        comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "HTTP://EX" should match http://example.com/.
+  add_task(async function prefixCase() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "HTTP://" + searchCase,
+      autofilled: "HTTP://" + searchCase + url.substr(searchCase.length),
+      completed: "http://" + url,
+      matches: [{
+        value: "http://" + url,
+        comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "http://ex" should match http://www.example.com/.
+  add_task(async function prefixNoWWWShouldMatchWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://www." + url),
+    }]);
+    await check_autocomplete({
+      search: "http://" + search,
+      autofilled: "http://" + url,
+      completed: "http://www." + url,
+      matches: [{
+        value: "http://" + url,
+        comment: "www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "HTTP://EX" should match http://www.example.com/.
+  add_task(async function prefixNoWWWShouldMatchWWWCase() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://www." + url),
+    }]);
+    await check_autocomplete({
+      search: "HTTP://" + searchCase,
+      autofilled: "HTTP://" + searchCase + url.substr(searchCase.length),
+      completed: "http://www." + url,
+      matches: [{
+        value: "http://" + url,
+        comment: "www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "http://www.ex" should *not* match http://example.com/.
+  add_task(async function prefixWWWShouldNotMatchNoWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "http://www." + search,
+      matches: [],
+    });
+    await cleanup();
+  });
+
+  // "http://ex" should *not* match https://example.com/.
+  add_task(async function httpPrefixShouldNotMatchHTTPS() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://" + url),
+    }]);
+    await check_autocomplete({
+      search: "http://" + search,
+      matches: [{
+        value: "https://" + url,
+        comment: "test visit for https://" + url,
+        style: ["favicon"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "ex" should match https://example.com/.
+  add_task(async function httpsBasic() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://" + url),
+    }]);
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://" + url,
+      matches: [{
+        value: url,
+        comment: "https://" + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "ex" should match https://www.example.com/.
+  add_task(async function httpsNoWWWShouldMatchWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://www." + url),
+    }]);
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://www." + url,
+      matches: [{
+        value: url,
+        comment: "https://www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "www.ex" should *not* match https://example.com/.
+  add_task(async function httpsWWWShouldNotMatchNoWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://" + url),
+    }]);
+    await check_autocomplete({
+      search: "www." + search,
+      matches: [],
+    });
+    await cleanup();
+  });
+
+  // "https://ex" should match https://example.com/.
+  add_task(async function httpsPrefix() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://" + url),
+    }]);
+    await check_autocomplete({
+      search: "https://" + search,
+      autofilled: "https://" + url,
+      completed: "https://" + url,
+      matches: [{
+        value: "https://" + url,
+        comment: "https://" + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "https://ex" should match https://www.example.com/.
+  add_task(async function httpsPrefixNoWWWShouldMatchWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://www." + url),
+    }]);
+    await check_autocomplete({
+      search: "https://" + search,
+      autofilled: "https://" + url,
+      completed: "https://www." + url,
+      matches: [{
+        value: "https://" + url,
+        comment: "https://www." + comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // "https://www.ex" should *not* match https://example.com/.
+  add_task(async function httpsPrefixWWWShouldNotMatchNoWWW() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("https://" + url),
+    }]);
+    await check_autocomplete({
+      search: "https://www." + search,
+      matches: [],
+    });
+    await cleanup();
+  });
+
+  // "https://ex" should *not* match http://example.com/.
+  add_task(async function httpsPrefixShouldNotMatchHTTP() {
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "https://" + search,
+      matches: [{
+        value: "http://" + url,
+        comment: "test visit for http://" + url,
+        style: ["favicon"],
+      }],
+    });
+    await cleanup();
+  });
+
+  // Autofill should respond to frecency changes.
+  add_task(async function frecency() {
+    // Start with an http visit.  It should be completed.
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    dump("******XXXadw check_autocomplete 1\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [{
+        value: url,
+        comment,
+        style: ["autofill", "heuristic"],
+      }],
+    });
+    dump("******XXXadw check_autocomplete 1 done\n");
+
+    // Add two https visits.  https should now be completed.
+    for (let i = 0; i < 2; i++) {
+      await PlacesTestUtils.addVisits([
+        { uri: NetUtil.newURI("https://" + url) },
+      ]);
+    }
+    dump("******XXXadw check_autocomplete 2\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://" + url,
+      matches: [
+        {
+          value: url,
+          comment: "https://" + comment,
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: "http://" + url,
+          comment: "test visit for http://" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 2 done\n");
+
+    // Add two more http visits, three total.  http should now be completed
+    // again.
+    for (let i = 0; i < 2; i++) {
+      await PlacesTestUtils.addVisits([
+        { uri: NetUtil.newURI("http://" + url) },
+      ]);
+    }
+    dump("******XXXadw check_autocomplete 3\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [
+        {
+          value: url,
+          comment,
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: "https://" + url,
+          comment: "test visit for https://" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 3 done\n");
+
+    // Add four www https visits.  www https should now be completed.
+    for (let i = 0; i < 4; i++) {
+      await PlacesTestUtils.addVisits([
+        { uri: NetUtil.newURI("https://www." + url) },
+      ]);
+    }
+    dump("******XXXadw check_autocomplete 4\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://www." + url,
+      matches: [
+        {
+          value: url,
+          comment: "https://www." + comment,
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: "http://" + url,
+          comment: "test visit for http://" + url,
+          style: ["favicon"],
+        },
+        {
+          value: "https://" + url,
+          comment: "test visit for https://" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 4 done\n");
+
+    // Remove the www https page.
+    await PlacesUtils.history.remove([
+      "https://www." + url,
+    ]);
+
+    // http should now be completed again.
+    dump("******XXXadw check_autocomplete 5\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [
+        {
+          value: url,
+          comment,
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: "https://" + url,
+          comment: "test visit for https://" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 5 done\n");
+
+    // Remove the http page.
+    await PlacesUtils.history.remove([
+      "http://" + url,
+    ]);
+
+    // https should now be completed again.
+    dump("******XXXadw check_autocomplete 6\n");
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://" + url,
+      matches: [
+        {
+          value: url,
+          comment: "https://" + comment,
+          style: ["autofill", "heuristic"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 6 done\n");
+
+    // Add a visit with a different host so that "ex" doesn't autofill it.
+    // https://example.com/ should still have a higher frecency though, so it
+    // should still be autofilled.
+    await PlacesTestUtils.addVisits([
+      { uri: NetUtil.newURI("https://not-" + url) },
+    ]);
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://" + url,
+      matches: [
+        {
+          value: url,
+          comment: "https://" + comment,
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: "https://not-" + url,
+          comment: "test visit for https://not-" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 6XXX done\n");
+
+    // Now add 10 more visits to the different host so that the frecency of
+    // https://example.com/ falls below the autofill threshold.  It should not
+    // be autofilled now.
+    for (let i = 0; i < 10; i++) {
+      await PlacesTestUtils.addVisits([
+        { uri: NetUtil.newURI("https://not-" + url) },
+      ]);
+    }
+
+    // Enable actions to make sure that the failure to make an autofill match
+    // does not interrupt creating another type of heuristic match, in this case
+    // a search (for "ex") in the `origins` case, and a visit in the `!origins`
+    // case.
+    await check_autocomplete({
+      search,
+      searchParam: "enable-actions",
+      matches: [
+        origins ?
+          makeSearchMatch(search, { style: ["heuristic"] }) :
+          makeVisitMatch(search, "http://" + search, { heuristic: true }),
+        {
+          value: "https://not-" + url,
+          comment: "test visit for https://not-" + url,
+          style: ["favicon"],
+        },
+        {
+          value: "https://" + url,
+          comment: "test visit for https://" + url,
+          style: ["favicon"],
+        },
+      ],
+    });
+
+    // Remove the visits to the different host.
+    await PlacesUtils.history.remove([
+      "https://not-" + url,
+    ]);
+
+    // https should be completed again.
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "https://" + url,
+      matches: [
+        {
+          value: url,
+          comment: "https://" + comment,
+          style: ["autofill", "heuristic"],
+        },
+      ],
+    });
+    dump("******XXXadw check_autocomplete 6 done\n");
+
+    // Remove the https visits.
+    await PlacesUtils.history.remove([
+      "https://" + url,
+    ]);
+
+    // Now nothing should be completed.
+    dump("******XXXadw check_autocomplete 7\n");
+    await check_autocomplete({
+      search,
+      matches: [],
+    });
+    dump("******XXXadw check_autocomplete 7 done\n");
+
+    await cleanup();
+  });
+
+  // Autofill should respect the browser.urlbar.suggest.history pref -- i.e., it
+  // should complete only bookmarked pages when that pref is false.
+  add_task(async function bookmarked() {
+    // Force only bookmarked pages to be suggested and therefore only bookmarked
+    // pages to be completed.
+    Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
+
+    // Add a non-bookmarked page.  It should not be suggested or completed.
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+//       uri: NetUtil.newURI("http://" + url),//XXXadw
+    }]);
+    await check_autocomplete({
+      search,
+      matches: [],
+    });
+
+    // Bookmark the page.  It should be suggested and completed.
+    await addBookmark({
+      uri: NetUtil.newURI("http://" + url),
+    });
+    await check_autocomplete({
+      search,
+      autofilled: url,
+      completed: "http://" + url,
+      matches: [
+        {
+          value: url,
+          comment,
+          style: ["autofill", "heuristic"],
+        },
+      ],
+    });
+
+    await cleanup();
+  });
+
+  // Same as previous but the search contains a prefix.
+  add_task(async function bookmarkedPrefix() {
+    // Force only bookmarked pages to be suggested and therefore only bookmarked
+    // pages to be completed.
+    Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
+
+    // Add a non-bookmarked page.  It should not be suggested or completed.
+    await PlacesTestUtils.addVisits([{
+      uri: NetUtil.newURI("http://" + url),
+    }]);
+    await check_autocomplete({
+      search: "http://" + search,
+      matches: [],
+    });
+
+    // Bookmark the page.  It should be suggested and completed.
+    await addBookmark({
+      uri: NetUtil.newURI("http://" + url),
+    });
+    await check_autocomplete({
+      search: "http://" + search,
+      autofilled: "http://" + url,
+      completed: "http://" + url,
+      matches: [
+        {
+          value: "http://" + url,
+          comment,
+          style: ["autofill", "heuristic"],
+        },
+      ],
+    });
+
+    await cleanup();
+  });
+}
--- a/toolkit/components/places/tests/unifiedcomplete/test_417798.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_417798.js
@@ -23,21 +23,20 @@ add_task(async function test_javascript_
   });
 
   info("Match non-javascript: with almost javascript:");
   await check_autocomplete({
     search: "javascript",
     matches: [ { uri: uri1, title: "Title with javascript:" } ]
   });
 
-  info("Match javascript:");
+  info("Match nothing with javascript:");
   await check_autocomplete({
     search: "javascript:",
-    matches: [ { uri: uri1, title: "Title with javascript:" },
-               { uri: uri2, title: "Title with javascript:", style: [ "bookmark" ]} ]
+    matches: []
   });
 
   info("Match nothing with non-first javascript:");
   await check_autocomplete({
     search: "5 javascript:",
     matches: [ ]
   });
 
--- a/toolkit/components/places/tests/unifiedcomplete/test_418257.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_418257.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Test bug 418257 by making sure tags are returned with the title as part of
  * the "comment" if there are tags even if we didn't match in the tags. They
  * are separated from the title by a endash.
  */
 
-add_task(async function test_javascript_match() {
+add_task(async function test() {
   let uri1 = NetUtil.newURI("http://page1");
   let uri2 = NetUtil.newURI("http://page2");
   let uri3 = NetUtil.newURI("http://page3");
   let uri4 = NetUtil.newURI("http://page4");
   await PlacesTestUtils.addVisits([
     { uri: uri1, title: "tagged" },
     { uri: uri2, title: "tagged" },
     { uri: uri3, title: "tagged" },
@@ -42,22 +42,24 @@ add_task(async function test_javascript_
   await check_autocomplete({
     search: "page2 tag",
     matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "bookmark-tag" ] } ]
   });
 
   info("Make sure tags appear even when not matching the tag");
   await check_autocomplete({
     search: "page3",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri3, title: "tagged", tags: [ "tag1", "tag3" ], style: [ "bookmark-tag" ] } ]
   });
 
   info("Multiple tags come in commas for page4");
   await check_autocomplete({
     search: "page4",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "bookmark-tag" ] } ]
   });
 
   info("Extra test just to make sure we match the title");
   await check_autocomplete({
     search: "tag2",
     matches: [ { uri: uri2, title: "tagged", tags: [ "tag1", "tag2" ], style: [ "bookmark-tag" ] },
                { uri: uri4, title: "tagged", tags: [ "tag1", "tag2", "tag3" ], style: [ "bookmark-tag" ] } ]
--- a/toolkit/components/places/tests/unifiedcomplete/test_422277.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_422277.js
@@ -2,18 +2,19 @@
  * 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/. */
 
 /**
  * Test bug 422277 to make sure bad escaped uris don't get escaped. This makes
  * sure we don't hit an assertion for "not a UTF8 string".
  */
 
-add_task(async function test_javascript_match() {
+add_task(async function test() {
   info("Bad escaped uri stays escaped");
   let uri1 = NetUtil.newURI("http://site/%EAid");
   await PlacesTestUtils.addVisits([ { uri: uri1, title: "title" } ]);
   await check_autocomplete({
+    searchParam: "prohibit-autofill",
     search: "site",
     matches: [ { uri: uri1, title: "title" } ]
   });
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_PlacesSearchAutocompleteProvider.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_PlacesSearchAutocompleteProvider.js
@@ -30,17 +30,18 @@ add_task(async function no_match() {
 
 add_task(async function hide_search_engine_nomatch() {
   let engine = await promiseDefaultSearchEngine();
   let token = engine.getResultDomain();
   let promiseTopic = promiseSearchTopic("engine-changed");
   Services.search.removeEngine(engine);
   await promiseTopic;
   Assert.ok(engine.hidden);
-  Assert.equal(null, await PlacesSearchAutocompleteProvider.findMatchByToken(token.substr(0, 1)));
+  let match = await PlacesSearchAutocompleteProvider.findMatchByToken(token.substr(0, 1));
+  Assert.ok(!match || match.token != token);
 });
 
 add_task(async function add_search_engine_match() {
   let promiseTopic = promiseSearchTopic("engine-added");
   Assert.equal(null, await PlacesSearchAutocompleteProvider.findMatchByToken("bacon"));
   Services.search.addEngineWithDetails("bacon", "", "pork", "Search Bacon",
                                        "GET", "http://www.bacon.moz/?search={searchTerms}");
   await promiseTopic;
--- a/toolkit/components/places/tests/unifiedcomplete/test_autocomplete_functional.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autocomplete_functional.js
@@ -6,146 +6,89 @@
 
 const PREF_AUTOCOMPLETE_ENABLED = "browser.urlbar.autocomplete.enabled";
 
 add_task(async function test_disabling_autocomplete() {
   info("Check disabling autocomplete disables autofill");
   Services.prefs.setBoolPref(PREF_AUTOCOMPLETE_ENABLED, false);
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://visit.mozilla.org"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "vis",
     autofilled: "vis",
     completed: "vis"
   });
   await cleanup();
 });
 
 add_task(async function test_urls_order() {
   info("Add urls, check for correct order");
   let places = [{ uri: NetUtil.newURI("http://visit1.mozilla.org") },
-                { uri: NetUtil.newURI("http://visit2.mozilla.org"),
-                  transition: TRANSITION_TYPED }];
+                { uri: NetUtil.newURI("http://visit2.mozilla.org") }];
   await PlacesTestUtils.addVisits(places);
   await check_autocomplete({
     search: "vis",
     autofilled: "visit2.mozilla.org/",
-    completed: "visit2.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_ignore_prefix() {
-  info("Add urls, make sure www and http are ignored");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit1.mozilla.org"));
-  await check_autocomplete({
-    search: "visit1",
-    autofilled: "visit1.mozilla.org/",
-    completed: "visit1.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_after_host() {
-  info("Autocompleting after an existing host completes to the url");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://www.visit3.mozilla.org"));
-  await check_autocomplete({
-    search: "visit3.mozilla.org/",
-    autofilled: "visit3.mozilla.org/",
-    completed: "visit3.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_respect_www() {
-  info("Searching for www.me should yield www.me.mozilla.org/");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://www.me.mozilla.org"));
-  await check_autocomplete({
-    search: "www.me",
-    autofilled: "www.me.mozilla.org/",
-    completed: "www.me.mozilla.org/"
+    completed: "http://visit2.mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_bookmark_first() {
   info("With a bookmark and history, the query result should be the bookmark");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
   await addBookmark({ uri: NetUtil.newURI("http://bookmark1.mozilla.org/") });
+
+//     dump("\n\n");
+//     dump("****************************XXXadw 1\n");
+//     dump_table("moz_origins");
+//     dump_table("moz_prefixes");
+//     dump_table("moz_hosts");
+//     dump_table("moz_autofill_origins");
+//     dump_table("moz_places");
+//     dump("\n\n");
+
   await PlacesTestUtils.addVisits(NetUtil.newURI("http://bookmark1.mozilla.org/foo"));
+
+//   await new Promise(r => {
+//     Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer).init(r,
+//       2000, Ci.nsITimer.TYPE_ONE_SHOT);
+//   });
+
+//     dump("\n\n");
+//     dump("****************************XXXadw 2\n");
+//     dump_table("moz_origins");
+//     dump_table("moz_prefixes");
+//     dump_table("moz_hosts");
+//     dump_table("moz_autofill_origins");
+//     dump_table("moz_places");
+//     dump("\n\n");
+
+
   await check_autocomplete({
     search: "bookmark",
     autofilled: "bookmark1.mozilla.org/",
-    completed: "bookmark1.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_full_path() {
-  info("Check to make sure we get the proper results with full paths");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
-                { uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
-  await PlacesTestUtils.addVisits(places);
-  await check_autocomplete({
-    search: "smokey",
-    autofilled: "smokey.mozilla.org/",
-    completed: "smokey.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_complete_to_slash() {
-  info("Check to make sure we autocomplete to the following '/'");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  let places = [{ uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
-                { uri: NetUtil.newURI("http://smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
-  await PlacesTestUtils.addVisits(places);
-  await check_autocomplete({
-    search: "smokey.mozilla.org/fo",
-    autofilled: "smokey.mozilla.org/foo/",
-    completed: "http://smokey.mozilla.org/foo/",
-  });
-  await cleanup();
-});
-
-add_task(async function test_complete_to_slash_with_www() {
-  info("Check to make sure we autocomplete to the following '/'");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  let places = [{ uri: NetUtil.newURI("http://www.smokey.mozilla.org/foo/bar/baz?bacon=delicious") },
-                { uri: NetUtil.newURI("http://www.smokey.mozilla.org/foo/bar/baz?bacon=smokey") }];
-  await PlacesTestUtils.addVisits(places);
-  await check_autocomplete({
-    search: "smokey.mozilla.org/fo",
-    autofilled: "smokey.mozilla.org/foo/",
-    completed: "http://www.smokey.mozilla.org/foo/",
+    completed: "http://bookmark1.mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_complete_querystring() {
   info("Check to make sure we autocomplete after ?");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
   await PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious"));
   await check_autocomplete({
     search: "smokey.mozilla.org/foo?",
     autofilled: "smokey.mozilla.org/foo?bacon=delicious",
     completed: "http://smokey.mozilla.org/foo?bacon=delicious",
   });
   await cleanup();
 });
 
 add_task(async function test_complete_fragment() {
   info("Check to make sure we autocomplete after #");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
   await PlacesTestUtils.addVisits(NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar"));
   await check_autocomplete({
     search: "smokey.mozilla.org/foo?bacon=delicious#bar",
     autofilled: "smokey.mozilla.org/foo?bacon=delicious#bar",
     completed: "http://smokey.mozilla.org/foo?bacon=delicious#bar",
   });
   await cleanup();
 });
deleted file mode 100644
--- a/toolkit/components/places/tests/unifiedcomplete/test_autofill_default_behavior.js
+++ /dev/null
@@ -1,322 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-/**
- * Test autoFill for different default behaviors.
- */
-
-add_task(async function test_default_behavior_host() {
-  let uri1 = NetUtil.newURI("http://typed/");
-  let uri2 = NetUtil.newURI("http://visited/");
-  let uri3 = NetUtil.newURI("http://bookmarked/");
-  let uri4 = NetUtil.newURI("http://tpbk/");
-  let uri5 = NetUtil.newURI("http://tagged/");
-  let uri6 = NetUtil.newURI("https://secure/");
-
-  await PlacesTestUtils.addVisits([
-    { uri: uri1, title: "typed", transition: TRANSITION_TYPED },
-    { uri: uri2, title: "visited" },
-    { uri: uri4, title: "tpbk", transition: TRANSITION_TYPED },
-    { uri: uri6, title: "secure", transition: TRANSITION_TYPED },
-  ]);
-  await addBookmark( { uri: uri3, title: "bookmarked" } );
-  await addBookmark( { uri: uri4, title: "tpbk" } );
-  await addBookmark( { uri: uri5, title: "title", tags: ["foo"] } );
-
-  await setFaviconForPage(uri1, "chrome://global/skin/icons/info.svg");
-  await setFaviconForPage(uri3, "chrome://global/skin/icons/error-16.png");
-  await setFaviconForPage(uri6, "chrome://global/skin/icons/question-16.png");
-
-  // RESTRICT TO HISTORY.
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history", true);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", false);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", false);
-
-  info("Restrict history, common visit, should not autoFill");
-  await check_autocomplete({
-    search: "vi",
-    matches: [ { uri: uri2, title: "visited" } ],
-    autofilled: "vi",
-    completed: "vi"
-  });
-
-  info("Restrict history, typed visit, should autoFill");
-  await check_autocomplete({
-    search: "ty",
-    matches: [ { uri: uri1, title: "typed", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/info.svg" } ],
-    autofilled: "typed/",
-    completed: "typed/"
-  });
-
-  info("Restrict history, secure typed visit, should autoFill with https");
-  await check_autocomplete({
-    search: "secure",
-    matches: [ { uri: uri6, title: "https://secure", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/question-16.png" } ],
-    autofilled: "secure/",
-    completed: "https://secure/"
-  });
-
-  // Don't autoFill this one cause it's not typed.
-  info("Restrict history, bookmark, should not autoFill");
-  await check_autocomplete({
-    search: "bo",
-    matches: [ ],
-    autofilled: "bo",
-    completed: "bo"
-  });
-
-  // Note we don't show this one cause it's not typed.
-  info("Restrict history, typed bookmark, should autoFill");
-  await check_autocomplete({
-    search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "tpbk/",
-    completed: "tpbk/"
-  });
-
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-
-  // We are not restricting on typed, so we autoFill the bookmark even if we
-  // are restricted to history.  We accept that cause not doing that
-  // would be a perf hit and the privacy implications are very weak.
-  info("Restrict history, bookmark, autoFill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "bo",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/error-16.png" } ],
-    autofilled: "bookmarked/",
-    completed: "bookmarked/"
-  });
-
-  info("Restrict history, common visit, autoFill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "vi",
-    matches: [ { uri: uri2, title: "visited", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "visited/",
-    completed: "visited/"
-  });
-
-  // RESTRICT TO TYPED.
-  // This should basically ignore autoFill.typed and acts as if it would be set.
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", true);
-
-  // Typed behavior basically acts like history, but filters on typed.
-  info("Restrict typed, common visit, autoFill.typed = false, should not autoFill");
-  await check_autocomplete({
-    search: "vi",
-    matches: [ ],
-    autofilled: "vi",
-    completed: "vi"
-  });
-
-  info("Restrict typed, typed visit, autofill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "ty",
-    matches: [ { uri: uri1, title: "typed", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/info.svg"} ],
-    autofilled: "typed/",
-    completed: "typed/"
-  });
-
-  info("Restrict typed, bookmark, autofill.typed = false, should not autoFill");
-  await check_autocomplete({
-    search: "bo",
-    matches: [ ],
-    autofilled: "bo",
-    completed: "bo"
-  });
-
-  info("Restrict typed, typed bookmark, autofill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "tpbk/",
-    completed: "tpbk/"
-  });
-
-  // RESTRICT BOOKMARKS.
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-
-  info("Restrict bookmarks, common visit, should not autoFill");
-  await check_autocomplete({
-    search: "vi",
-    matches: [ ],
-    autofilled: "vi",
-    completed: "vi"
-  });
-
-  info("Restrict bookmarks, typed visit, should not autoFill");
-  await check_autocomplete({
-    search: "ty",
-    matches: [ ],
-    autofilled: "ty",
-    completed: "ty"
-  });
-
-  // Don't autoFill this one cause it's not typed.
-  info("Restrict bookmarks, bookmark, should not autoFill");
-  await check_autocomplete({
-    search: "bo",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "bookmark" ],
-                 icon: "chrome://global/skin/icons/error-16.png"} ],
-    autofilled: "bo",
-    completed: "bo"
-  });
-
-  // Note we don't show this one cause it's not typed.
-  info("Restrict bookmarks, typed bookmark, should autoFill");
-  await check_autocomplete({
-    search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "tpbk/",
-    completed: "tpbk/"
-  });
-
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-
-  info("Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "bo",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/error-16.png" } ],
-    autofilled: "bookmarked/",
-    completed: "bookmarked/"
-  });
-
-  // Don't autofill because it's a title.
-  info("Restrict bookmarks, title, autofill.typed = false, should not autoFill");
-  await check_autocomplete({
-    search: "# ta",
-    matches: [ ],
-    autofilled: "# ta",
-    completed: "# ta"
-  });
-
-  // Don't autofill because it's a tag.
-  info("Restrict bookmarks, tag, autofill.typed = false, should not autoFill");
-  await check_autocomplete({
-    search: "+ ta",
-    matches: [ { uri: uri5, title: "title", tags: [ "foo" ], style: [ "tag" ] } ],
-    autofilled: "+ ta",
-    completed: "+ ta"
-  });
-
-  await cleanup();
-});
-
-add_task(async function test_default_behavior_url() {
-  let uri1 = NetUtil.newURI("http://typed/ty/");
-  let uri2 = NetUtil.newURI("http://visited/vi/");
-  let uri3 = NetUtil.newURI("http://bookmarked/bo/");
-  let uri4 = NetUtil.newURI("http://tpbk/tp/");
-
-  await PlacesTestUtils.addVisits([
-    { uri: uri1, title: "typed", transition: TRANSITION_TYPED },
-    { uri: uri2, title: "visited" },
-    { uri: uri4, title: "tpbk", transition: TRANSITION_TYPED },
-  ]);
-  await addBookmark( { uri: uri3, title: "bookmarked" } );
-  await addBookmark( { uri: uri4, title: "tpbk" } );
-
-  await setFaviconForPage(uri1, "chrome://global/skin/icons/info.svg");
-  await setFaviconForPage(uri3, "chrome://global/skin/icons/error-16.png");
-
-  // RESTRICT TO HISTORY.
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history", true);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", false);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", false);
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
-
-  info("URL: Restrict history, common visit, should not autoFill");
-  await check_autocomplete({
-    search: "visited/v",
-    matches: [ { uri: uri2, title: "visited" } ],
-    autofilled: "visited/v",
-    completed: "visited/v"
-  });
-
-  info("URL: Restrict history, typed visit, should autoFill");
-  await check_autocomplete({
-    search: "typed/t",
-    matches: [ { uri: uri1, title: "typed/ty/", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/info.svg"} ],
-    autofilled: "typed/ty/",
-    completed: "http://typed/ty/"
-  });
-
-  // Don't autoFill this one cause it's not typed.
-  info("URL: Restrict history, bookmark, should not autoFill");
-  await check_autocomplete({
-    search: "bookmarked/b",
-    matches: [ ],
-    autofilled: "bookmarked/b",
-    completed: "bookmarked/b"
-  });
-
-  // Note we don't show this one cause it's not typed.
-  info("URL: Restrict history, typed bookmark, should autoFill");
-  await check_autocomplete({
-    search: "tpbk/t",
-    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "tpbk/tp/",
-    completed: "http://tpbk/tp/"
-  });
-
-  // RESTRICT BOOKMARKS.
-  Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
-  Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
-
-  info("URL: Restrict bookmarks, common visit, should not autoFill");
-  await check_autocomplete({
-    search: "visited/v",
-    matches: [ ],
-    autofilled: "visited/v",
-    completed: "visited/v"
-  });
-
-  info("URL: Restrict bookmarks, typed visit, should not autoFill");
-  await check_autocomplete({
-    search: "typed/t",
-    matches: [ ],
-    autofilled: "typed/t",
-    completed: "typed/t"
-  });
-
-  // Don't autoFill this one cause it's not typed.
-  info("URL: Restrict bookmarks, bookmark, should not autoFill");
-  await check_autocomplete({
-    search: "bookmarked/b",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "bookmark" ],
-                 icon: "chrome://global/skin/icons/error-16.png" } ],
-    autofilled: "bookmarked/b",
-    completed: "bookmarked/b"
-  });
-
-  // Note we don't show this one cause it's not typed.
-  info("URL: Restrict bookmarks, typed bookmark, should autoFill");
-  await check_autocomplete({
-    search: "tpbk/t",
-    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill", "heuristic" ] } ],
-    autofilled: "tpbk/tp/",
-    completed: "http://tpbk/tp/"
-  });
-
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-
-  info("URL: Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
-  await check_autocomplete({
-    search: "bookmarked/b",
-    matches: [ { uri: uri3, title: "bookmarked/bo/", style: [ "autofill", "heuristic" ],
-                 icon: "chrome://global/skin/icons/error-16.png" } ],
-    autofilled: "bookmarked/bo/",
-    completed: "http://bookmarked/bo/"
-  });
-
-  await cleanup();
-});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autofill_origins.js
@@ -0,0 +1,142 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+//XXXadw should have tests for origins/urls that don't meet the threshold right?
+// am i already doing that, or at least accidentally?
+
+"use strict";
+
+addAutofillTasks(true);
+
+
+// add_task(async function XXXadw() {
+//   let visits = [];
+//   for (let i = 0; i < 10; i++) {
+//     visits.push({
+// //       uri: makeURI("http://example.com/autocomplete/?" + i),
+//       uri: "http://example.com/autocomplete/" + i,
+//     });
+//   }
+//   await PlacesTestUtils.addVisits(visits);
+
+//   await check_autocomplete({
+//     search: "ex",
+//     autofilled: "example.com/",
+//     completed: "http://example.com/",
+//     matches: [
+//       {
+//         value: "example.com/",
+//         comment: "example.com",
+//         style: ["autofill", "heuristic"],
+//       },
+//       {
+//         value: "http://example.com/autocomplete/9",
+//         comment: "test visit for http://example.com/autocomplete/9",
+//         style: ["favicon"],
+//       }
+//     ],
+//   });
+//   await cleanup();
+// });
+
+
+
+// "example.com/" should match http://example.com/.  i.e., the search string
+// should be treated as if it didn't have the trailing slash.
+add_task(async function trailingSlash() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com/",
+    autofilled: "example.com/",
+    completed: "http://example.com/",
+    matches: [{
+      value: "example.com/",
+      comment: "example.com/",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "example.com/" should match http://www.example.com/.  i.e., the search string
+// should be treated as if it didn't have the trailing slash.
+add_task(async function trailingSlashWWW() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://www.example.com/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com/",
+    autofilled: "example.com/",
+    completed: "http://www.example.com/",
+    matches: [{
+      value: "example.com/",
+      comment: "www.example.com/",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "ex" should match http://example.com:8888/, and the port should be completed.
+add_task(async function port() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/"),
+  }]);
+  await check_autocomplete({
+    search: "ex",
+    autofilled: "example.com:8888/",
+    completed: "http://example.com:8888/",
+    matches: [{
+      value: "example.com:8888/",
+      comment: "example.com:8888",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "example.com:8" should match http://example.com:8888/, and the port should
+// be completed.
+add_task(async function portPartial() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com:8",
+    autofilled: "example.com:8888/",
+    completed: "http://example.com:8888/",
+    matches: [{
+      value: "example.com:8888/",
+      comment: "example.com:8888",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "example.com:89" should *not* match http://example.com:8888/.
+add_task(async function portNoMatch1() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com:89",
+    matches: [],
+  });
+  await cleanup();
+});
+
+// "example.com:9" should *not* match http://example.com:8888/.
+add_task(async function portNoMatch2() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com:9",
+    matches: [],
+  });
+  await cleanup();
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autofill_search_engines.js
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+//XXXadw there's already test_search_engine_host.js though
+
+// The autoFill.searchEngines pref autofills the domains of engines registered
+// with the search service.  That's what this test checks.  It's a different
+// path in UnifiedComplete.js from normal moz_places autofill, which is tested
+// in test_autofill_origins.js and test_autofill_urls.js.
+
+"use strict";
+
+add_task(async function searchEngines() {
+  Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
+
+  let schemes = ["http", "https"];
+  for (let i = 0; i < schemes.length; i++) {
+    let scheme = schemes[i];
+    Services.search.addEngineWithDetails("TestEngine", "", "", "", "GET",
+                                         scheme + "://www.example.com/");
+    let engine = Services.search.getEngineByName("TestEngine");
+    engine.addParam("q", "{searchTerms}", null);
+
+    await check_autocomplete({
+      search: "ex",
+      autofilled: "example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: "example.com",
+      autofilled: "example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: "example.com/",
+      autofilled: "example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: "www.ex",
+      autofilled: "www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: "www.example.com",
+      autofilled: "www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: "www.example.com/",
+      autofilled: "www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: "www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://ex",
+      autofilled: scheme + "://example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://example.com",
+      autofilled: scheme + "://example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://example.com/",
+      autofilled: scheme + "://example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://www.ex",
+      autofilled: scheme + "://www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://www.example.com",
+      autofilled: scheme + "://www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    await check_autocomplete({
+      search: scheme + "://www.example.com/",
+      autofilled: scheme + "://www.example.com/",
+      completed: scheme + "://www.example.com/",
+      matches: [{
+        value: scheme + "://www.example.com/",
+        comment: "TestEngine",
+        style: ["heuristic", "priority-search"],
+      }],
+    });
+
+    let otherScheme = schemes[(i + 1) % schemes.length];
+    await check_autocomplete({
+      search: otherScheme + "://ex",
+      matches: [],
+    });
+    await check_autocomplete({
+      search: otherScheme + "://www.ex",
+      matches: [],
+    });
+
+    Services.search.removeEngine(engine);
+  }
+
+  await cleanup();
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autofill_urls.js
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+"use strict";
+
+addAutofillTasks(false);
+
+// "example.com/foo/" should match http://example.com/foo/.
+add_task(async function multipleSlashes() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com/foo/"),
+  }]);
+  await check_autocomplete({
+    search: "example.com/foo/",
+    autofilled: "example.com/foo/",
+    completed: "http://example.com/foo/",
+    matches: [{
+      value: "example.com/foo/",
+      comment: "example.com/foo/",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "example.com:8888/f" should match http://example.com:8888/foo.
+add_task(async function port() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/foo"),
+  }]);
+  await check_autocomplete({
+    search: "example.com:8888/f",
+    autofilled: "example.com:8888/foo",
+    completed: "http://example.com:8888/foo",
+    matches: [{
+      value: "example.com:8888/foo",
+      comment: "example.com:8888/foo",
+      style: ["autofill", "heuristic"],
+    }],
+  });
+  await cleanup();
+});
+
+// "example.com:8999/f" should *not* match http://example.com:8888/foo.
+add_task(async function portNoMatch() {
+  await PlacesTestUtils.addVisits([{
+    uri: NetUtil.newURI("http://example.com:8888/foo"),
+  }]);
+  await check_autocomplete({
+    search: "example.com:8999/f",
+    matches: [],
+  });
+  await cleanup();
+});
--- a/toolkit/components/places/tests/unifiedcomplete/test_avoid_middle_complete.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_avoid_middle_complete.js
@@ -40,18 +40,18 @@ add_task(async function test_searchEngin
                                        "GET", "http://cake.search/");
   let engine = Services.search.getEngineByName("CakeSearch");
   engine.addParam("q", "{searchTerms}", null);
   registerCleanupFunction(() => Services.search.removeEngine(engine));
 
   info("Should autoFill search engine if search string does not contains a space");
   await check_autocomplete({
     search: "ca",
-    autofilled: "cake.search",
-    completed: "http://cake.search"
+    autofilled: "cake.search/",
+    completed: "http://cake.search/"
   });
 
   await cleanup();
 });
 
 add_task(async function test_searchEngine_prefix_space_noautofill() {
   Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
   Services.search.addEngineWithDetails("CupcakeSearch", "", "", "",
@@ -131,49 +131,47 @@ add_task(async function test_searchEngin
   let engine = Services.search.getEngineByName("BeanSearch");
   engine.addParam("q", "{searchTerms}", null);
   registerCleanupFunction(() => Services.search.removeEngine(engine));
 
 
   info("Should autoFill search engine if search string has matching prefix.");
   await check_autocomplete({
     search: "http://www.be",
-    autofilled: "http://www.bean.search",
-    completed: "http://www.bean.search"
+    autofilled: "http://www.bean.search/",
+    completed: "http://www.bean.search/"
   });
 
   info("Should autoFill search engine if search string has www prefix.");
   await check_autocomplete({
     search: "www.be",
-    autofilled: "www.bean.search",
-    completed: "http://www.bean.search"
+    autofilled: "www.bean.search/",
+    completed: "http://www.bean.search/"
   });
 
   info("Should autoFill search engine if search string has matching scheme.");
   await check_autocomplete({
     search: "http://be",
-    autofilled: "http://bean.search",
-    completed: "http://www.bean.search"
+    autofilled: "http://bean.search/",
+    completed: "http://www.bean.search/"
   });
 
   await cleanup();
 });
 
 add_task(async function test_prefix_autofill() {
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://moz.org/test/"),
-    transition: TRANSITION_TYPED
   });
 
   info("Should not try to autoFill in-the-middle if a search is canceled immediately");
   await check_autocomplete({
     incompleteSearch: "moz",
     search: "mozi",
     autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
+    completed: "http://mozilla.org/"
   });
 
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_avoid_stripping_to_empty_tokens.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_avoid_stripping_to_empty_tokens.js
@@ -8,31 +8,125 @@ add_task(async function test_protocol_tr
       // Include the protocol in the query string to ensure we get matches (see bug 1059395)
       uri: NetUtil.newURI(prot + "://www.mozilla.org/test/?q=" + prot + encodeURIComponent("://") + "www.foo"),
       title: "Test title",
       transition: TRANSITION_TYPED
     };
     await PlacesTestUtils.addVisits(visit);
     let matches = [{uri: visit.uri, title: visit.title}];
 
+//     let inputs = [
+//       prot + "://",
+//       prot + ":// ",
+//       prot + ":// mo",
+//       prot + "://mo te",
+//       prot + "://www.",
+//       prot + "://www. ",
+//       prot + "://www. mo",
+//       prot + "://www.mo te",
+//       "www.",
+//       "www. ",
+//       "www. mo",
+//       "www.mo te"
+//     ];
+//     for (let input of inputs) {
+//       info("Searching for: " + input);
+//       await check_autocomplete({
+//         search: input,
+//         matches
+//       });
+//     }
+
+//     let inputs = [
+// //       prot + "://",
+// //       prot + ":// ",
+// //       prot + ":// mo",
+// //       prot + "://mo te",
+//       prot + "://www.",
+// //       prot + "://www. ",
+// //       prot + "://www. mo",
+// //       prot + "://www.mo te",
+//       "www.",
+// //       "www. ",
+// //       "www. mo",
+// //       "www.mo te"
+//     ];
+//     for (let input of inputs) {
+//       info("Searching for: " + input);
+//       await check_autocomplete({
+//         search: input,
+//         matches: [{
+//           value: "http://www.mozilla.org/",
+//           comment: "example.com/",
+//           style: ["autofill", "heuristic"],
+//         }],
+//       });
+//     }
+
+
+
+
+
+
+
+
+
+    let input = prot + "://www.";
+    info("Searching for: " + input);
+    await check_autocomplete({
+      search: input,
+      matches: [
+        {
+          value: prot + "://www.mozilla.org/",
+          comment: prot == "http" ? "www.mozilla.org"
+                                  : prot + "://www.mozilla.org",
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: visit.uri.spec,
+          comment: visit.title,
+          style: ["favicon"],
+        }
+      ],
+    });
+
+    input = "www.";
+    info("Searching for: " + input);
+    await check_autocomplete({
+      search: input,
+      matches: [
+        {
+          value: "www.mozilla.org/",
+          comment: prot == "http" ? "www.mozilla.org"
+                                  : prot + "://www.mozilla.org",
+          style: ["autofill", "heuristic"],
+        },
+        {
+          value: visit.uri.spec,
+          comment: visit.title,
+          style: ["favicon"],
+        }
+      ],
+    });
+
+
     let inputs = [
       prot + "://",
       prot + ":// ",
       prot + ":// mo",
       prot + "://mo te",
-      prot + "://www.",
       prot + "://www. ",
       prot + "://www. mo",
       prot + "://www.mo te",
-      "www.",
       "www. ",
       "www. mo",
       "www.mo te"
     ];
-    for (let input of inputs) {
+    for (input of inputs) {
+      dump(`****XXXadw input='${input}' prot=${prot}\n`);
       info("Searching for: " + input);
       await check_autocomplete({
         search: input,
         matches
       });
     }
 
     await cleanup();
--- a/toolkit/components/places/tests/unifiedcomplete/test_casing.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_casing.js
@@ -1,157 +1,146 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 add_task(async function test_casing_1() {
   info("Searching for cased entry 1");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "MOZ",
     autofilled: "MOZilla.org/",
-    completed: "mozilla.org/"
+    completed: "http://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_casing_2() {
   info("Searching for cased entry 2");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/T",
     autofilled: "mozilla.org/T",
     completed: "mozilla.org/T"
   });
   await cleanup();
 });
 
 add_task(async function test_casing_3() {
   info("Searching for cased entry 3");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/T",
     autofilled: "mozilla.org/Test/",
     completed: "http://mozilla.org/Test/"
   });
   await cleanup();
 });
 
 add_task(async function test_casing_4() {
   info("Searching for cased entry 4");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mOzilla.org/t",
     autofilled: "mOzilla.org/t",
     completed: "mOzilla.org/t"
   });
   await cleanup();
 });
 
 add_task(async function test_casing_5() {
   info("Searching for cased entry 5");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mOzilla.org/T",
     autofilled: "mOzilla.org/Test/",
     completed: "http://mozilla.org/Test/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_casing() {
   info("Searching for untrimmed cased entry");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://mOz",
     autofilled: "http://mOzilla.org/",
     completed: "http://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_www_casing() {
   info("Searching for untrimmed cased entry with www");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://www.mOz",
     autofilled: "http://www.mOzilla.org/",
     completed: "http://www.mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_path_casing() {
   info("Searching for untrimmed cased entry with path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://mOzilla.org/t",
     autofilled: "http://mOzilla.org/t",
     completed: "http://mOzilla.org/t"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_path_casing_2() {
   info("Searching for untrimmed cased entry with path 2");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://mOzilla.org/T",
     autofilled: "http://mOzilla.org/Test/",
     completed: "http://mozilla.org/Test/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_path_www_casing() {
   info("Searching for untrimmed cased entry with www and path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://www.mOzilla.org/t",
     autofilled: "http://www.mOzilla.org/t",
     completed: "http://www.mOzilla.org/t"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_path_www_casing_2() {
   info("Searching for untrimmed cased entry with www and path 2");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "http://www.mOzilla.org/T",
     autofilled: "http://www.mOzilla.org/Test/",
     completed: "http://www.mozilla.org/Test/"
   });
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_dupe_urls.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_dupe_urls.js
@@ -9,17 +9,17 @@ add_task(async function test_dupe_urls()
     uri: NetUtil.newURI("http://mozilla.org/"),
     transition: TRANSITION_TYPED
   }, {
     uri: NetUtil.newURI("http://mozilla.org/?")
   });
   await check_autocomplete({
     search: "moz",
     autofilled: "mozilla.org/",
-    completed:  "mozilla.org/",
+    completed:  "http://mozilla.org/",
     matches: [ { uri: NetUtil.newURI("http://mozilla.org/"),
                  title: "mozilla.org",
                  style: [ "autofill", "heuristic" ] } ]
   });
 });
 
 add_task(async function test_dupe_secure_urls() {
   await PlacesTestUtils.addVisits({
--- a/toolkit/components/places/tests/unifiedcomplete/test_enabled.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_enabled.js
@@ -2,30 +2,33 @@ add_task(async function test_enabled() {
   // Test for bug 471903 to make sure searching in autocomplete can be turned on
   // and off. Also test bug 463535 for pref changing search.
   let uri = NetUtil.newURI("http://url/0");
   await PlacesTestUtils.addVisits([ { uri, title: "title" } ]);
 
   info("plain search");
   await check_autocomplete({
     search: "url",
+    searchParam: "prohibit-autofill",
     matches: [ { uri, title: "title" } ]
   });
 
   info("search disabled");
   Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", false);
   await check_autocomplete({
     search: "url",
+    searchParam: "prohibit-autofill",
     matches: [ ]
   });
 
   info("resume normal search");
   Services.prefs.setBoolPref("browser.urlbar.autocomplete.enabled", true);
   await check_autocomplete({
     search: "url",
+    searchParam: "prohibit-autofill",
     matches: [ { uri, title: "title" } ]
   });
 
   await cleanup();
 });
 
 add_task(async function test_linked_enabled_prefs() {
   // Initialize unified complete.
--- a/toolkit/components/places/tests/unifiedcomplete/test_escape_self.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_escape_self.js
@@ -13,19 +13,21 @@ add_task(async function test_escape() {
   await PlacesTestUtils.addVisits([
     { uri: uri1, title: "title" },
     { uri: uri2, title: "title" }
   ]);
 
   info("Unescaped location matches itself");
   await check_autocomplete({
     search: "http://unescapeduri/",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri1, title: "title" } ]
   });
 
   info("Escaped location matches itself");
   await check_autocomplete({
     search: "http://escapeduri/%40/",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri2, title: "title" } ]
   });
 
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js
@@ -12,13 +12,14 @@ add_task(async function test_escape() {
   await PlacesTestUtils.addVisits([
     { uri: uri1, title: "title" },
     { uri: uri2, title: "title" }
   ]);
 
   info("Searching for h matches site and not http://");
   await check_autocomplete({
     search: "h",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri2, title: "title" } ]
   });
 
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_keywords.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keywords.js
@@ -1,77 +1,72 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 add_task(async function test_non_keyword() {
   info("Searching for non-keyworded entry should autoFill it");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/") });
   await check_autocomplete({
     search: "moz",
     autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
+    completed: "http://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_keyword() {
   info("Searching for keyworded entry should not autoFill it");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
   await check_autocomplete({
     search: "moz",
     autofilled: "moz",
     completed: "moz",
   });
   await cleanup();
 });
 
 add_task(async function test_more_than_keyword() {
   info("Searching for more than keyworded entry should autoFill it");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
   await check_autocomplete({
     search: "mozi",
     autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
+    completed: "http://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_less_than_keyword() {
   info("Searching for less than keyworded entry should autoFill it");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
   await check_autocomplete({
     search: "mo",
     autofilled: "mozilla.org/",
-    completed: "mozilla.org/",
+    completed: "http://mozilla.org/",
   });
   await cleanup();
 });
 
 add_task(async function test_keyword_casing() {
   info("Searching for keyworded entry is case-insensitive");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await addBookmark({ uri: NetUtil.newURI("http://mozilla.org/test/"), keyword: "moz" });
   await check_autocomplete({
     search: "MoZ",
     autofilled: "MoZ",
     completed: "MoZ"
   });
   await cleanup();
--- a/toolkit/components/places/tests/unifiedcomplete/test_match_beginning.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_match_beginning.js
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * Test bug 451760 which allows matching only at the beginning of urls or
  * titles to simulate Firefox 2 functionality.
  */
 
 add_task(async function test_match_beginning() {
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
-
   let uri1 = NetUtil.newURI("http://x.com/y");
   let uri2 = NetUtil.newURI("https://y.com/x");
   await PlacesTestUtils.addVisits([
     { uri: uri1, title: "a b" },
     { uri: uri2, title: "b a" }
   ]);
 
   info("Match at the beginning of titles");
@@ -28,22 +26,24 @@ add_task(async function test_match_begin
   await check_autocomplete({
     search: "b",
     matches: [ { uri: uri2, title: "b a" } ]
   });
 
   info("Match at the beginning of urls");
   await check_autocomplete({
     search: "x",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri1, title: "a b" } ]
   });
 
   info("Match at the beginning of urls");
   await check_autocomplete({
     search: "y",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri2, title: "b a" } ]
   });
 
   info("Sanity check that matching anywhere finds more");
   Services.prefs.setIntPref("browser.urlbar.matchBehavior", 1);
   await check_autocomplete({
     search: "a",
     matches: [ { uri: uri1, title: "a b" },
--- a/toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js
@@ -131,149 +131,145 @@ add_task(async function test_scheme_and_
 
   let titlesMap = new Map(sites);
 
   autocompleteObject.populatePreloadedSiteStorage(sites);
 
   let tests =
   [
     // User typed,
-    // Inline autofill,
-    // Substitute after enter is pressed,
+    // Inline autofill (`autofilled`),
+    // Substitute after enter is pressed (`completed`),
     //   [List matches, with sorting]
     //   not tested if omitted
     //   !!! first one is always an autofill entry !!!
 
     [// Protocol by itself doesn't match anything
     "https://",
     "https://",
     "https://",
       []
     ],
 
-    [// "www." by itself doesn't match anything
-    "www.",
+    [
     "www.",
-    "www.",
-      []
+    "www.ooops-https-www.com/",
+    "https://www.ooops-https-www.com/",
+      [
+        ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        "HTTP://www.ooops-HTTP-www.com/",
+        "https://www.bar.com/",
+      ]
     ],
 
-    [// Protocol with "www." by itself doesn't match anything
-    "http://www.",
+    [
     "http://www.",
-    "http://www.",
-      []
+    "http://www.ooops-http-www.com/",
+    "http://www.ooops-http-www.com/",
+      [
+        ["http://www.ooops-http-www.com/", "www.ooops-http-www.com"],
+      ]
     ],
 
-    [// ftp: - ignore
+    [
     "ftp://ooops",
     "ftp://ooops",
     "ftp://ooops",
       []
     ],
 
-    [// Edge case: no "www." in search string, autofill and list entries with "www."
+    [
     "ww",
     "www.ooops-https-www.com/",
-    "https://www.ooops-https-www.com/", // 2nd in list, but has priority as strict
+    "https://www.ooops-https-www.com/",
       [
-      ["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
-      "HTTP://www.ooops-HTTP-www.com/",
-      ["https://foo.com/", "Title with www", ["preloaded-top-site"]],
-      "https://www.bar.com/",
+        ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        "HTTP://www.ooops-HTTP-www.com/",
+        ["https://foo.com/", "Title with www", ["preloaded-top-site"]],
+        "https://www.bar.com/",
       ]
     ],
 
-    [// Strict match, no "www."
+    [
     "ooops",
-    "ooops-https.com/",
-    "https://ooops-https.com/", // 2nd in list, but has priority as strict
-      [// List entries are not sorted (initial sorting preserved)
-       // except autofill entry is on top as always
-      ["https://ooops-https.com/", "https://ooops-https.com"],
-      "https://www.ooops-https-www.com/",
-      "HTTP://ooops-HTTP.com/",
-      "HTTP://www.ooops-HTTP-www.com/",
+    "ooops-https-www.com/",
+    "https://www.ooops-https-www.com/",
+      [
+        ["ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        "https://ooops-https.com/",
+        "HTTP://ooops-HTTP.com/",
+        "HTTP://www.ooops-HTTP-www.com/",
       ]
     ],
 
-    [// Strict match with "www."
+    [
     "www.ooops",
     "www.ooops-https-www.com/",
     "https://www.ooops-https-www.com/",
-      [// Matches with "www." sorted on top
-      ["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
-      "HTTP://www.ooops-HTTP-www.com/",
-      "https://ooops-https.com/",
-      "HTTP://ooops-HTTP.com/",
+      [
+        ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        "HTTP://www.ooops-HTTP-www.com/",
       ]
     ],
 
-    [// Loose match: search no "www.", result with "www."
+    [
     "ooops-https-www",
     "ooops-https-www.com/",
     "https://www.ooops-https-www.com/",
       [
-      ["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        ["ooops-https-www.com/", "https://www.ooops-https-www.com"],
       ]
     ],
 
-    [// Loose match: search "www.", no-www site gets "www."
+    [
+    "www.ooops-https.",
+    "www.ooops-https.",
     "www.ooops-https.",
-    "www.ooops-https.com/",
-    "https://www.ooops-https.com/",
-      [// Only autofill entry gets "www."
-      ["https://www.ooops-https.com/", "https://www.ooops-https.com"],
-      "https://ooops-https.com/", // List entry with preloaded top URL for match site
+      []
+    ],
+
+    [
+    "https://ooops",
+    "https://ooops-https-www.com/",
+    "https://www.ooops-https-www.com/",
+      [
+        ["https://ooops-https-www.com/", "https://www.ooops-https-www.com"],
+        "https://ooops-https.com/",
       ]
     ],
 
-    [// Explicit protocol, no "www."
-    "https://ooops",
-    "https://ooops-https.com/",
-    "https://ooops-https.com/",
-      [
-      ["https://ooops-https.com/", "https://ooops-https.com"],
-      "https://www.ooops-https-www.com/",
-      ]
-    ],
-
-    [// Explicit protocol, with "www."
+    [
     "https://www.ooops",
     "https://www.ooops-https-www.com/",
     "https://www.ooops-https-www.com/",
       [
-      ["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
-      "https://ooops-https.com/",
+        ["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
       ]
     ],
 
-    [// Explicit HTTP protocol, no-www site gets "www."
+    [
+    "http://www.ooops-http.",
     "http://www.ooops-http.",
-    "http://www.ooops-http.com/",
-    "http://www.ooops-http.com/",
-      [
-      ["HTTP://www.ooops-HTTP.com/", "www.ooops-http.com"],
-      "HTTP://ooops-HTTP.com/",
-      ]
+    "http://www.ooops-http.",
+      []
     ],
 
-    [// Wrong protocol
+    [
     "http://ooops-https",
     "http://ooops-https",
     "http://ooops-https",
       []
     ],
   ];
 
   function toMatch(entry, index) {
     if (Array.isArray(entry)) {
       return {
-        uri: NetUtil.newURI(entry[0]),
-        title: entry[1],
+        value: entry[0],
+        comment: entry[1],
         style: entry[2] || ["autofill", "heuristic", "preloaded-top-site"],
       };
     }
     return {
       uri: NetUtil.newURI(entry),
       title: titlesMap.get(entry),
       style: ["preloaded-top-site"],
     };
--- a/toolkit/components/places/tests/unifiedcomplete/test_query_url.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_query_url.js
@@ -1,68 +1,61 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 add_task(async function test_no_slash() {
   info("Searching for host match without slash should match host");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://file.org/test/"),
-    transition: TRANSITION_TYPED
   }, {
     uri: NetUtil.newURI("file:///c:/test.html"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "file",
     autofilled: "file.org/",
-    completed: "file.org/"
+    completed: "http://file.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_w_slash() {
-  info("Searching match with slash at the end should do nothing");
+  info("Searching match with slash at the end should match host");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://file.org/test/"),
-    transition: TRANSITION_TYPED
   }, {
     uri: NetUtil.newURI("file:///c:/test.html"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "file.org/",
     autofilled: "file.org/",
-    completed: "file.org/"
+    completed: "http://file.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_middle() {
   info("Searching match with slash in the middle should match url");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://file.org/test/"),
-    transition: TRANSITION_TYPED
   }, {
     uri: NetUtil.newURI("file:///c:/test.html"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "file.org/t",
     autofilled: "file.org/test/",
     completed: "http://file.org/test/"
   });
   await cleanup();
 });
 
 add_task(async function test_nonhost() {
   info("Searching for non-host match without slash should not match url");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("file:///c:/test.html"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "file",
     autofilled: "file",
     completed: "file"
   });
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_search_engine_host.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_search_engine_host.js
@@ -17,18 +17,18 @@ add_task(async function test_searchEngin
   await PlacesTestUtils.addVisits(visits);
   await addBookmark({ uri, title: "Example bookmark" });
   await PlacesTestUtils.promiseAsyncUpdates();
   ok(frecencyForUrl(uri) > 10000, "Added URI should have expected high frecency");
 
   info("Check search domain is autoFilled even if there's an higher frecency match");
   await check_autocomplete({
     search: "my",
-    autofilled: "my.search.com",
-    completed: "http://my.search.com"
+    autofilled: "my.search.com/",
+    completed: "http://my.search.com/"
   });
 
   await cleanup();
 });
 
 add_task(async function test_searchEngine_noautoFill() {
   let engineName = "engine-rel-searchform.xml";
   let engine = await addTestEngine(engineName);
@@ -36,14 +36,14 @@ add_task(async function test_searchEngin
 
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
   await PlacesTestUtils.addVisits(NetUtil.newURI("http://example.com/my/"));
 
   info("Check search domain is not autoFilled if it matches a visited domain");
   await check_autocomplete({
     search: "example",
     autofilled: "example.com/",
-    completed: "example.com/"
+    completed: "http://example.com/"
   });
 
   await cleanup();
 });
 
--- a/toolkit/components/places/tests/unifiedcomplete/test_search_suggestions.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_search_suggestions.js
@@ -784,17 +784,17 @@ add_task(async function avoid_http_url_s
   Services.prefs.setBoolPref(SUGGEST_PREF, true);
 
   setSuggestionsFn(searchStr => {
     return [searchStr + "ed"];
   });
 
   await check_autocomplete({
     search: "htt",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("htt", { engineName: ENGINE_NAME, heuristic: true }),
       {
         uri: makeActionURI(("searchengine"), {
           engineName: ENGINE_NAME,
           input: "htted",
           searchQuery: "htt",
           searchSuggestion: "htted",
@@ -803,41 +803,41 @@ add_task(async function avoid_http_url_s
         style: ["action", "searchengine", "suggestion"],
         icon: "",
       },
     ],
   });
 
   await check_autocomplete({
     search: "ftp",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("ftp", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "http",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("http", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "https",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("https", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "httpd",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("httpd", { engineName: ENGINE_NAME, heuristic: true }),
       {
         uri: makeActionURI(("searchengine"), {
           engineName: ENGINE_NAME,
           input: "httpded",
           searchQuery: "httpd",
           searchSuggestion: "httpded",
@@ -846,173 +846,169 @@ add_task(async function avoid_http_url_s
         style: ["action", "searchengine", "suggestion"],
         icon: "",
       },
     ],
   });
 
   await check_autocomplete({
     search: "http:",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
+//     matches: [
+//       {
+//         uri: makeActionURI("visiturl", { url: "http://http/", input: "http:" }),
+//         style: [ "action", "visiturl", "heuristic" ],
+//         title: "http://http/",
+//       },
+//     ],
+
     matches: [
-      {
-        uri: makeActionURI("visiturl", { url: "http://http/", input: "http:" }),
-        style: [ "action", "visiturl", "heuristic" ],
-        title: "http://http/",
-      },
+      makeSearchMatch("http:", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "https:",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
-      {
-        uri: makeActionURI("visiturl", { url: "http://https/", input: "https:" }),
-        style: [ "action", "visiturl", "heuristic" ],
-        title: "http://https/",
-      },
+      makeSearchMatch("https:", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "ftp:",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
-      {
-        uri: makeActionURI("visiturl", { url: "http://ftp/", input: "ftp:" }),
-        style: [ "action", "visiturl", "heuristic" ],
-        title: "http://ftp/",
-      },
+      makeSearchMatch("ftp:", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "http:/",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://http/", input: "http:/" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://http/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "https:/",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://https/", input: "https:/" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://https/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "ftp:/",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://ftp/", input: "ftp:/" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://ftp/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "http://",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("http://", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "https://",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("https://", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "ftp://",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       makeSearchMatch("ftp://", { engineName: ENGINE_NAME, heuristic: true }),
     ],
   });
 
   await check_autocomplete({
     search: "http://www",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://www/", input: "http://www" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://www/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "https://www",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "https://www/", input: "https://www" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "https://www/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "http://test",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://test/", input: "http://test" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://test/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "https://test",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "https://test/", input: "https://test" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "https://test/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "ftp://test",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "ftp://test/", input: "ftp://test" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "ftp://test/",
       },
     ],
   });
 
   await check_autocomplete({
     search: "http://www.test",
-    searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [
       {
         uri: makeActionURI("visiturl", { url: "http://www.test/", input: "http://www.test" }),
         style: [ "action", "visiturl", "heuristic" ],
         title: "http://www.test/",
       },
     ],
   });
--- a/toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js
@@ -1,12 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
+//XXXadw is this right?  this test disables autofill.  seems like the patch
+// shouldn't affect non-autofill matches...?
+//XXXadw and at least most/all of these info()s are now wrong, need to be
+// updated.
+
 /**
  * Test bug 424717 to make sure searching with an existing location like
  * http://site/ also matches https://site/ or ftp://site/. Same thing for
  * ftp://site/ and https://site/.
  *
  * Test bug 461483 to make sure a search for "w" doesn't match the "www." from
  * site subdomains.
  */
@@ -36,29 +41,40 @@ add_task(async function test_swap_protoc
     { uri: uri2, title: "title" },
     { uri: uri3, title: "title" },
     { uri: uri4, title: "title" },
     { uri: uri5, title: "title" },
     { uri: uri6, title: "title" }
   ];
 
   // Disable autoFill to avoid handling the first result.
-  Services.prefs.setBoolPref("browser.urlbar.autoFill", "false");
+  Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
   Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
 
   info("http://www.site matches all site");
   await check_autocomplete({
     search: "http://www.site",
-    matches: allMatches
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+    ]
+//     matches: allMatches
   });
 
   info("http://site matches all site");
   await check_autocomplete({
     search: "http://site",
-    matches: allMatches
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri2, title: "title" },
+      { uri: uri3, title: "title" },
+      { uri: uri4, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri6, title: "title" },
+    ]
   });
 
   info("ftp://ftp.site matches itself");
   await check_autocomplete({
     search: "ftp://ftp.site",
     matches: [ { uri: uri3, title: "title" } ]
   });
 
@@ -66,88 +82,118 @@ add_task(async function test_swap_protoc
   await check_autocomplete({
     search: "ftp://site",
     matches: allMatches
   });
 
   info("https://www.site matches all site");
   await check_autocomplete({
     search: "https://www.site",
-    matches: allMatches
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+    ]
   });
 
   info("https://site matches all site");
   await check_autocomplete({
     search: "https://site",
-    matches: allMatches
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri2, title: "title" },
+      { uri: uri3, title: "title" },
+      { uri: uri4, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri6, title: "title" },
+    ]
   });
 
   info("www.site matches all site");
   await check_autocomplete({
     search: "www.site",
-    matches: allMatches
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+    ]
   });
 
   info("w matches none of www.");
   await check_autocomplete({
     search: "w",
-    matches: [ { uri: uri7, title: "title" },
-               { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri7, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://w matches none of www.");
   await check_autocomplete({
     search: "http://w",
-    matches: [ { uri: uri7, title: "title" },
-               { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri7, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://w matches none of www.");
   await check_autocomplete({
     search: "http://www.w",
-    matches: [ { uri: uri7, title: "title" },
-               { uri: uri8, title: "title" } ]
+    matches: []
   });
 
   info("ww matches none of www.");
   await check_autocomplete({
     search: "ww",
-    matches: [ { uri: uri8, title: "title" } ]
-  });
-
-  info("ww matches none of www.");
-  await check_autocomplete({
-    search: "ww",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://ww matches none of www.");
   await check_autocomplete({
     search: "http://ww",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://www.ww matches none of www.");
   await check_autocomplete({
     search: "http://www.ww",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: []
   });
 
   info("www matches none of www.");
   await check_autocomplete({
     search: "www",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://www matches none of www.");
   await check_autocomplete({
     search: "http://www",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: [
+      { uri: uri1, title: "title" },
+      { uri: uri5, title: "title" },
+      { uri: uri8, title: "title" },
+    ]
   });
 
   info("http://www.www matches none of www.");
   await check_autocomplete({
     search: "http://www.www",
-    matches: [ { uri: uri8, title: "title" } ]
+    matches: []
   });
 
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js
@@ -20,145 +20,159 @@ add_task(async function test_tab_matches
   addOpenPages(uri1, 1);
   // Pages that cannot be registered in history.
   addOpenPages(uri3, 1);
   addOpenPages(uri4, 1);
 
   info("two results, normal result is a tab match");
   await check_autocomplete({
     search: "abc.com",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeVisitMatch("abc.com", "http://abc.com/", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSearchMatch("abc.com", { heuristic: false }) ]
   });
 
   info("three results, one tab match");
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] },
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("three results, both normal results are tab matches");
   addOpenPages(uri2, 1);
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("http://xyz.net/", { title: "xyz.net - we're better than ABC" }),
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("a container tab is not visible in 'switch to tab'");
   addOpenPages(uri5, 1, /* userContextId: */ 3);
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("http://xyz.net/", { title: "xyz.net - we're better than ABC" }),
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("a container tab should not see 'switch to tab' for other container tabs");
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions user-context-id:3",
+//     searchParam: "enable-actions user-context-id:3",
+    searchParam: "enable-actions user-context-id:3 prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://foobar.org/", { title: "foobar.org - much better than ABC, definitely better than XYZ" }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] } ]
   });
 
   info("a different container tab should not see any 'switch to tab'");
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions user-context-id:2",
+//     searchParam: "enable-actions user-context-id:2",
+    searchParam: "enable-actions user-context-id:2 prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] },
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("three results, both normal results are tab matches, one has multiple tabs");
   addOpenPages(uri2, 5);
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("http://xyz.net/", { title: "xyz.net - we're better than ABC" }),
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("three results, no tab matches (disable-private-actions)");
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions disable-private-actions",
+//     searchParam: "enable-actions disable-private-actions",
+    searchParam: "enable-actions disable-private-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] },
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("two results (actions disabled)");
   await check_autocomplete({
     search: "abc",
-    searchParam: "",
+//     searchParam: "",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] },
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("three results, no tab matches");
   removeOpenPages(uri1, 1);
   removeOpenPages(uri2, 6);
   await check_autocomplete({
     search: "abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("abc", { heuristic: true }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] },
                { uri: uri5, title: "foobar.org - much better than ABC, definitely better than XYZ", style: [ "favicon" ] } ]
   });
 
   info("tab match search with restriction character");
   addOpenPages(uri1, 1);
   await check_autocomplete({
     search: gTabRestrictChar + " abc",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch(gTabRestrictChar + " abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }) ]
   });
 
   info("tab match with not-addable pages");
   await check_autocomplete({
     search: "mozilla",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch("mozilla", { heuristic: true }),
                makeSwitchToTabMatch("about:mozilla") ]
   });
 
   info("tab match with not-addable pages and restriction character");
   await check_autocomplete({
     search: gTabRestrictChar + " mozilla",
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch(gTabRestrictChar + " mozilla", { heuristic: true }),
                makeSwitchToTabMatch("about:mozilla") ]
   });
 
   info("tab match with not-addable pages and only restriction character");
   await check_autocomplete({
     search: gTabRestrictChar,
-    searchParam: "enable-actions",
+//     searchParam: "enable-actions",
+    searchParam: "enable-actions prohibit-autofill",
     matches: [ makeSearchMatch(gTabRestrictChar, { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("about:mozilla"),
                makeSwitchToTabMatch("data:text/html,test") ]
   });
 
   await cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_trimming.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_trimming.js
@@ -1,313 +1,120 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 add_task(async function test_untrimmed_secure_www() {
   info("Searching for untrimmed https://www entry");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("https://www.mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mo",
     autofilled: "mozilla.org/",
     completed: "https://www.mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_secure_www_path() {
   info("Searching for untrimmed https://www entry with path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("https://www.mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/t",
     autofilled: "mozilla.org/test/",
     completed: "https://www.mozilla.org/test/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_secure() {
   info("Searching for untrimmed https:// entry");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("https://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mo",
     autofilled: "mozilla.org/",
     completed: "https://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_secure_path() {
   info("Searching for untrimmed https:// entry with path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("https://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/t",
     autofilled: "mozilla.org/test/",
     completed: "https://mozilla.org/test/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_www() {
   info("Searching for untrimmed http://www entry");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mo",
     autofilled: "mozilla.org/",
-    completed: "www.mozilla.org/"
+    completed: "http://www.mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_www_path() {
   info("Searching for untrimmed http://www entry with path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("http://www.mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/t",
     autofilled: "mozilla.org/test/",
     completed: "http://www.mozilla.org/test/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_ftp() {
   info("Searching for untrimmed ftp:// entry");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mo",
     autofilled: "mozilla.org/",
     completed: "ftp://mozilla.org/"
   });
   await cleanup();
 });
 
 add_task(async function test_untrimmed_ftp_path() {
   info("Searching for untrimmed ftp:// entry with path");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("ftp://mozilla.org/test/"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "mozilla.org/t",
     autofilled: "mozilla.org/test/",
     completed: "ftp://mozilla.org/test/"
   });
   await cleanup();
 });
 
-add_task(async function test_priority_1() {
-  info("Ensuring correct priority 1");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("https://www.mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("https://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("ftp://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://www.mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.org/test/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_priority_2() {
-  info( "Ensuring correct priority 2");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("https://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("ftp://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://www.mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.org/test/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_priority_3() {
-  info("Ensuring correct priority 3");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("ftp://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://www.mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.org/test/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_priority_4() {
-  info("Ensuring correct priority 4");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("http://www.mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.org/test/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "www.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_priority_5() {
-  info("Ensuring correct priority 5");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("ftp://mozilla.org/test/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("ftp://www.mozilla.org/test/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "ftp://mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_priority_6() {
-  info("Ensuring correct priority 6");
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("http://www.mozilla.org/test1/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://www.mozilla.org/test2/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.org/",
-    completed: "www.mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_longer_domain() {
-  info("Ensuring longer domain can't match");
-  // The .co should be preferred, but should not get the https from the .com.
-  // The .co domain must be added later to activate the trigger bug.
-  await PlacesTestUtils.addVisits([
-    { uri: NetUtil.newURI("https://mozilla.com/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.co/"), transition: TRANSITION_TYPED },
-    { uri: NetUtil.newURI("http://mozilla.co/"), transition: TRANSITION_TYPED }
-  ]);
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "mozilla.co/",
-    completed: "mozilla.co/"
-  });
-
-  await cleanup();
-});
-
 add_task(async function test_escaped_chars() {
   info("Searching for URL with characters that are normally escaped");
   await PlacesTestUtils.addVisits({
     uri: NetUtil.newURI("https://www.mozilla.org/啊-test"),
-    transition: TRANSITION_TYPED
   });
   await check_autocomplete({
     search: "https://www.mozilla.org/啊-test",
     autofilled: "https://www.mozilla.org/啊-test",
     completed: "https://www.mozilla.org/啊-test"
   });
   await cleanup();
 });
-
-add_task(async function test_unsecure_secure() {
-  info("Don't return unsecure URL when searching for secure ones");
-  await PlacesTestUtils.addVisits({
-    uri: NetUtil.newURI("http://test.moz.org/test/"),
-    transition: TRANSITION_TYPED
-  });
-  await check_autocomplete({
-    search: "https://test.moz.org/t",
-    autofilled: "https://test.moz.org/test/",
-    completed: "https://test.moz.org/test/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_unsecure_secure_domain() {
-  info("Don't return unsecure domain when searching for secure ones");
-  await PlacesTestUtils.addVisits({
-    uri: NetUtil.newURI("http://test.moz.org/test/"),
-    transition: TRANSITION_TYPED
-  });
-  await check_autocomplete({
-    search: "https://test.moz",
-    autofilled: "https://test.moz.org/",
-    completed: "https://test.moz.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_untyped_www() {
-  info("Untyped is not accounted for www");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://www.moz.org/test/") });
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "moz.org/",
-    completed: "moz.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_untyped_ftp() {
-  info("Untyped is not accounted for ftp");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("ftp://moz.org/test/") });
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "moz.org/",
-    completed: "moz.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_untyped_secure() {
-  info("Untyped is not accounted for https");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://moz.org/test/") });
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "moz.org/",
-    completed: "moz.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_untyped_secure_www() {
-  info("Untyped is not accounted for https://www");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("https://www.moz.org/test/") });
-  await check_autocomplete({
-    search: "mo",
-    autofilled: "moz.org/",
-    completed: "moz.org/"
-  });
-  await cleanup();
-});
deleted file mode 100644
--- a/toolkit/components/places/tests/unifiedcomplete/test_typed.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-// First do searches with typed behavior forced to false, so later tests will
-// ensure autocomplete is able to dinamically switch behavior.
-
-const FAVICON_HREF = NetUtil.newURI(do_get_file("../favicons/favicon-normal16.png")).spec;
-
-add_task(async function test_domain() {
-  info("Searching for domain should autoFill it");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
-  await setFaviconForPage("http://mozilla.org/link/", FAVICON_HREF);
-  await check_autocomplete({
-    search: "moz",
-    autofilled: "mozilla.org/",
-    completed: "mozilla.org/",
-    icon: "moz-anno:favicon:" + FAVICON_HREF
-  });
-  await cleanup();
-});
-
-add_task(async function test_url() {
-  info("Searching for url should autoFill it");
-  Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
-  await setFaviconForPage("http://mozilla.org/link/", FAVICON_HREF);
-  await check_autocomplete({
-    search: "mozilla.org/li",
-    autofilled: "mozilla.org/link/",
-    completed: "http://mozilla.org/link/",
-    icon: "moz-anno:favicon:" + FAVICON_HREF
-  });
-  await cleanup();
-});
-
-// Now do searches with typed behavior forced to true.
-
-add_task(async function test_untyped_domain() {
-  info("Searching for non-typed domain should not autoFill it");
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
-  await check_autocomplete({
-    search: "moz",
-    autofilled: "moz",
-    completed: "moz"
-  });
-  await cleanup();
-});
-
-add_task(async function test_typed_domain() {
-  info("Searching for typed domain should autoFill it");
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/typed/"),
-                           transition: TRANSITION_TYPED });
-  await check_autocomplete({
-    search: "moz",
-    autofilled: "mozilla.org/",
-    completed: "mozilla.org/"
-  });
-  await cleanup();
-});
-
-add_task(async function test_untyped_url() {
-  info("Searching for non-typed url should not autoFill it");
-  await PlacesTestUtils.addVisits(NetUtil.newURI("http://mozilla.org/link/"));
-  await check_autocomplete({
-    search: "mozilla.org/li",
-    autofilled: "mozilla.org/li",
-    completed: "mozilla.org/li"
-  });
-  await cleanup();
-});
-
-add_task(async function test_typed_url() {
-  info("Searching for typed url should autoFill it");
-  await PlacesTestUtils.addVisits({ uri: NetUtil.newURI("http://mozilla.org/link/"),
-                           transition: TRANSITION_TYPED });
-  await check_autocomplete({
-    search: "mozilla.org/li",
-    autofilled: "mozilla.org/link/",
-    completed: "http://mozilla.org/link/"
-  });
-  await cleanup();
-});
--- a/toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js
@@ -73,16 +73,17 @@ add_task(async function test_escape() {
                { uri: uri4, title: "dontmatchme3" },
                { uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
                { uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] } ]
   });
 
   info("Match 't' at the beginning or after /");
   await check_autocomplete({
     search: "t",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri1, title: "title1" },
                { uri: uri2, title: "title1" },
                { uri: uri3, title: "matchme2" },
                { uri: uri4, title: "dontmatchme3" },
                { uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
                { uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] },
                { uri: uri10, title: "title1" } ]
   });
@@ -91,16 +92,17 @@ add_task(async function test_escape() {
   await check_autocomplete({
     search: "word",
     matches: [ { uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" } ]
   });
 
   info("Match a word boundary '/' for everything");
   await check_autocomplete({
     search: "/",
+    searchParam: "prohibit-autofill",
     matches: [ { uri: uri1, title: "title1" },
                { uri: uri2, title: "title1" },
                { uri: uri3, title: "matchme2" },
                { uri: uri4, title: "dontmatchme3" },
                { uri: uri5, title: "title1", tags: [ "matchme2" ], style: [ "bookmark-tag" ] },
                { uri: uri6, title: "title1", tags: [ "dontmatchme3" ], style: [ "bookmark-tag" ] },
                { uri: uri7, title: "!@#$%^&*()_+{}|:<>?word" },
                { uri: uri8, title: katakana.join("") },
--- a/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
+++ b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
@@ -9,17 +9,21 @@ support-files =
 
 [test_416211.js]
 [test_416214.js]
 [test_417798.js]
 [test_418257.js]
 [test_422277.js]
 [test_autocomplete_functional.js]
 [test_autocomplete_stopSearch_no_throw.js]
-[test_autofill_default_behavior.js]
+[test_autofill_origins.js]
+head = head_autocomplete.js head_autofill.js
+[test_autofill_search_engines.js]
+[test_autofill_urls.js]
+head = head_autocomplete.js head_autofill.js
 [test_avoid_middle_complete.js]
 [test_avoid_stripping_to_empty_tokens.js]
 [test_casing.js]
 [test_do_not_trim.js]
 [test_download_embed_bookmarks.js]
 [test_dupe_urls.js]
 [test_empty_search.js]
 [test_enabled.js]
@@ -42,12 +46,11 @@ skip-if = !sync
 [test_search_engine_current.js]
 [test_search_engine_host.js]
 [test_search_engine_restyle.js]
 [test_search_suggestions.js]
 [test_special_search.js]
 [test_swap_protocol.js]
 [test_tab_matches.js]
 [test_trimming.js]
-[test_typed.js]
 [test_visit_url.js]
 [test_word_boundary_search.js]
 [test_zero_frecency.js]
--- a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
+++ b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
@@ -114,16 +114,23 @@ function addAdaptiveFeedback(aUrl, aSear
       searchString: aSearch
     };
 
     Services.obs.notifyObservers(thing, "autocomplete-will-enter-text");
   });
 }
 
 
+add_task(function init() {
+  Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("browser.urlbar.autoFill");
+  });
+});
+
 add_task(async function test_adaptive_search_specific() {
   // Add a bookmark to our url.
   await PlacesUtils.bookmarks.insert({
     parentGuid: PlacesUtils.bookmarks.unfiledGuid,
     title: "test_book",
     url: TEST_URL,
   });
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_frecency_stats.js
@@ -0,0 +1,130 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+"use strict";
+
+add_task(async function init() {
+  await cleanUp();
+});
+
+add_task(async function basic() {
+  Assert.equal(PlacesUtils.history.frecencyMean, 0);
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation, 0);
+
+  let frecenciesByURL = {};
+  let urls = [0, 1, 2].map(i => "http://example.com/" + i);
+
+  // Add a URL 0 visit.
+  await PlacesTestUtils.addVisits([{ uri: urls[0] }]);
+  frecenciesByURL[urls[0]] = frecencyForUrl(urls[0]);
+  Assert.ok(frecenciesByURL[urls[0]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Add a URL 1 visit.
+  await PlacesTestUtils.addVisits([{ uri: urls[1] }]);
+  frecenciesByURL[urls[1]] = frecencyForUrl(urls[1]);
+  Assert.ok(frecenciesByURL[urls[1]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Add a URL 2 visit.
+  await PlacesTestUtils.addVisits([{ uri: urls[2] }]);
+  frecenciesByURL[urls[2]] = frecencyForUrl(urls[2]);
+  Assert.ok(frecenciesByURL[urls[2]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Add another URL 2 visit.
+  await PlacesTestUtils.addVisits([{ uri: urls[2] }]);
+  frecenciesByURL[urls[2]] = frecencyForUrl(urls[2]);
+  Assert.ok(frecenciesByURL[urls[2]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Remove URL 2's visits.
+  await PlacesUtils.history.remove([urls[2]]);
+  delete frecenciesByURL[urls[2]];
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Bookmark URL 1.
+  let bookmark = await addBookmark({ uri: NetUtil.newURI(urls[1]) });
+  frecenciesByURL[urls[1]] = frecencyForUrl(urls[1]);
+  Assert.ok(frecenciesByURL[urls[1]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Remove URL 1's visit.
+  await PlacesUtils.history.remove([urls[1]]);
+  frecenciesByURL[urls[1]] = frecencyForUrl(urls[1]);
+  Assert.ok(frecenciesByURL[urls[1]] > 0, "Sanity check");
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Remove URL 1's bookmark.  Also need to call history.remove() again to
+  // remove the URL from moz_places.  Otherwise it sticks around and keeps
+  // contributing to the frecency stats.
+  await PlacesUtils.bookmarks.remove(bookmark);
+  await PlacesUtils.history.remove(urls[1]);
+  delete frecenciesByURL[urls[1]];
+  Assert.equal(PlacesUtils.history.frecencyMean,
+               mean(Object.values(frecenciesByURL)));
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation,
+               stddev(Object.values(frecenciesByURL)));
+
+  // Remove URL 0.
+  await PlacesUtils.history.remove([urls[0]]);
+  delete frecenciesByURL[urls[0]];
+  Assert.equal(PlacesUtils.history.frecencyMean, 0);
+  Assert.equal(PlacesUtils.history.frecencyStandardDeviation, 0);
+
+  await cleanUp();
+});
+
+function mean(values) {
+  if (values.length == 0) {
+    return 0;
+  }
+  return values.reduce((sum, value) => {
+    sum += value;
+    return sum;
+  }, 0) / values.length;
+}
+
+function stddev(values) {
+  if (values.length <= 1) {
+    return 0;
+  }
+  let sum = values.reduce((memo, value) => {
+    memo += value;
+    return memo;
+  }, 0);
+  let sumOfSquares = values.reduce((memo, value) => {
+    memo += value * value;
+    return memo;
+  }, 0);
+  return Math.sqrt(
+    (sumOfSquares - ((sum * sum) / values.length)) / values.length
+  );
+}
+
+async function cleanUp() {
+  await PlacesUtils.bookmarks.eraseEverything();
+  await PlacesTestUtils.clearHistory();
+}
rename from toolkit/components/places/tests/unit/test_hosts_triggers.js
rename to toolkit/components/places/tests/unit/test_origins.js
--- a/toolkit/components/places/tests/unit/test_hosts_triggers.js
+++ b/toolkit/components/places/tests/unit/test_origins.js
@@ -1,377 +1,430 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */