Bug 1678618: Remove onDeleteURI and onDeleteVisits from nsINavHistoryObserver. r=mak

Depends on D101115

Differential Revision: https://phabricator.services.mozilla.com/D101118
This commit is contained in:
Daisuke Akatsuka 2021-02-15 08:04:15 +00:00
Родитель f4358ad192
Коммит 105aaaa9fa
20 изменённых файлов: 75 добавлений и 600 удалений

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

@ -94,27 +94,6 @@ const convertNavHistoryContainerResultNode = (container, converter) => {
return results; return results;
}; };
var _observer;
const getHistoryObserver = () => {
if (!_observer) {
_observer = new (class extends EventEmitter {
onDeleteURI(uri, guid, reason) {
this.emit("visitRemoved", { allHistory: false, urls: [uri.spec] });
}
onBeginUpdateBatch() {}
onEndUpdateBatch() {}
onDeleteVisits(uri, partialRemoval, guid, reason) {
if (!partialRemoval) {
this.emit("visitRemoved", { allHistory: false, urls: [uri.spec] });
}
}
})();
PlacesUtils.history.addObserver(_observer);
}
return _observer;
};
this.history = class extends ExtensionAPI { this.history = class extends ExtensionAPI {
getAPI(context) { getAPI(context) {
return { return {
@ -257,10 +236,7 @@ this.history = class extends ExtensionAPI {
context, context,
name: "history.onVisitRemoved", name: "history.onVisitRemoved",
register: fire => { register: fire => {
let listener = (event, data) => { const listener = events => {
fire.sync(data);
};
const historyClearedListener = events => {
const removedURLs = []; const removedURLs = [];
for (const event of events) { for (const event of events) {
@ -283,16 +259,14 @@ this.history = class extends ExtensionAPI {
} }
}; };
getHistoryObserver().on("visitRemoved", listener);
PlacesUtils.observers.addListener( PlacesUtils.observers.addListener(
["history-cleared", "page-removed"], ["history-cleared", "page-removed"],
historyClearedListener listener
); );
return () => { return () => {
getHistoryObserver().off("visitRemoved", listener);
PlacesUtils.observers.removeListener( PlacesUtils.observers.removeListener(
["history-cleared", "page-removed"], ["history-cleared", "page-removed"],
historyClearedListener listener
); );
}; };
}, },

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

@ -46,36 +46,6 @@ class Observer {
} }
} }
/**
* HistoryObserver - observes events from PlacesUtils.history
*/
class HistoryObserver extends Observer {
constructor(dispatch) {
super(dispatch, Ci.nsINavHistoryObserver);
}
/**
* onDeleteURI - Called when an link is deleted from history.
*
* @param {obj} uri A URI object representing the link's url
* {str} uri.spec The URI as a string
*/
onDeleteURI(uri) {
this.dispatch({ type: at.PLACES_LINKS_CHANGED });
this.dispatch({
type: at.PLACES_LINK_DELETED,
data: { url: uri.spec },
});
}
// Empty functions to make xpconnect happy
onBeginUpdateBatch() {}
onEndUpdateBatch() {}
onDeleteVisits() {}
}
/** /**
* BookmarksObserver - observes events from PlacesUtils.bookmarks * BookmarksObserver - observes events from PlacesUtils.bookmarks
*/ */
@ -188,16 +158,12 @@ class PlacesFeed {
constructor() { constructor() {
this.placesChangedTimer = null; this.placesChangedTimer = null;
this.customDispatch = this.customDispatch.bind(this); this.customDispatch = this.customDispatch.bind(this);
this.historyObserver = new HistoryObserver(this.customDispatch);
this.bookmarksObserver = new BookmarksObserver(this.customDispatch); this.bookmarksObserver = new BookmarksObserver(this.customDispatch);
this.placesObserver = new PlacesObserver(this.customDispatch); this.placesObserver = new PlacesObserver(this.customDispatch);
} }
addObservers() { addObservers() {
// NB: Directly get services without importing the *BIG* PlacesUtils module // NB: Directly get services without importing the *BIG* PlacesUtils module
Cc["@mozilla.org/browser/nav-history-service;1"]
.getService(Ci.nsINavHistoryService)
.addObserver(this.historyObserver, true);
Cc["@mozilla.org/browser/nav-bookmarks-service;1"] Cc["@mozilla.org/browser/nav-bookmarks-service;1"]
.getService(Ci.nsINavBookmarksService) .getService(Ci.nsINavBookmarksService)
.addObserver(this.bookmarksObserver, true); .addObserver(this.bookmarksObserver, true);
@ -243,7 +209,6 @@ class PlacesFeed {
this.placesChangedTimer.cancel(); this.placesChangedTimer.cancel();
this.placesChangedTimer = null; this.placesChangedTimer = null;
} }
PlacesUtils.history.removeObserver(this.historyObserver);
PlacesUtils.bookmarks.removeObserver(this.bookmarksObserver); PlacesUtils.bookmarks.removeObserver(this.bookmarksObserver);
PlacesUtils.observers.removeListener( PlacesUtils.observers.removeListener(
["bookmark-added", "bookmark-removed", "history-cleared", "page-removed"], ["bookmark-added", "bookmark-removed", "history-cleared", "page-removed"],
@ -577,7 +542,6 @@ class PlacesFeed {
this.PlacesFeed = PlacesFeed; this.PlacesFeed = PlacesFeed;
// Exported for testing only // Exported for testing only
PlacesFeed.HistoryObserver = HistoryObserver;
PlacesFeed.BookmarksObserver = BookmarksObserver; PlacesFeed.BookmarksObserver = BookmarksObserver;
PlacesFeed.PlacesObserver = PlacesObserver; PlacesFeed.PlacesObserver = PlacesObserver;

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

@ -1,7 +1,7 @@
import { actionCreators as ac, actionTypes as at } from "common/Actions.jsm"; import { actionCreators as ac, actionTypes as at } from "common/Actions.jsm";
import { GlobalOverrider } from "test/unit/utils"; import { GlobalOverrider } from "test/unit/utils";
import { PlacesFeed } from "lib/PlacesFeed.jsm"; import { PlacesFeed } from "lib/PlacesFeed.jsm";
const { HistoryObserver, BookmarksObserver, PlacesObserver } = PlacesFeed; const { BookmarksObserver, PlacesObserver } = PlacesFeed;
const FAKE_BOOKMARK = { const FAKE_BOOKMARK = {
bookmarkGuid: "xi31", bookmarkGuid: "xi31",
@ -82,16 +82,6 @@ describe("PlacesFeed", () => {
}); });
afterEach(() => globals.restore()); afterEach(() => globals.restore());
it("should have a HistoryObserver that dispatches to the store", () => {
assert.instanceOf(feed.historyObserver, HistoryObserver);
const action = { type: "FOO" };
feed.historyObserver.dispatch(action);
assert.calledOnce(feed.store.dispatch);
assert.equal(feed.store.dispatch.firstCall.args[0].type, action.type);
});
it("should have a BookmarksObserver that dispatch to the store", () => { it("should have a BookmarksObserver that dispatch to the store", () => {
assert.instanceOf(feed.bookmarksObserver, BookmarksObserver); assert.instanceOf(feed.bookmarksObserver, BookmarksObserver);
const action = { type: "FOO" }; const action = { type: "FOO" };
@ -115,11 +105,6 @@ describe("PlacesFeed", () => {
it("should add bookmark, history, places, blocked observers on INIT", () => { it("should add bookmark, history, places, blocked observers on INIT", () => {
feed.onAction({ type: at.INIT }); feed.onAction({ type: at.INIT });
assert.calledWith(
global.PlacesUtils.history.addObserver,
feed.historyObserver,
true
);
assert.calledWith( assert.calledWith(
global.PlacesUtils.bookmarks.addObserver, global.PlacesUtils.bookmarks.addObserver,
feed.bookmarksObserver, feed.bookmarksObserver,
@ -144,10 +129,6 @@ describe("PlacesFeed", () => {
let spy = feed.placesChangedTimer.cancel; let spy = feed.placesChangedTimer.cancel;
feed.onAction({ type: at.UNINIT }); feed.onAction({ type: at.UNINIT });
assert.calledWith(
global.PlacesUtils.history.removeObserver,
feed.historyObserver
);
assert.calledWith( assert.calledWith(
global.PlacesUtils.bookmarks.removeObserver, global.PlacesUtils.bookmarks.removeObserver,
feed.bookmarksObserver feed.bookmarksObserver
@ -752,25 +733,6 @@ describe("PlacesFeed", () => {
}); });
}); });
describe("HistoryObserver", () => {
let dispatch;
let observer;
beforeEach(() => {
dispatch = sandbox.spy();
observer = new HistoryObserver(dispatch);
});
it("should have a QueryInterface property", () => {
assert.property(observer, "QueryInterface");
});
describe("Other empty methods (to keep code coverage happy)", () => {
it("should have a various empty functions for xpconnect happiness", () => {
observer.onBeginUpdateBatch();
observer.onEndUpdateBatch();
observer.onDeleteVisits();
});
});
});
describe("Custom dispatch", () => { describe("Custom dispatch", () => {
it("should only dispatch 1 PLACES_LINKS_CHANGED action if many bookmark-added notifications happened at once", async () => { it("should only dispatch 1 PLACES_LINKS_CHANGED action if many bookmark-added notifications happened at once", async () => {
// Yes, onItemAdded has at least 8 arguments. See function definition for docs. // Yes, onItemAdded has at least 8 arguments. See function definition for docs.
@ -821,10 +783,16 @@ describe("PlacesFeed", () => {
) )
); );
}); });
it("should only dispatch 1 PLACES_LINKS_CHANGED action if any onDeleteURI notifications happened at once", async () => { it("should only dispatch 1 PLACES_LINKS_CHANGED action if any page-removed notifications happened at once", async () => {
await feed.historyObserver.onDeleteURI({ spec: "foo.com" }); await feed.placesObserver.handlePlacesEvent([
await feed.historyObserver.onDeleteURI({ spec: "foo1.com" }); { type: "page-removed", url: "foo.com", isRemovedFromStore: true },
await feed.historyObserver.onDeleteURI({ spec: "foo2.com" }); ]);
await feed.placesObserver.handlePlacesEvent([
{ type: "page-removed", url: "foo1.com", isRemovedFromStore: true },
]);
await feed.placesObserver.handlePlacesEvent([
{ type: "page-removed", url: "foo2.com", isRemovedFromStore: true },
]);
assert.calledOnce( assert.calledOnce(
feed.store.dispatch.withArgs( feed.store.dispatch.withArgs(

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

@ -220,60 +220,41 @@ HistoryStore.prototype = {
} }
}); });
if (toAdd.length || toRemove.length) { if (toAdd.length || toRemove.length) {
// We want to notify history observers that a batch operation is underway if (toRemove.length) {
// so they don't do lots of work for each incoming record. // PlacesUtils.history.remove takes an array of visits to remove,
let observers = PlacesUtils.history.getObservers(); // but the error semantics are tricky - a single "bad" entry will cause
const notifyHistoryObservers = notification => { // an exception before anything is removed. So we do remove them one at
for (let observer of observers) { // a time.
await Async.yieldingForEach(toRemove, async record => {
try { try {
observer[notification](); await this.remove(record);
} catch (ex) { } catch (ex) {
// don't log an error - it's not our code that failed and we don't if (Async.isShutdownException(ex)) {
// want an error log written just for this. throw ex;
this._log.info("history observer failed", ex);
}
}
};
notifyHistoryObservers("onBeginUpdateBatch");
try {
if (toRemove.length) {
// PlacesUtils.history.remove takes an array of visits to remove,
// but the error semantics are tricky - a single "bad" entry will cause
// an exception before anything is removed. So we do remove them one at
// a time.
await Async.yieldingForEach(toRemove, async record => {
try {
await this.remove(record);
} catch (ex) {
if (Async.isShutdownException(ex)) {
throw ex;
}
this._log.error("Failed to delete a place info", ex);
this._log.trace("The record that failed", record);
failed.push(record.id);
} }
}); this._log.error("Failed to delete a place info", ex);
} this._log.trace("The record that failed", record);
for (let chunk of this._generateChunks(toAdd)) { failed.push(record.id);
// Per bug 1415560, we ignore any exceptions returned by insertMany
// as they are likely to be spurious. We do supply an onError handler
// and log the exceptions seen there as they are likely to be
// informative, but we still never abort the sync based on them.
try {
await PlacesUtils.history.insertMany(chunk, null, failedVisit => {
this._log.info(
"Failed to insert a history record",
failedVisit.guid
);
this._log.trace("The record that failed", failedVisit);
failed.push(failedVisit.guid);
});
} catch (ex) {
this._log.info("Failed to insert history records", ex);
} }
});
}
for (let chunk of this._generateChunks(toAdd)) {
// Per bug 1415560, we ignore any exceptions returned by insertMany
// as they are likely to be spurious. We do supply an onError handler
// and log the exceptions seen there as they are likely to be
// informative, but we still never abort the sync based on them.
try {
await PlacesUtils.history.insertMany(chunk, null, failedVisit => {
this._log.info(
"Failed to insert a history record",
failedVisit.guid
);
this._log.trace("The record that failed", failedVisit);
failed.push(failedVisit.guid);
});
} catch (ex) {
this._log.info("Failed to insert history records", ex);
} }
} finally {
notifyHistoryObservers("onEndUpdateBatch");
} }
} }
@ -521,7 +502,6 @@ HistoryTracker.prototype = {
onStart() { onStart() {
this._log.info("Adding Places observer."); this._log.info("Adding Places observer.");
PlacesUtils.history.addObserver(this, true);
this._placesObserver = new PlacesWeakCallbackWrapper( this._placesObserver = new PlacesWeakCallbackWrapper(
this.handlePlacesEvents.bind(this) this.handlePlacesEvents.bind(this)
); );
@ -533,7 +513,6 @@ HistoryTracker.prototype = {
onStop() { onStop() {
this._log.info("Removing Places observer."); this._log.info("Removing Places observer.");
PlacesUtils.history.removeObserver(this);
if (this._placesObserver) { if (this._placesObserver) {
PlacesObservers.removeListener( PlacesObservers.removeListener(
["page-visited", "history-cleared", "page-removed"], ["page-visited", "history-cleared", "page-removed"],
@ -542,45 +521,7 @@ HistoryTracker.prototype = {
} }
}, },
QueryInterface: ChromeUtils.generateQI([ QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
"nsINavHistoryObserver",
"nsISupportsWeakReference",
]),
async onDeleteAffectsGUID(uri, guid, reason, source, increment) {
if (this.ignoreAll || reason === PlacesVisitRemoved.REASON_EXPIRED) {
return;
}
this._log.trace(source + ": " + uri.spec + ", reason " + reason);
const added = await this.addChangedID(guid);
if (added) {
this.score += increment;
}
},
onDeleteVisits(uri, partialRemoval, guid, reason) {
this.asyncObserver.enqueueCall(() =>
this.onDeleteAffectsGUID(
uri,
guid,
reason,
"onDeleteVisits",
SCORE_INCREMENT_SMALL
)
);
},
onDeleteURI(uri, guid, reason) {
this.asyncObserver.enqueueCall(() =>
this.onDeleteAffectsGUID(
uri,
guid,
reason,
"onDeleteURI",
SCORE_INCREMENT_XLARGE
)
);
},
handlePlacesEvents(aEvents) { handlePlacesEvents(aEvents) {
this.asyncObserver.enqueueCall(() => this._handlePlacesEvents(aEvents)); this.asyncObserver.enqueueCall(() => this._handlePlacesEvents(aEvents));
@ -634,8 +575,4 @@ HistoryTracker.prototype = {
} }
} }
}, },
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onBeforeDeleteURI() {},
}; };

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

@ -617,7 +617,6 @@ async function promiseVisit(expectedType, expectedURI) {
return new Promise(resolve => { return new Promise(resolve => {
function done(type, uri) { function done(type, uri) {
if (uri == expectedURI.spec && type == expectedType) { if (uri == expectedURI.spec && type == expectedType) {
PlacesUtils.history.removeObserver(observer);
PlacesObservers.removeListener( PlacesObservers.removeListener(
["page-visited", "page-removed"], ["page-visited", "page-removed"],
observer.handlePlacesEvents observer.handlePlacesEvents
@ -636,14 +635,7 @@ async function promiseVisit(expectedType, expectedURI) {
done("removed", events[0].url); done("removed", events[0].url);
} }
}, },
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI(uri) {
done("removed", uri.spec);
},
onDeleteVisits() {},
}; };
PlacesUtils.history.addObserver(observer, false);
PlacesObservers.addListener( PlacesObservers.addListener(
["page-visited", "page-removed"], ["page-visited", "page-removed"],
observer.handlePlacesEvents observer.handlePlacesEvents

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

@ -191,8 +191,6 @@ var DownloadCache = {
return this._initializePromise; return this._initializePromise;
} }
this._initializePromise = (async () => { this._initializePromise = (async () => {
PlacesUtils.history.addObserver(this, true);
const placesObserver = new PlacesWeakCallbackWrapper( const placesObserver = new PlacesWeakCallbackWrapper(
this.handlePlacesEvents.bind(this) this.handlePlacesEvents.bind(this)
); );
@ -326,10 +324,7 @@ var DownloadCache = {
} }
}, },
QueryInterface: ChromeUtils.generateQI([ QueryInterface: ChromeUtils.generateQI(["nsISupportsWeakReference"]),
"nsINavHistoryObserver",
"nsISupportsWeakReference",
]),
handlePlacesEvents(events) { handlePlacesEvents(events) {
for (const event of events) { for (const event of events) {
@ -347,14 +342,6 @@ var DownloadCache = {
} }
} }
}, },
// nsINavHistoryObserver
onDeleteURI(uri) {
this._data.delete(uri.spec);
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteVisits() {},
}; };
/** /**

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

@ -58,11 +58,6 @@ ChromeUtils.defineModuleGetter(
"NetUtil", "NetUtil",
"resource://gre/modules/NetUtil.jsm" "resource://gre/modules/NetUtil.jsm"
); );
ChromeUtils.defineModuleGetter(
this,
"PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm"
);
ChromeUtils.defineModuleGetter( ChromeUtils.defineModuleGetter(
this, this,
"Services", "Services",
@ -1228,7 +1223,6 @@ var DownloadObserver = {
*/ */
var DownloadHistoryObserver = function(aList) { var DownloadHistoryObserver = function(aList) {
this._list = aList; this._list = aList;
PlacesUtils.history.addObserver(this);
const placesObserver = new PlacesWeakCallbackWrapper( const placesObserver = new PlacesWeakCallbackWrapper(
this.handlePlacesEvents.bind(this) this.handlePlacesEvents.bind(this)
@ -1245,8 +1239,6 @@ DownloadHistoryObserver.prototype = {
*/ */
_list: null, _list: null,
QueryInterface: ChromeUtils.generateQI(["nsINavHistoryObserver"]),
handlePlacesEvents(events) { handlePlacesEvents(events) {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
@ -1265,17 +1257,6 @@ DownloadHistoryObserver.prototype = {
} }
} }
}, },
// nsINavHistoryObserver
onDeleteURI: function DL_onDeleteURI(aURI, aGUID) {
this._list.removeFinished(download =>
aURI.equals(NetUtil.newURI(download.source.url))
);
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteVisits() {},
}; };
/** /**

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

@ -578,62 +578,6 @@ interface nsINavHistoryObserver : nsISupports
* ahead and update UI, etc. * ahead and update UI, etc.
*/ */
void onEndUpdateBatch(); void onEndUpdateBatch();
/**
* Removed by the user.
*/
const unsigned short REASON_DELETED = 0;
/**
* Removed by automatic expiration.
*/
const unsigned short REASON_EXPIRED = 1;
/**
* This page and all of its visits are being deleted. Note: the page may not
* necessarily have actually existed for this function to be called.
*
* Delete notifications are only 99.99% accurate. Batch delete operations
* must be done in two steps, so first come notifications, then a bulk
* delete. If there is some error in the middle (for example, out of memory)
* then you'll get a notification and it won't get deleted. There's no easy
* way around this.
*
* @param aURI
* The URI that was deleted.
* @param aGUID
* The unique ID associated with the page.
* @param aReason
* Indicates the reason for the removal. see REASON_* constants.
*/
void onDeleteURI(in nsIURI aURI,
in ACString aGUID,
in unsigned short aReason);
/**
* Called when some visits of an history entry are expired.
*
* @param aURI
* The page whose visits have been expired.
* @param aPartialRemoval
* Set to true if only some of the visits for the page have been removed.
* @param aGUID
* The unique ID associated with the page.
*
* @note: when all visits for a page are expired and also the full page entry
* is expired, you will only get an onDeleteURI notification. If a
* page entry is removed, then you can be sure that we don't have
* anymore visits for it.
* @param aReason
* Indicates the reason for the removal. see REASON_* constants.
* @param aTransitionType
* If it's a valid TRANSITION_* value, all visits of the specified type
* have been removed.
*/
void onDeleteVisits(in nsIURI aURI,
in boolean aPartialRemoval,
in ACString aGUID,
in unsigned short aReason,
in unsigned long aTransitionType);
}; };

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

@ -2262,9 +2262,8 @@ nsresult nsNavHistoryQueryResultNode::OnTitleChanged(
* Here, we can always live update by just deleting all occurrences of * Here, we can always live update by just deleting all occurrences of
* the given URI. * the given URI.
*/ */
NS_IMETHODIMP nsresult nsNavHistoryQueryResultNode::OnPageRemovedFromStore(
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI* aURI, const nsACString& aGUID, nsIURI* aURI, const nsACString& aGUID, uint16_t aReason) {
uint16_t aReason) {
nsNavHistoryResult* result = GetResult(); nsNavHistoryResult* result = GetResult();
NS_ENSURE_STATE(result); NS_ENSURE_STATE(result);
if (result->mBatchInProgress && if (result->mBatchInProgress &&
@ -2328,11 +2327,9 @@ static nsresult setFaviconCallback(nsNavHistoryResultNode* aNode,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult nsNavHistoryQueryResultNode::OnPageRemovedVisits(
nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, bool aPartialRemoval, nsIURI* aURI, bool aPartialRemoval, const nsACString& aGUID,
const nsACString& aGUID, uint16_t aReason, uint32_t aTransitionType) {
uint16_t aReason,
uint32_t aTransitionType) {
MOZ_ASSERT( MOZ_ASSERT(
mOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY, mOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY,
"Bookmarks queries should not get a OnDeleteVisits notification"); "Bookmarks queries should not get a OnDeleteVisits notification");
@ -2340,16 +2337,16 @@ nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, bool aPartialRemoval,
if (!aPartialRemoval) { if (!aPartialRemoval) {
// All visits for this uri have been removed, but the uri won't be removed // All visits for this uri have been removed, but the uri won't be removed
// from the databse, most likely because it's a bookmark. For a history // from the databse, most likely because it's a bookmark. For a history
// query this is equivalent to a onDeleteURI notification. // query this is equivalent to a OnPageRemovedFromStore notification.
nsresult rv = OnDeleteURI(aURI, aGUID, aReason); nsresult rv = OnPageRemovedFromStore(aURI, aGUID, aReason);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
if (aTransitionType > 0) { if (aTransitionType > 0) {
// All visits for aTransitionType have been removed, if the query is // All visits for aTransitionType have been removed, if the query is
// filtering on such transition type, this is equivalent to an onDeleteURI // filtering on such transition type, this is equivalent to an
// notification. // OnPageRemovedFromStore notification.
if (mTransitions.Length() > 0 && mTransitions.Contains(aTransitionType)) { if (mTransitions.Length() > 0 && mTransitions.Contains(aTransitionType)) {
nsresult rv = OnDeleteURI(aURI, aGUID, aReason); nsresult rv = OnPageRemovedFromStore(aURI, aGUID, aReason);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
} }
@ -3511,8 +3508,8 @@ void nsNavHistoryResult::StopObserving() {
nsNavHistory* history = nsNavHistory::GetHistoryService(); nsNavHistory* history = nsNavHistory::GetHistoryService();
if (history) { if (history) {
history->RemoveObserver(this); history->RemoveObserver(this);
mIsHistoryObserver = false;
} }
mIsHistoryObserver = false;
events.AppendElement(PlacesEventType::History_cleared); events.AppendElement(PlacesEventType::History_cleared);
events.AppendElement(PlacesEventType::Page_removed); events.AppendElement(PlacesEventType::Page_removed);
} }
@ -4219,14 +4216,15 @@ void nsNavHistoryResult::HandlePlacesEvent(const PlacesEventSequence& aEvents) {
} }
if (removeEvent->mIsRemovedFromStore) { if (removeEvent->mIsRemovedFromStore) {
ENUMERATE_HISTORY_OBSERVERS( ENUMERATE_HISTORY_OBSERVERS(OnPageRemovedFromStore(
OnDeleteURI(uri, removeEvent->mPageGuid, removeEvent->mReason)); uri, removeEvent->mPageGuid, removeEvent->mReason));
} else { } else {
ENUMERATE_HISTORY_OBSERVERS( ENUMERATE_HISTORY_OBSERVERS(
OnDeleteVisits(uri, removeEvent->mIsPartialVisistsRemoval, OnPageRemovedVisits(uri, removeEvent->mIsPartialVisistsRemoval,
removeEvent->mPageGuid, removeEvent->mReason, removeEvent->mPageGuid, removeEvent->mReason,
removeEvent->mTransitionType)); removeEvent->mTransitionType));
} }
break; break;
} }
default: { default: {
@ -4237,29 +4235,6 @@ void nsNavHistoryResult::HandlePlacesEvent(const PlacesEventSequence& aEvents) {
} }
} }
NS_IMETHODIMP
nsNavHistoryResult::OnDeleteURI(nsIURI* aURI, const nsACString& aGUID,
uint16_t aReason) {
NS_ENSURE_ARG(aURI);
ENUMERATE_HISTORY_OBSERVERS(OnDeleteURI(aURI, aGUID, aReason));
return NS_OK;
}
/**
* Don't do anything when visits expire.
*/
NS_IMETHODIMP
nsNavHistoryResult::OnDeleteVisits(nsIURI* aURI, bool aPartialRemoval,
const nsACString& aGUID, uint16_t aReason,
uint32_t aTransitionType) {
NS_ENSURE_ARG(aURI);
ENUMERATE_HISTORY_OBSERVERS(
OnDeleteVisits(aURI, aPartialRemoval, aGUID, aReason, aTransitionType));
return NS_OK;
}
void nsNavHistoryResult::OnMobilePrefChanged() { void nsNavHistoryResult::OnMobilePrefChanged() {
ENUMERATE_MOBILE_PREF_OBSERVERS( ENUMERATE_MOBILE_PREF_OBSERVERS(
OnMobilePrefChanged(Preferences::GetBool(MOBILE_BOOKMARKS_PREF, false))); OnMobilePrefChanged(Preferences::GetBool(MOBILE_BOOKMARKS_PREF, false)));

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

@ -60,24 +60,6 @@ class nsTrimInt64HashKey : public PLDHashEntryHdr {
const int64_t mValue; const int64_t mValue;
}; };
// Declare methods for implementing nsINavBookmarkObserver
// and nsINavHistoryObserver (some methods, such as BeginUpdateBatch overlap)
#define NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE(...) \
NS_DECL_NSINAVBOOKMARKOBSERVER \
NS_IMETHOD OnDeleteURI(nsIURI* aURI, const nsACString& aGUID, \
uint16_t aReason) __VA_ARGS__; \
NS_IMETHOD OnDeleteVisits(nsIURI* aURI, bool aPartialRemoval, \
const nsACString& aGUID, uint16_t aReason, \
uint32_t aTransitionType) __VA_ARGS__;
// The internal version is used by query nodes.
#define NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL \
NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE()
// The external version is used by results.
#define NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(...) \
NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE(__VA_ARGS__)
// nsNavHistoryResult // nsNavHistoryResult
// //
// nsNavHistory creates this object and fills in mChildren (by getting // nsNavHistory creates this object and fills in mChildren (by getting
@ -104,7 +86,7 @@ class nsNavHistoryResult final
NS_DECL_NSINAVHISTORYRESULT NS_DECL_NSINAVHISTORYRESULT
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult,
nsINavHistoryResult) nsINavHistoryResult)
NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(override) NS_DECL_NSINAVBOOKMARKOBSERVER;
void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode); void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode);
void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode,
@ -687,7 +669,7 @@ class nsNavHistoryQueryResultNode final
virtual nsresult OpenContainer() override; virtual nsresult OpenContainer() override;
NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL NS_DECL_NSINAVBOOKMARKOBSERVER;
nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex, nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex,
uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded, uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded,
@ -706,6 +688,12 @@ class nsNavHistoryQueryResultNode final
nsresult OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, nsresult OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle,
const nsACString& aGUID); const nsACString& aGUID);
nsresult OnClearHistory(); nsresult OnClearHistory();
nsresult OnPageRemovedFromStore(nsIURI* aURI, const nsACString& aGUID,
uint16_t aReason);
nsresult OnPageRemovedVisits(nsIURI* aURI, bool aPartialRemoval,
const nsACString& aGUID, uint16_t aReason,
uint32_t aTransitionType);
virtual void OnRemoving() override; virtual void OnRemoving() override;
public: public:

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

@ -80,20 +80,6 @@ function promiseFieldForUrl(aURI, aFieldName) {
}); });
} }
/**
* Generic nsINavHistoryObserver that doesn't implement anything, but provides
* dummy methods to prevent errors about an object not having a certain method.
*/
function NavHistoryObserver() {}
NavHistoryObserver.prototype = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI() {},
onDeleteVisits() {},
QueryInterface: ChromeUtils.generateQI(["nsINavHistoryObserver"]),
};
function whenNewWindowLoaded(aOptions, aCallback) { function whenNewWindowLoaded(aOptions, aCallback) {
BrowserTestUtils.waitForNewWindow().then(aCallback); BrowserTestUtils.waitForNewWindow().then(aCallback);
OpenBrowserWindow(aOptions); OpenBrowserWindow(aOptions);

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

@ -84,17 +84,6 @@ add_task(async function test_pref_maxpages() {
await PlacesTestUtils.addVisits({ uri: uri(page), visitDate: now-- }); await PlacesTestUtils.addVisits({ uri: uri(page), visitDate: now-- });
} }
// Observe history.
let historyObserver = new NavHistoryObserver();
historyObserver.onDeleteURI = aURI => {
print("onDeleteURI " + aURI.spec);
currentTest.receivedNotifications++;
};
historyObserver.onDeleteVisits = (aURI, aPartialRemoval) => {
print("onDeleteVisits " + aURI.spec + " " + aPartialRemoval);
};
PlacesUtils.history.addObserver(historyObserver);
const listener = events => { const listener = events => {
for (const event of events) { for (const event of events) {
print("page-removed " + event.url); print("page-removed " + event.url);
@ -111,7 +100,6 @@ add_task(async function test_pref_maxpages() {
// Expire now. // Expire now.
await promiseForceExpirationStep(-1); await promiseForceExpirationStep(-1);
PlacesUtils.history.removeObserver(historyObserver, false);
PlacesObservers.removeListener(["page-removed"], listener); PlacesObservers.removeListener(["page-removed"], listener);
Assert.equal( Assert.equal(

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

@ -728,20 +728,6 @@ NavBookmarkObserver.prototype = {
QueryInterface: ChromeUtils.generateQI(["nsINavBookmarkObserver"]), QueryInterface: ChromeUtils.generateQI(["nsINavBookmarkObserver"]),
}; };
/**
* Generic nsINavHistoryObserver that doesn't implement anything, but provides
* dummy methods to prevent errors about an object not having a certain method.
*/
function NavHistoryObserver() {}
NavHistoryObserver.prototype = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI() {},
onDeleteVisits() {},
QueryInterface: ChromeUtils.generateQI(["nsINavHistoryObserver"]),
};
/** /**
* Generic nsINavHistoryResultObserver that doesn't implement anything, but * Generic nsINavHistoryResultObserver that doesn't implement anything, but
* provides dummy methods to prevent errors about an object not having a certain * provides dummy methods to prevent errors about an object not having a certain

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

@ -39,33 +39,8 @@ add_task(async function test_remove_single() {
} }
let shouldRemove = !options.addBookmark; let shouldRemove = !options.addBookmark;
let observer;
let placesEventListener; let placesEventListener;
let promiseObserved = new Promise((resolve, reject) => { let promiseObserved = new Promise((resolve, reject) => {
observer = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI(aURI) {
try {
Assert.ok(shouldRemove, "Observing onDeleteURI");
Assert.equal(
aURI.spec,
uri.spec,
"Observing effect on the right uri"
);
} finally {
resolve();
}
},
onDeleteVisits(aURI) {
Assert.equal(
aURI.spec,
uri.spec,
"Observing onDeleteVisits on the right uri"
);
},
};
placesEventListener = events => { placesEventListener = events => {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
@ -105,7 +80,6 @@ add_task(async function test_remove_single() {
} }
}; };
}); });
PlacesUtils.history.addObserver(observer);
PlacesObservers.addListener( PlacesObservers.addListener(
[ [
"page-title-changed", "page-title-changed",
@ -138,7 +112,6 @@ add_task(async function test_remove_single() {
} }
await promiseObserved; await promiseObserved;
PlacesUtils.history.removeObserver(observer);
PlacesObservers.removeListener( PlacesObservers.removeListener(
[ [
"page-title-changed", "page-title-changed",

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

@ -58,12 +58,9 @@ add_task(async function test_removeByFilter() {
await checkBeforeRemove(); await checkBeforeRemove();
// Take care of any observers (due to bookmarks) // Take care of any observers (due to bookmarks)
let { observer, placesEventListener, promiseObserved } = getObserverPromise( let { placesEventListener, promiseObserved } = getObserverPromise(
bookmarkedUri bookmarkedUri
); );
if (observer) {
PlacesUtils.history.addObserver(observer, false);
}
if (placesEventListener) { if (placesEventListener) {
PlacesObservers.addListener( PlacesObservers.addListener(
["page-title-changed", "history-cleared", "page-removed"], ["page-title-changed", "history-cleared", "page-removed"],
@ -91,12 +88,8 @@ add_task(async function test_removeByFilter() {
} }
await checkAfterRemove(); await checkAfterRemove();
await promiseObserved; await promiseObserved;
if (observer) {
PlacesUtils.history.removeObserver(observer);
// Remove the added bookmarks as they interfere with following tests
await PlacesUtils.bookmarks.eraseEverything();
}
if (placesEventListener) { if (placesEventListener) {
await PlacesUtils.bookmarks.eraseEverything();
PlacesObservers.removeListener( PlacesObservers.removeListener(
["page-title-changed", "history-cleared", "page-removed"], ["page-title-changed", "history-cleared", "page-removed"],
placesEventListener placesEventListener
@ -456,43 +449,10 @@ add_task(async function test_chunking() {
function getObserverPromise(bookmarkedUri) { function getObserverPromise(bookmarkedUri) {
if (!bookmarkedUri) { if (!bookmarkedUri) {
return { observer: null, promiseObserved: Promise.resolve() }; return { promiseObserved: Promise.resolve() };
} }
let observer;
let placesEventListener; let placesEventListener;
let promiseObserved = new Promise((resolve, reject) => { let promiseObserved = new Promise((resolve, reject) => {
observer = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI(aURI) {
try {
Assert.notEqual(
aURI.spec,
bookmarkedUri,
"Bookmarked URI should not be deleted"
);
} finally {
resolve();
}
},
onDeleteVisits(aURI, aPartialRemoval) {
try {
Assert.equal(
aPartialRemoval,
false,
"Observing onDeleteVisits deletes all visits"
);
Assert.equal(
aURI.spec,
bookmarkedUri,
"Bookmarked URI should have all visits removed but not the page itself"
);
} finally {
resolve();
}
},
};
placesEventListener = events => { placesEventListener = events => {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
@ -530,5 +490,5 @@ function getObserverPromise(bookmarkedUri) {
} }
}; };
}); });
return { observer, placesEventListener, promiseObserved }; return { placesEventListener, promiseObserved };
} }

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

@ -38,10 +38,6 @@ add_task(async function test_remove_many() {
hasBookmark, hasBookmark,
// `true` once `onResult` has been called for this page // `true` once `onResult` has been called for this page
onResultCalled: false, onResultCalled: false,
// `true` once `onDeleteVisits` has been called for this page
onDeleteVisitsCalled: false,
// `true` once `onDeleteURI` has been called for this page
onDeleteURICalled: false,
// `true` once page-removed for store has been fired for this page // `true` once page-removed for store has been fired for this page
pageRemovedFromStore: false, pageRemovedFromStore: false,
// `true` once page-removed for all visits has been fired for this page // `true` once page-removed for all visits has been fired for this page
@ -81,37 +77,6 @@ add_task(async function test_remove_many() {
} }
let onPageRankingChanged = false; let onPageRankingChanged = false;
let observer = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onVisits(aVisits) {
Assert.ok(false, "Unexpected call to onVisits " + aVisits.length);
},
onDeleteURI(aURI) {
let origin = pages.find(x => x.uri.spec == aURI.spec);
Assert.ok(origin);
Assert.ok(
!origin.hasBookmark,
"Observing onDeleteURI on a page without a bookmark"
);
Assert.ok(
!origin.onDeleteURICalled,
"Observing onDeleteURI for the first time"
);
origin.onDeleteURICalled = true;
},
onDeleteVisits(aURI) {
let origin = pages.find(x => x.uri.spec == aURI.spec);
Assert.ok(origin);
Assert.ok(
!origin.onDeleteVisitsCalled,
"Observing onDeleteVisits for the first time"
);
origin.onDeleteVisitsCalled = true;
},
};
PlacesUtils.history.addObserver(observer);
const placesEventListener = events => { const placesEventListener = events => {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
@ -181,7 +146,6 @@ add_task(async function test_remove_many() {
Assert.ok(removed, "Something was removed"); Assert.ok(removed, "Something was removed");
PlacesUtils.history.removeObserver(observer);
PlacesObservers.removeListener( PlacesObservers.removeListener(
[ [
"page-title-changed", "page-title-changed",

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

@ -66,7 +66,6 @@ add_task(async function test_removeVisitsByFilter() {
// `true` if there is a bookmark for this URI, i.e. of the page // `true` if there is a bookmark for this URI, i.e. of the page
// should not be entirely removed. // should not be entirely removed.
hasBookmark, hasBookmark,
onDeleteURI: null,
}, },
}; };
visits.push(visit); visits.push(visit);
@ -142,22 +141,6 @@ add_task(async function test_removeVisitsByFilter() {
} }
} }
let observer = {
deferred: PromiseUtils.defer(),
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI(aURI) {
info("onDeleteURI " + aURI.spec);
let deferred = uriDeletePromises.get(aURI.spec);
Assert.ok(!!deferred, "Observing onDeleteURI");
deferred.resolve();
},
onDeleteVisits(aURI) {
// Not sure we can test anything.
},
};
PlacesUtils.history.addObserver(observer);
const placesEventListener = events => { const placesEventListener = events => {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
@ -262,7 +245,6 @@ add_task(async function test_removeVisitsByFilter() {
await Promise.all(Array.from(uriDeletePromises.values())); await Promise.all(Array.from(uriDeletePromises.values()));
info("Checking frecency change promises."); info("Checking frecency change promises.");
await Promise.all(rankingChangePromises); await Promise.all(rankingChangePromises);
PlacesUtils.history.removeObserver(observer);
PlacesObservers.removeListener( PlacesObservers.removeListener(
["page-title-changed", "history-cleared", "pages-rank-changed"], ["page-title-changed", "history-cleared", "pages-rank-changed"],
placesEventListener placesEventListener

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

@ -1,36 +1,6 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */ http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Generic nsINavHistoryObserver that doesn't implement anything, but provides
* dummy methods to prevent errors about an object not having a certain method.
*/
function NavHistoryObserver() {}
NavHistoryObserver.prototype = {
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteURI() {},
onDeleteVisits() {},
QueryInterface: ChromeUtils.generateQI(["nsINavHistoryObserver"]),
};
/**
* Registers a one-time history observer for and calls the callback
* when the specified nsINavHistoryObserver method is called.
* Returns a promise that is resolved when the callback returns.
*/
function onNotify(callback) {
return new Promise(resolve => {
let obs = new NavHistoryObserver();
obs[callback.name] = function() {
PlacesUtils.history.removeObserver(this);
callback.apply(this, arguments);
resolve();
};
PlacesUtils.history.addObserver(obs);
});
}
/** /**
* Registers a one-time places observer for 'page-visited', * Registers a one-time places observer for 'page-visited',
* which resolves a promise on being called. * which resolves a promise on being called.

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

@ -34,7 +34,6 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["FileReader"]);
XPCOMUtils.defineLazyModuleGetters(this, { XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm", Services: "resource://gre/modules/Services.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm", AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
PageThumbUtils: "resource://gre/modules/PageThumbUtils.jsm", PageThumbUtils: "resource://gre/modules/PageThumbUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
@ -117,7 +116,6 @@ var PageThumbs = {
init: function PageThumbs_init() { init: function PageThumbs_init() {
if (!this._initialized) { if (!this._initialized) {
this._initialized = true; this._initialized = true;
PlacesUtils.history.addObserver(PageThumbsHistoryObserver, true);
this._placesObserver = new PlacesWeakCallbackWrapper( this._placesObserver = new PlacesWeakCallbackWrapper(
this.handlePlacesEvents.bind(this) this.handlePlacesEvents.bind(this)
@ -886,18 +884,3 @@ var PageThumbsWorker = new BasePromiseWorker(
// As the PageThumbsWorker performs I/O, we can receive instances of // As the PageThumbsWorker performs I/O, we can receive instances of
// OS.File.Error, so we need to install a decoder. // OS.File.Error, so we need to install a decoder.
PageThumbsWorker.ExceptionHandlers["OS.File.Error"] = OS.File.Error.fromMsg; PageThumbsWorker.ExceptionHandlers["OS.File.Error"] = OS.File.Error.fromMsg;
var PageThumbsHistoryObserver = {
onDeleteURI(aURI, aGUID) {
PageThumbsStorage.remove(aURI.spec);
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onDeleteVisits() {},
QueryInterface: ChromeUtils.generateQI([
"nsINavHistoryObserver",
"nsISupportsWeakReference",
]),
};

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

@ -586,12 +586,6 @@ var BlockedLinks = {
* the history to retrieve the most frequently visited sites. * the history to retrieve the most frequently visited sites.
*/ */
var PlacesProvider = { var PlacesProvider = {
/**
* A count of how many batch updates are under way (batches may be nested, so
* we keep a counter instead of a simple bool).
**/
_batchProcessingDepth: 0,
/** /**
* Set this to change the maximum number of links the provider will provide. * Set this to change the maximum number of links the provider will provide.
*/ */
@ -601,7 +595,6 @@ var PlacesProvider = {
* Must be called before the provider is used. * Must be called before the provider is used.
*/ */
init: function PlacesProvider_init() { init: function PlacesProvider_init() {
PlacesUtils.history.addObserver(this, true);
this._placesObserver = new PlacesWeakCallbackWrapper( this._placesObserver = new PlacesWeakCallbackWrapper(
this.handlePlacesEvents.bind(this) this.handlePlacesEvents.bind(this)
); );
@ -709,22 +702,7 @@ var PlacesProvider = {
_observers: [], _observers: [],
/**
* Called by the history service.
*/
onBeginUpdateBatch() {
this._batchProcessingDepth += 1;
},
onEndUpdateBatch() {
this._batchProcessingDepth -= 1;
},
handlePlacesEvents(aEvents) { handlePlacesEvents(aEvents) {
if (this._batchProcessingDepth) {
return;
}
for (let event of aEvents) { for (let event of aEvents) {
switch (event.type) { switch (event.type) {
case "page-visited": { case "page-visited": {
@ -789,11 +767,6 @@ var PlacesProvider = {
} }
} }
}, },
QueryInterface: ChromeUtils.generateQI([
"nsINavHistoryObserver",
"nsISupportsWeakReference",
]),
}; };
/** /**