Bug 598229 (part 2) - Increase performance of Win7 JumpList favorites queries. r=sdwilsh,jimm sr=rstrong a=blocking

This commit is contained in:
Marco Bonardo 2010-10-14 10:46:38 +02:00
Родитель f0e456d04f
Коммит 00b2650bc7
6 изменённых файлов: 383 добавлений и 106 удалений

Просмотреть файл

@ -961,7 +961,7 @@ pref("browser.taskbar.lists.frequent.enabled", true);
pref("browser.taskbar.lists.recent.enabled", false); pref("browser.taskbar.lists.recent.enabled", false);
pref("browser.taskbar.lists.maxListItemCount", 7); pref("browser.taskbar.lists.maxListItemCount", 7);
pref("browser.taskbar.lists.tasks.enabled", true); pref("browser.taskbar.lists.tasks.enabled", true);
pref("browser.taskbar.lists.refreshInSeconds", 30); pref("browser.taskbar.lists.refreshInSeconds", 120);
#endif #endif
#endif #endif

Просмотреть файл

@ -21,6 +21,7 @@
* *
* Contributor(s): * Contributor(s):
* Jim Mathies <jmathies@mozilla.com> (Original author) * Jim Mathies <jmathies@mozilla.com> (Original author)
* Marco Bonardo <mak77@bonardo.net>
* *
* Alternatively, the contents of this file may be used under the terms of * Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -46,6 +47,9 @@ Components.utils.import("resource://gre/modules/Services.jsm");
const Cc = Components.classes; const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
// Stop updating jumplists after some idle time.
const IDLE_TIMEOUT_SECONDS = 5 * 60;
// Prefs // Prefs
const PREF_TASKBAR_BRANCH = "browser.taskbar.lists."; const PREF_TASKBAR_BRANCH = "browser.taskbar.lists.";
const PREF_TASKBAR_ENABLED = "enabled"; const PREF_TASKBAR_ENABLED = "enabled";
@ -55,6 +59,12 @@ const PREF_TASKBAR_RECENT = "recent.enabled";
const PREF_TASKBAR_TASKS = "tasks.enabled"; const PREF_TASKBAR_TASKS = "tasks.enabled";
const PREF_TASKBAR_REFRESH = "refreshInSeconds"; const PREF_TASKBAR_REFRESH = "refreshInSeconds";
// Hash keys for pendingStatements.
const LIST_TYPE = {
FREQUENT: 0
, RECENT: 1
}
/** /**
* Exports * Exports
*/ */
@ -87,6 +97,10 @@ XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
return NetUtil; return NetUtil;
}); });
XPCOMUtils.defineLazyServiceGetter(this, "_idle",
"@mozilla.org/widget/idleservice;1",
"nsIIdleService");
XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService", XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService",
"@mozilla.org/windows-taskbar;1", "@mozilla.org/windows-taskbar;1",
"nsIWinTaskbar"); "nsIWinTaskbar");
@ -129,7 +143,9 @@ var tasksCfg = [
args: "-new-tab about:blank", args: "-new-tab about:blank",
iconIndex: 0, // Fx app icon iconIndex: 0, // Fx app icon
open: true, open: true,
close: false, // The jump list already has an app launch icon close: true, // The jump list already has an app launch icon, but
// we don't always update the list on shutdown.
// Thus true for consistency.
}, },
// Open new tab // Open new tab
@ -139,7 +155,8 @@ var tasksCfg = [
args: "-browser", args: "-browser",
iconIndex: 0, // Fx app icon iconIndex: 0, // Fx app icon
open: true, open: true,
close: false, // no point close: true, // No point, but we don't always update the list on
// shutdown. Thus true for consistency.
}, },
// Toggle the Private Browsing mode // Toggle the Private Browsing mode
@ -202,7 +219,7 @@ var WinTaskbarJumpList =
this._initObs(); this._initObs();
// jump list refresh timer // jump list refresh timer
this._initTimer(); this._updateTimer();
}, },
update: function WTBJL_update() { update: function WTBJL_update() {
@ -216,7 +233,14 @@ var WinTaskbarJumpList =
_shutdown: function WTBJL__shutdown() { _shutdown: function WTBJL__shutdown() {
this._shuttingDown = true; this._shuttingDown = true;
this.update();
// Correctly handle a clear history on shutdown. If there are no
// entries be sure to empty all history lists. Luckily Places caches
// this value, so it's a pretty fast call.
if (!PlacesUtils.history.hasHistoryEntries) {
this.update();
}
this._free(); this._free();
}, },
@ -226,9 +250,34 @@ var WinTaskbarJumpList =
/** /**
* List building * List building
*/ *
* @note Async builders must add their mozIStoragePendingStatement to
* _pendingStatements object, using a different LIST_TYPE entry for
* each statement. Once finished they must remove it and call
* commitBuild(). When there will be no more _pendingStatements,
* commitBuild() will commit for real.
*/
_pendingStatements: {},
_hasPendingStatements: function WTBJL__hasPendingStatements() {
for (let listType in this._pendingStatements) {
return true;
}
return false;
},
_buildList: function WTBJL__buildList() { _buildList: function WTBJL__buildList() {
if (this._hasPendingStatements()) {
// We were requested to update the list while another update was in
// progress, this could happen at shutdown, idle or privatebrowsing.
// Abort the current list building.
for (let listType in this._pendingStatements) {
this._pendingStatements[listType].cancel();
delete this._pendingStatements[listType];
}
this._builder.abortListBuild();
}
// anything to build? // anything to build?
if (!this._showFrequent && !this._showRecent && !this._showTasks) { if (!this._showFrequent && !this._showRecent && !this._showTasks) {
// don't leave the last list hanging on the taskbar. // don't leave the last list hanging on the taskbar.
@ -269,8 +318,9 @@ var WinTaskbarJumpList =
}, },
_commitBuild: function WTBJL__commitBuild() { _commitBuild: function WTBJL__commitBuild() {
if (!this._builder.commitListBuild()) if (!this._hasPendingStatements() && !this._builder.commitListBuild()) {
this._builder.abortListBuild(); this._builder.abortListBuild();
}
}, },
_buildTasks: function WTBJL__buildTasks() { _buildTasks: function WTBJL__buildTasks() {
@ -301,46 +351,67 @@ var WinTaskbarJumpList =
var items = Cc["@mozilla.org/array;1"]. var items = Cc["@mozilla.org/array;1"].
createInstance(Ci.nsIMutableArray); createInstance(Ci.nsIMutableArray);
var list = this._getNavFrequent(this._maxItemCount);
if (!list || list.length == 0)
return;
// track frequent items so that we don't add them to // track frequent items so that we don't add them to
// the recent list. // the recent list.
this._frequentHashList = []; this._frequentHashList = [];
list.forEach(function (entry) { this._pendingStatements[LIST_TYPE.FREQUENT] = this._getHistoryResults(
let shortcut = this._getHandlerAppItem(entry.title, entry.title, entry.uri, 1); Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING,
items.appendElement(shortcut, false); this._maxItemCount,
this._frequentHashList.push(entry.uri); function (aResult) {
}, this); if (!aResult) {
this._buildCustom(_getString("taskbar.frequent.label"), items); delete this._pendingStatements[LIST_TYPE.FREQUENT];
// The are no more results, build the list.
this._buildCustom(_getString("taskbar.frequent.label"), items);
this._commitBuild();
return;
}
let title = aResult.title || aResult.uri;
let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1);
items.appendElement(shortcut, false);
this._frequentHashList.push(aResult.uri);
},
this
);
}, },
_buildRecent: function WTBJL__buildRecent() { _buildRecent: function WTBJL__buildRecent() {
var items = Cc["@mozilla.org/array;1"]. var items = Cc["@mozilla.org/array;1"].
createInstance(Ci.nsIMutableArray); createInstance(Ci.nsIMutableArray);
var list = this._getNavRecent(this._maxItemCount*2); // Frequent items will be skipped, so we select a double amount of
// entries and stop fetching results at _maxItemCount.
var count = 0;
if (!list || list.length == 0) this._pendingStatements[LIST_TYPE.RECENT] = this._getHistoryResults(
return; Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING,
this._maxItemCount * 2,
function (aResult) {
if (!aResult) {
// The are no more results, build the list.
this._buildCustom(_getString("taskbar.recent.label"), items);
delete this._pendingStatements[LIST_TYPE.RECENT];
this._commitBuild();
return;
}
let count = 0; if (count >= this._maxItemCount) {
for (let idx = 0; idx < list.length; idx++) { return;
if (count >= this._maxItemCount) }
break;
let entry = list[idx]; // Do not add items to recent that have already been added to frequent.
// do not add items to recent that have already been added if (this._frequentHashList &&
// to frequent. this._frequentHashList.indexOf(aResult.uri) != -1) {
if (this._frequentHashList && return;
this._frequentHashList.indexOf(entry.uri) != -1) }
continue;
let shortcut = this._getHandlerAppItem(entry.title, entry.title, entry.uri, 1); let title = aResult.title || aResult.uri;
items.appendElement(shortcut, false); let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1);
count++; items.appendElement(shortcut, false);
} count++;
this._buildCustom(_getString("taskbar.recent.label"), items); },
this
);
}, },
_deleteActiveJumpList: function WTBJL__deleteAJL() { _deleteActiveJumpList: function WTBJL__deleteAJL() {
@ -381,79 +452,57 @@ var WinTaskbarJumpList =
/** /**
* Nav history helpers * Nav history helpers
*/ */
_getNavFrequent: function WTBJL__getNavFrequent(depth) { _getHistoryResults:
var options = PlacesUtils.history.getNewQueryOptions(); function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) {
var query = PlacesUtils.history.getNewQuery();
query.beginTimeReference = query.TIME_RELATIVE_NOW;
query.beginTime = -24 * 30 * 60 * 60 * 1000000; // one month
query.endTimeReference = query.TIME_RELATIVE_NOW;
options.maxResults = depth;
options.queryType = options.QUERY_TYPE_HISTORY;
options.sortingMode = options.SORT_BY_VISITCOUNT_DESCENDING;
options.resultType = options.RESULT_TYPE_URI;
var result = PlacesUtils.history.executeQuery(query, options);
var list = [];
var rootNode = result.root;
rootNode.containerOpen = true;
for (let idx = 0; idx < rootNode.childCount; idx++) {
let node = rootNode.getChild(idx);
list.push({uri: node.uri, title: node.title});
}
rootNode.containerOpen = false;
return list;
},
_getNavRecent: function WTBJL__getNavRecent(depth) {
var options = PlacesUtils.history.getNewQueryOptions(); var options = PlacesUtils.history.getNewQueryOptions();
options.maxResults = aLimit;
options.sortingMode = aSortingMode;
// We don't want source redirects for these queries.
options.redirectsMode = Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET;
var query = PlacesUtils.history.getNewQuery(); var query = PlacesUtils.history.getNewQuery();
query.beginTimeReference = query.TIME_RELATIVE_NOW; // Return the pending statement to the caller, to allow cancelation.
query.beginTime = -48 * 60 * 60 * 1000000; // two days return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
query.endTimeReference = query.TIME_RELATIVE_NOW; .asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
options.maxResults = depth; for (let row; (row = aResultSet.getNextRow());) {
options.queryType = options.QUERY_TYPE_HISTORY; try {
options.sortingMode = options.SORT_BY_LASTMODIFIED_DESCENDING; aCallback.call(aScope,
options.resultType = options.RESULT_TYPE_URI; { uri: row.getResultByIndex(1)
, title: row.getResultByIndex(2)
var result = PlacesUtils.history.executeQuery(query, options); });
} catch (e) {}
var list = []; }
},
var rootNode = result.root; handleError: function (aError) {
rootNode.containerOpen = true; Components.utils.reportError(
"Async execution error (" + aError.result + "): " + aError.message);
for (var idx = 0; idx < rootNode.childCount; idx++) { },
var node = rootNode.getChild(idx); handleCompletion: function (aReason) {
list.push({uri: node.uri, title: node.title}); aCallback.call(WinTaskbarJumpList, null);
} },
rootNode.containerOpen = false; });
return list;
}, },
_clearHistory: function WTBJL__clearHistory(items) { _clearHistory: function WTBJL__clearHistory(items) {
if (!items) if (!items)
return; return;
var URIsToRemove = [];
var enum = items.enumerate(); var enum = items.enumerate();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
let oldItem = enum.getNext().QueryInterface(Ci.nsIJumpListShortcut); let oldItem = enum.getNext().QueryInterface(Ci.nsIJumpListShortcut);
if (oldItem) { if (oldItem) {
try { // in case we get a bad uri try { // in case we get a bad uri
let uriSpec = oldItem.app.getParameter(0); let uriSpec = oldItem.app.getParameter(0);
PlacesUtils.bhistory.removePage(NetUtil.newURI(uriSpec)); URIsToRemove.push(NetUtil.newURI(uriSpec));
} catch (err) { } } catch (err) { }
} }
} }
if (URIsToRemove.length > 0) {
PlacesUtils.bhistory.removePages(URIsToRemove, URIsToRemove.length, true);
}
}, },
/** /**
@ -482,29 +531,51 @@ var WinTaskbarJumpList =
_initObs: function WTBJL__initObs() { _initObs: function WTBJL__initObs() {
Services.obs.addObserver(this, "private-browsing", false); Services.obs.addObserver(this, "private-browsing", false);
Services.obs.addObserver(this, "quit-application-granted", false); // If the browser is closed while in private browsing mode, the "exit"
// notification is fired on quit-application-granted.
// History cleanup can happen at profile-change-teardown.
Services.obs.addObserver(this, "profile-before-change", false);
Services.obs.addObserver(this, "browser:purge-session-history", false); Services.obs.addObserver(this, "browser:purge-session-history", false);
_prefs.addObserver("", this, false); _prefs.addObserver("", this, false);
}, },
_freeObs: function WTBJL__freeObs() { _freeObs: function WTBJL__freeObs() {
Services.obs.removeObserver(this, "private-browsing"); Services.obs.removeObserver(this, "private-browsing");
Services.obs.removeObserver(this, "quit-application-granted"); Services.obs.removeObserver(this, "profile-before-change");
Services.obs.removeObserver(this, "browser:purge-session-history"); Services.obs.removeObserver(this, "browser:purge-session-history");
_prefs.removeObserver("", this); _prefs.removeObserver("", this);
}, },
_initTimer: function WTBJL__initTimer(aTimer) { _updateTimer: function WTBJL__updateTimer() {
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); if (this._enabled && !this._shuttingDown && !this._timer) {
this._timer.initWithCallback(this, this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
_prefs.getIntPref(PREF_TASKBAR_REFRESH)*1000, this._timer.initWithCallback(this,
this._timer.TYPE_REPEATING_SLACK); _prefs.getIntPref(PREF_TASKBAR_REFRESH)*1000,
this._timer.TYPE_REPEATING_SLACK);
}
else if ((!this._enabled || this._shuttingDown) && this._timer) {
this._timer.cancel();
delete this._timer;
}
},
_hasIdleObserver: false,
_updateIdleObserver: function WTBJL__updateIdleObserver() {
if (this._enabled && !this._shuttingDown && !this._hasIdleObserver) {
_idle.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
this._hasIdleObserver = true;
}
else if ((!this._enabled || this._shuttingDown) && this._hasIdleObserver) {
_idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS);
this._hasIdleObserver = false;
}
}, },
_free: function WTBJL__free() { _free: function WTBJL__free() {
this._freeObs(); this._freeObs();
this._updateTimer();
this._updateIdleObserver();
delete this._builder; delete this._builder;
delete this._timer;
}, },
/** /**
@ -512,6 +583,8 @@ var WinTaskbarJumpList =
*/ */
notify: function WTBJL_notify(aTimer) { notify: function WTBJL_notify(aTimer) {
// Add idle observer on the first notification so it doesn't hit startup.
this._updateIdleObserver();
this.update(); this.update();
}, },
@ -521,10 +594,12 @@ var WinTaskbarJumpList =
if (this._enabled == true && !_prefs.getBoolPref(PREF_TASKBAR_ENABLED)) if (this._enabled == true && !_prefs.getBoolPref(PREF_TASKBAR_ENABLED))
this._deleteActiveJumpList(); this._deleteActiveJumpList();
this._refreshPrefs(); this._refreshPrefs();
this._updateTimer();
this._updateIdleObserver();
this.update(); this.update();
break; break;
case "quit-application-granted": case "profile-before-change":
this._shutdown(); this._shutdown();
break; break;
@ -535,6 +610,17 @@ var WinTaskbarJumpList =
case "private-browsing": case "private-browsing":
this.update(); this.update();
break; break;
case "idle":
if (this._timer) {
this._timer.cancel();
delete this._timer;
}
break;
case "back":
this._updateTimer();
break;
} }
}, },
}; };

Просмотреть файл

@ -47,18 +47,18 @@
*/ */
#include "nsISupports.idl" #include "nsISupports.idl"
#include "nsIArray.idl"
#include "nsIURI.idl"
#include "nsIVariant.idl"
interface nsIArray;
interface nsIURI;
interface nsIVariant;
interface nsIFile; interface nsIFile;
interface nsINavHistoryContainerResultNode; interface nsINavHistoryContainerResultNode;
interface nsINavHistoryQueryResultNode; interface nsINavHistoryQueryResultNode;
interface nsINavHistoryQuery; interface nsINavHistoryQuery;
interface nsINavHistoryQueryOptions; interface nsINavHistoryQueryOptions;
interface nsINavHistoryResult; interface nsINavHistoryResult;
interface nsINavHistoryBatchCallback; interface nsINavHistoryBatchCallback;
interface nsITreeColumn;
[scriptable, uuid(081452e5-be5c-4038-a5ea-f1f34cb6fd81)] [scriptable, uuid(081452e5-be5c-4038-a5ea-f1f34cb6fd81)]
interface nsINavHistoryResultNode : nsISupports interface nsINavHistoryResultNode : nsISupports

Просмотреть файл

@ -40,17 +40,39 @@
#include "nsISupports.idl" #include "nsISupports.idl"
interface mozIStorageConnection; interface mozIStorageConnection;
interface nsINavHistoryQuery;
interface nsINavHistoryQueryOptions;
interface mozIStorageStatementCallback;
interface mozIStoragePendingStatement;
/** /**
* This is a private interface used by Places components to get access to the * This is a private interface used by Places components to get access to the
* database. If outside consumers wish to use this, they should only read from * database. If outside consumers wish to use this, they should only read from
* the database so they do not break any internal invariants. * the database so they do not break any internal invariants.
*/ */
[scriptable, uuid(5fd91813-229c-4d30-851b-700afa39a987)] [scriptable, uuid(6eb7ed3d-13ca-450b-b370-15c75e2f3dab)]
interface nsPIPlacesDatabase : nsISupports interface nsPIPlacesDatabase : nsISupports
{ {
/** /**
* The database connection used by Places. * The database connection used by Places.
*/ */
readonly attribute mozIStorageConnection DBConnection; readonly attribute mozIStorageConnection DBConnection;
/**
* Asynchronously executes the statement created from queries.
*
* @see nsINavHistoryService::executeQueries
* @note THIS IS A TEMPORARY API. Don't rely on it, since it will be replaced
* in future versions by a real async querying API.
* @note Results obtained from this method differ from results obtained from
* executeQueries, because there is additional filtering and sorting
* done by the latter. Thus you should use executeQueries, unless you
* are absolutely sure that the returned results are fine for
* your use-case.
*/
mozIStoragePendingStatement asyncExecuteLegacyQueries(
[array, size_is(aQueryCount)] in nsINavHistoryQuery aQueries,
in unsigned long aQueryCount,
in nsINavHistoryQueryOptions aOptions,
in mozIStorageStatementCallback aCallback);
}; };

Просмотреть файл

@ -4340,6 +4340,7 @@ nsNavHistory::GetQueryResults(nsNavHistoryQueryResultNode *aResultNode,
return NS_OK; return NS_OK;
} }
// nsNavHistory::AddObserver // nsNavHistory::AddObserver
NS_IMETHODIMP NS_IMETHODIMP
@ -5689,6 +5690,72 @@ nsNavHistory::FinalizeInternalStatements()
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsNavHistory::AsyncExecuteLegacyQueries(nsINavHistoryQuery** aQueries,
PRUint32 aQueryCount,
nsINavHistoryQueryOptions* aOptions,
mozIStorageStatementCallback* aCallback,
mozIStoragePendingStatement** _stmt)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
NS_ENSURE_ARG(aQueries);
NS_ENSURE_ARG(aOptions);
NS_ENSURE_ARG(aCallback);
NS_ENSURE_ARG_POINTER(_stmt);
nsCOMArray<nsNavHistoryQuery> queries;
for (PRUint32 i = 0; i < aQueryCount; i ++) {
nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface(aQueries[i]);
NS_ENSURE_STATE(query);
queries.AppendObject(query);
}
NS_ENSURE_ARG_MIN(queries.Count(), 1);
nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
NS_ENSURE_ARG(options);
nsCString queryString;
PRBool paramsPresent = PR_FALSE;
nsNavHistory::StringHash addParams;
addParams.Init(HISTORY_DATE_CONT_MAX);
nsresult rv = ConstructQueryString(queries, options, queryString,
paramsPresent, addParams);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<mozIStorageStatement> statement;
rv = mDBConn->CreateStatement(queryString, getter_AddRefs(statement));
#ifdef DEBUG
if (NS_FAILED(rv)) {
nsCAutoString lastErrorString;
(void)mDBConn->GetLastErrorString(lastErrorString);
PRInt32 lastError = 0;
(void)mDBConn->GetLastError(&lastError);
printf("Places failed to create a statement from this query:\n%s\nStorage error (%d): %s\n",
PromiseFlatCString(queryString).get(),
lastError,
PromiseFlatCString(lastErrorString).get());
}
#endif
NS_ENSURE_SUCCESS(rv, rv);
if (paramsPresent) {
// bind parameters
PRInt32 i;
for (i = 0; i < queries.Count(); i++) {
rv = BindQueryClauseParameters(statement, i, queries[i], options);
NS_ENSURE_SUCCESS(rv, rv);
}
}
addParams.EnumerateRead(BindAdditionalParameter, statement.get());
rv = statement->ExecuteAsync(aCallback, _stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// nsPIPlacesHistoryListenersNotifier ****************************************** // nsPIPlacesHistoryListenersNotifier ******************************************
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -0,0 +1,102 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This is a test for asyncExecuteLegacyQueries API.
let tests = [
function test_history_query() {
let uri = NetUtil.newURI("http://test.visit.mozilla.com/");
let title = "Test visit";
visit(uri, title);
let options = PlacesUtils.history.getNewQueryOptions();
options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
let query = PlacesUtils.history.getNewQuery();
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
for (let row; (row = aResultSet.getNextRow());) {
try {
do_check_eq(row.getResultByIndex(1), uri.spec);
do_check_eq(row.getResultByIndex(2), title);
} catch (e) {
do_throw("Error while fetching page data.");
}
}
},
handleError: function (aError) {
do_throw("Async execution error (" + aError.result + "): " + aError.message);
},
handleCompletion: function (aReason) {
run_next_test();
},
});
},
function test_bookmarks_query() {
let uri = NetUtil.newURI("http://test.bookmark.mozilla.com/");
let title = "Test bookmark";
bookmark(uri, title);
let options = PlacesUtils.history.getNewQueryOptions();
options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_LASMODIFIED_DESCENDING;
options.queryType = options.QUERY_TYPE_BOOKMARKS;
let query = PlacesUtils.history.getNewQuery();
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
for (let row; (row = aResultSet.getNextRow());) {
try {
do_check_eq(row.getResultByIndex(1), uri.spec);
do_check_eq(row.getResultByIndex(2), title);
} catch (e) {
do_throw("Error while fetching page data.");
}
}
},
handleError: function (aError) {
do_throw("Async execution error (" + aError.result + "): " + aError.message);
},
handleCompletion: function (aReason) {
run_next_test();
},
});
},
];
function visit(aURI, aTitle)
{
PlacesUtils.history.addVisit(aURI, Date.now() * 1000, null,
PlacesUtils.history.TRANSITION_TYPED, false, 0);
setPageTitle(aURI, aTitle);
}
function bookmark(aURI, aTitle)
{
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
aURI,
PlacesUtils.bookmarks.DEFAULT_INDEX,
aTitle);
}
function run_test()
{
do_test_pending();
run_next_test();
}
function run_next_test() {
if (tests.length == 0) {
do_test_finished();
return;
}
let test = tests.shift();
waitForClearHistory(function() {
remove_all_bookmarks();
do_execute_soon(test);
});
}