--- 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><;
}
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/ */