Bug 1340498 - Update onVisits uses to 'page-visited' r=mak

Consuming the new 'page-visited' notification was fairly trivial,
since it was already brought over to onVisits. There's not much to
say about this other than that I'm a little bit uncertain about
all the hoops we have to jump through to get a JSContext and
GlobalObject from History.cpp (which is discussed in the earlier
commit in the series).

MozReview-Commit-ID: LHaBWSylyLI

--HG--
extra : rebase_source : 1190d4f127453cdcb692deb5982e92a93e236b9e
This commit is contained in:
Doug Thayer 2018-02-14 09:11:49 -08:00
parent 120468d5fd
commit 4dd5940382
18 changed files with 162 additions and 116 deletions

View File

@ -94,17 +94,17 @@ const getHistoryObserver = () => {
onDeleteURI(uri, guid, reason) {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
}
onVisits(visits) {
for (let visit of visits) {
let data = {
id: visit.guid,
url: visit.uri.spec,
title: visit.lastKnownTitle || "",
lastVisitTime: visit.time / 1000, // time from Places is microseconds,
visitCount: visit.visitCount,
typedCount: visit.typed,
handlePlacesEvents(events) {
for (let event of events) {
let visit = {
id: event.pageGuid,
url: event.url,
title: event.lastKnownTitle || "",
lastVisitTime: event.visitTime,
visitCount: event.visitCount,
typedCount: event.typedCount,
};
this.emit("visited", data);
this.emit("visited", visit);
}
}
onBeginUpdateBatch() {}
@ -122,6 +122,9 @@ const getHistoryObserver = () => {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
}
}();
PlacesUtils.observers.addListener(
["page-visited"],
_observer.handlePlacesEvents.bind(_observer));
PlacesUtils.history.addObserver(_observer);
}
return _observer;

View File

@ -60,7 +60,6 @@ class HistoryObserver extends Observer {
onEndUpdateBatch() {}
onVisits() {}
onTitleChanged() {}

View File

@ -816,7 +816,6 @@ var AeroPeek = {
/* nsINavHistoryObserver implementation */
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onVisits() {},
onTitleChanged() {},
onFrecencyChanged() {},
onManyFrecenciesChanged() {},

View File

@ -483,11 +483,17 @@ HistoryTracker.prototype = {
onStart() {
this._log.info("Adding Places observer.");
PlacesUtils.history.addObserver(this, true);
this._placesObserver =
new PlacesWeakCallbackWrapper(this.handlePlacesEvents.bind(this));
PlacesObservers.addListener(["page-visited"], this._placesObserver);
},
onStop() {
this._log.info("Removing Places observer.");
PlacesUtils.history.removeObserver(this);
if (this._placesObserver) {
PlacesObservers.removeListener(["page-visited"], this._placesObserver);
}
},
QueryInterface: ChromeUtils.generateQI([
@ -518,19 +524,20 @@ HistoryTracker.prototype = {
);
},
onVisits(aVisits) {
this.asyncObserver.enqueueCall(() => this._onVisits(aVisits));
handlePlacesEvents(aEvents) {
this.asyncObserver.enqueueCall(() => this._handlePlacesEvents(aEvents));
},
async _onVisits(aVisits) {
async _handlePlacesEvents(aEvents) {
if (this.ignoreAll) {
this._log.trace("ignoreAll: ignoring visits [" +
aVisits.map(v => v.guid).join(",") + "]");
aEvents.map(v => v.guid).join(",") + "]");
return;
}
for (let {uri, guid} of aVisits) {
this._log.trace("onVisits: " + uri.spec);
if (this.engine.shouldSyncURL(uri.spec) && (await this.addChangedID(guid))) {
for (let event of aEvents) {
this._log.trace("'page-visited': " + event.url);
if (this.engine.shouldSyncURL(event.url) &&
await this.addChangedID(event.pageGuid)) {
this.score += SCORE_INCREMENT_SMALL;
}
}

View File

@ -1022,7 +1022,6 @@ this.DownloadHistoryObserver.prototype = {
onTitleChanged() {},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onVisits() {},
onPageChanged() {},
onDeleteVisits() {},
};

View File

@ -38,6 +38,10 @@
#include "nsTHashtable.h"
#include "jsapi.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PlacesObservers.h"
#include "mozilla/dom/PlacesVisit.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/ScriptSettings.h"
// Initial size for the cache holding visited status observers.
#define VISIT_OBSERVERS_INITIAL_CACHE_LENGTH 64
@ -666,21 +670,28 @@ public:
aNavHistory->NotifyTitleChange(aURI, aPlace.title, aPlace.guid);
}
aNavHistory->UpdateDaysOfHistory(aPlace.visitTime);
return NS_OK;
}
void AddPlaceForNotify(const VisitData& aPlace,
nsIURI* aURI,
nsCOMArray<nsIVisitData>& aPlaces) {
Sequence<OwningNonNull<PlacesEvent>>& aEvents) {
if (aPlace.transitionType != nsINavHistoryService::TRANSITION_EMBED) {
nsCOMPtr<nsIVisitData> notifyPlace = new nsVisitData(
aURI, aPlace.visitId, aPlace.visitTime,
aPlace.referrerVisitId, aPlace.transitionType,
aPlace.guid, aPlace.hidden,
aPlace.visitCount + 1, // Add current visit.
static_cast<uint32_t>(aPlace.typed),
aPlace.title);
aPlaces.AppendElement(notifyPlace.forget());
RefPtr<PlacesVisit> vd = new PlacesVisit();
vd->mVisitId = aPlace.visitId;
vd->mUrl.Assign(NS_ConvertUTF8toUTF16(aPlace.spec));
vd->mVisitTime = aPlace.visitTime / 1000;
vd->mReferringVisitId = aPlace.referrerVisitId;
vd->mTransitionType = aPlace.transitionType;
vd->mPageGuid.Assign(aPlace.guid);
vd->mHidden = aPlace.hidden;
vd->mVisitCount = aPlace.visitCount + 1; // Add current visit
vd->mTypedCount = static_cast<uint32_t>(aPlace.typed);
vd->mLastKnownTitle.Assign(aPlace.title);
bool success = !!aEvents.AppendElement(vd.forget(), fallible);
MOZ_RELEASE_ASSERT(success);
}
}
@ -703,7 +714,7 @@ public:
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
nsCOMArray<nsIVisitData> places;
Sequence<OwningNonNull<PlacesEvent>> events;
nsCOMArray<nsIURI> uris;
if (mPlaces.Length() > 0) {
for (uint32_t i = 0; i < mPlaces.Length(); ++i) {
@ -712,7 +723,7 @@ public:
if (!uri) {
return NS_ERROR_UNEXPECTED;
}
AddPlaceForNotify(mPlaces[i], uri, places);
AddPlaceForNotify(mPlaces[i], uri, events);
uris.AppendElement(uri.forget());
}
} else {
@ -721,11 +732,12 @@ public:
if (!uri) {
return NS_ERROR_UNEXPECTED;
}
AddPlaceForNotify(mPlace, uri, places);
AddPlaceForNotify(mPlace, uri, events);
uris.AppendElement(uri.forget());
}
if (places.Length() > 0) {
navHistory->NotifyOnVisits(places.Elements(), places.Length());
if (events.Length() > 0) {
PlacesObservers::NotifyListeners(events);
}
PRTime now = PR_Now();

View File

@ -338,6 +338,7 @@ var PlacesUtils = {
TOPIC_BOOKMARKS_RESTORE_FAILED: "bookmarks-restore-failed",
ACTION_SCHEME: "moz-action:",
observers: PlacesObservers,
/**
* GUIDs associated with virtual queries that are used for displaying the

View File

@ -63,6 +63,8 @@ interface mozIAsyncLivemarks : nsISupports
*/
void reloadLivemarks([optional]in boolean aForceUpdate);
void handlePlacesEvents(in jsval aEvents);
jsval invalidateCachedLivemarks();
};

View File

@ -12,8 +12,12 @@ ChromeUtils.defineModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyGetter(this, "history", function() {
let livemarks = PlacesUtils.livemarks;
// Lazily add an history observer when it's actually needed.
PlacesUtils.history.addObserver(PlacesUtils.livemarks, true);
PlacesUtils.history.addObserver(livemarks, true);
let listener = new PlacesWeakCallbackWrapper(
livemarks.handlePlacesEvents.bind(livemarks));
PlacesObservers.addListener(["page-visited"], listener);
return PlacesUtils.history;
});
@ -336,6 +340,21 @@ LivemarkService.prototype = {
return this._invalidateCachedLivemarks();
},
handlePlacesEvents(aEvents) {
if (!aEvents) {
throw new Components.Exception("Invalid arguments",
Cr.NS_ERROR_INVALID_ARG);
}
this._withLivemarksMap(livemarksMap => {
for (let event of aEvents) {
for (let livemark of livemarksMap.values()) {
livemark.updateURIVisitedStatus(event.url, true);
}
}
});
},
// nsINavBookmarkObserver
onBeginUpdateBatch() {},
@ -412,16 +431,6 @@ LivemarkService.prototype = {
});
},
onVisits(aVisits) {
this._withLivemarksMap(livemarksMap => {
for (let {uri} of aVisits) {
for (let livemark of livemarksMap.values()) {
livemark.updateURIVisitedStatus(uri, true);
}
}
});
},
// nsISupports
classID: Components.ID("{dca61eb5-c7cd-4df1-b0fb-d0722baba251}"),
@ -692,18 +701,18 @@ Livemark.prototype = {
/**
* Updates the visited status of nodes observing this livemark.
*
* @param aURI
* @param href
* If provided will update nodes having the given uri,
* otherwise any node.
* @param aVisitedStatus
* @param visitedStatus
* Whether the nodes should be set as visited.
*/
updateURIVisitedStatus(aURI, aVisitedStatus) {
updateURIVisitedStatus(href, visitedStatus) {
let wasVisited = false;
for (let child of this.children) {
if (!aURI || child.uri.equals(aURI)) {
if (!href || child.uri.spec == href) {
wasVisited = child.visited;
child.visited = aVisitedStatus;
child.visited = visitedStatus;
}
}
@ -711,7 +720,7 @@ Livemark.prototype = {
if (this._nodes.has(container)) {
let nodes = this._nodes.get(container);
for (let node of nodes) {
if (!aURI || node.uri == aURI.spec) {
if (!href || node.uri == href) {
Services.tm.dispatchToMainThread(() => {
observer.nodeHistoryDetailsChanged(node, node.time, wasVisited);
});
@ -818,6 +827,7 @@ LivemarkLoadListener.prototype = {
this._livemark.children = livemarkChildren;
} catch (ex) {
Cu.reportError(ex);
this.abort(ex);
} finally {
this._processor.listener = null;

View File

@ -17,6 +17,8 @@
#include "nsQueryObject.h"
#include "mozilla/Preferences.h"
#include "mozilla/storage.h"
#include "mozilla/dom/PlacesObservers.h"
#include "mozilla/dom/PlacesVisit.h"
#include "GeckoProfiler.h"
@ -212,6 +214,9 @@ nsNavBookmarks::Init()
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_STATE(history);
history->AddObserver(this, true);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Page_visited);
PlacesObservers::AddListener(events, this);
// DO NOT PUT STUFF HERE that can fail. See observer comment above.
@ -2053,30 +2058,28 @@ nsNavBookmarks::OnEndUpdateBatch()
}
NS_IMETHODIMP
nsNavBookmarks::OnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount)
void
nsNavBookmarks::HandlePlacesEvent(const PlacesEventSequence& aEvents)
{
NS_ENSURE_ARG(aVisits);
NS_ENSURE_ARG(aVisitsCount);
for (const auto& event : aEvents) {
if (NS_WARN_IF(event->Type() != PlacesEventType::Page_visited)) {
continue;
}
for (uint32_t i = 0; i < aVisitsCount; ++i) {
nsIVisitData* place = aVisits[i];
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(place->GetUri(getter_AddRefs(uri)));
const dom::PlacesVisit* visit = event->AsPlacesVisit();
if (NS_WARN_IF(!visit)) {
continue;
}
// If the page is bookmarked, notify observers for each associated bookmark.
ItemVisitData visitData;
nsresult rv = uri->GetSpec(visitData.bookmark.url);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_SUCCEEDS(place->GetVisitId(&visitData.visitId));
MOZ_ALWAYS_SUCCEEDS(place->GetTime(&visitData.time));
MOZ_ALWAYS_SUCCEEDS(place->GetTransitionType(&visitData.transitionType));
visitData.visitId = visit->mVisitId;
visitData.bookmark.url = NS_ConvertUTF16toUTF8(visit->mUrl);
visitData.time = visit->mVisitTime * 1000;
visitData.transitionType = visit->mTransitionType;
RefPtr< AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData> > notifier =
new AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData>(this, &nsNavBookmarks::NotifyItemVisited, visitData);
notifier->Init();
}
return NS_OK;
}

View File

@ -78,6 +78,7 @@ class nsNavBookmarks final : public nsINavBookmarksService
, public nsINavHistoryObserver
, public nsIObserver
, public nsSupportsWeakReference
, public mozilla::places::INativePlacesEventCallback
{
public:
NS_DECL_ISUPPORTS
@ -207,6 +208,16 @@ public:
*/
void NotifyItemChanged(const ItemChangeData& aData);
/**
* Part of INativePlacesEventCallback - handles events from the places
* observer system.
* @param aCx
* A JSContext for extracting the values from aEvents.
* @param aEvents
* An array of weakly typed events detailing what changed.
*/
void HandlePlacesEvent(const PlacesEventSequence& aEvents) override;
static const int32_t kGetChildrenIndex_Guid;
static const int32_t kGetChildrenIndex_Position;
static const int32_t kGetChildrenIndex_Type;

View File

@ -521,25 +521,15 @@ nsNavHistory::LoadPrefs()
}
void
nsNavHistory::NotifyOnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount)
nsNavHistory::UpdateDaysOfHistory(PRTime visitTime)
{
MOZ_ASSERT(aVisits, "Can't call NotifyOnVisits with a NULL aVisits");
MOZ_ASSERT(aVisitsCount, "Should have at least 1 visit when notifying");
if (mDaysOfHistory == 0) {
mDaysOfHistory = 1;
}
for (uint32_t i = 0; i < aVisitsCount; ++i) {
PRTime time;
MOZ_ALWAYS_SUCCEEDS(aVisits[i]->GetTime(&time));
if (time > mLastCachedEndOfDay || time < mLastCachedStartOfDay) {
mDaysOfHistory = -1;
}
if (visitTime > mLastCachedEndOfDay || visitTime < mLastCachedStartOfDay) {
mDaysOfHistory = -1;
}
NOTIFY_OBSERVERS(mCanNotify, mObservers, nsINavHistoryObserver,
OnVisits(aVisits, aVisitsCount));
}
void

View File

@ -435,9 +435,10 @@ public:
}
/**
* Fires onVisits event to nsINavHistoryService observers
* Updates and invalidates the mDaysOfHistory cache. Should be
* called whenever a visit is added.
*/
void NotifyOnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount);
void UpdateDaysOfHistory(PRTime visitTime);
/**
* Fires onTitleChanged event to nsINavHistoryService observers

View File

@ -19,6 +19,8 @@
#include "nsUnicharUtils.h"
#include "prtime.h"
#include "nsQueryObject.h"
#include "mozilla/dom/PlacesObservers.h"
#include "mozilla/dom/PlacesVisit.h"
#include "nsCycleCollectionParticipant.h"
@ -3996,6 +3998,9 @@ nsNavHistoryResult::StopObserving()
nsNavHistory* history = nsNavHistory::GetHistoryService();
if (history) {
history->RemoveObserver(this);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Page_visited);
PlacesObservers::RemoveListener(events, this);
mIsHistoryObserver = false;
}
}
@ -4008,6 +4013,9 @@ nsNavHistoryResult::AddHistoryObserver(nsNavHistoryQueryResultNode* aNode)
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ASSERTION(history, "Can't create history service");
history->AddObserver(this, true);
AutoTArray<PlacesEventType, 1> events;
events.AppendElement(PlacesEventType::Page_visited);
PlacesObservers::AddListener(events, this);
mIsHistoryObserver = true;
}
// Don't add duplicate observers. In some case we don't unregister when
@ -4591,32 +4599,27 @@ nsNavHistoryResult::OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
}
NS_IMETHODIMP
nsNavHistoryResult::OnVisits(nsIVisitData** aVisits,
uint32_t aVisitsCount) {
for (uint32_t i = 0; i < aVisitsCount; ++i) {
nsIVisitData* place = aVisits[i];
void
nsNavHistoryResult::HandlePlacesEvent(const PlacesEventSequence& aEvents) {
for (const auto& event : aEvents) {
if (NS_WARN_IF(event->Type() != PlacesEventType::Page_visited)) {
continue;
}
const dom::PlacesVisit* visit = event->AsPlacesVisit();
if (NS_WARN_IF(!visit)) {
continue;
}
nsCOMPtr<nsIURI> uri;
MOZ_ALWAYS_SUCCEEDS(place->GetUri(getter_AddRefs(uri)));
int64_t visitId;
MOZ_ALWAYS_SUCCEEDS(place->GetVisitId(&visitId));
PRTime time;
MOZ_ALWAYS_SUCCEEDS(place->GetTime(&time));
uint32_t transitionType;
MOZ_ALWAYS_SUCCEEDS(place->GetTransitionType(&transitionType));
nsCString guid;
MOZ_ALWAYS_SUCCEEDS(place->GetGuid(guid));
bool hidden;
MOZ_ALWAYS_SUCCEEDS(place->GetHidden(&hidden));
uint32_t visitCount;
MOZ_ALWAYS_SUCCEEDS(place->GetVisitCount(&visitCount));
nsString lastKnownTitle;
MOZ_ALWAYS_SUCCEEDS(place->GetLastKnownTitle(lastKnownTitle));
nsresult rv = OnVisit(uri, visitId, time, transitionType, guid, hidden,
visitCount, lastKnownTitle);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), visit->mUrl));
if (!uri) {
return;
}
OnVisit(uri, visit->mVisitId, visit->mVisitTime * 1000,
visit->mTransitionType, visit->mPageGuid,
visit->mHidden, visit->mVisitCount, visit->mLastKnownTitle);
}
return NS_OK;
}

View File

@ -12,6 +12,7 @@
#ifndef nsNavHistoryResult_h_
#define nsNavHistoryResult_h_
#include "INativePlacesEventCallback.h"
#include "nsTArray.h"
#include "nsInterfaceHashtable.h"
#include "nsDataHashtable.h"
@ -98,7 +99,8 @@ private:
class nsNavHistoryResult final : public nsSupportsWeakReference,
public nsINavHistoryResult,
public nsINavBookmarkObserver,
public nsINavHistoryObserver
public nsINavHistoryObserver,
public mozilla::places::INativePlacesEventCallback
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
@ -107,8 +109,6 @@ public:
NS_DECL_NSINAVHISTORYRESULT
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, nsINavHistoryResult)
NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(override)
NS_IMETHOD OnVisits(nsIVisitData** aVisits,
uint32_t aVisitsCount) override;
void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode);
void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, int64_t aFolder);
@ -174,6 +174,8 @@ public:
ContainerObserverList mRefreshParticipants;
void requestRefresh(nsNavHistoryContainerResultNode* aContainer);
void HandlePlacesEvent(const PlacesEventSequence& aEvents) override;
void OnMobilePrefChanged();
static void OnMobilePrefChangedCallback(const char* prefName, void* closure);

View File

@ -536,7 +536,6 @@ nsPlacesExpiration.prototype = {
this.status = STATUS.CLEAN;
},
onVisits() {},
onTitleChanged() {},
onDeleteURI() {},
onPageChanged() {},

View File

@ -827,7 +827,6 @@ var PageThumbsHistoryObserver = {
onTitleChanged() {},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onVisits() {},
onPageChanged() {},
onDeleteVisits() {},

View File

@ -549,6 +549,9 @@ var PlacesProvider = {
*/
init: function PlacesProvider_init() {
PlacesUtils.history.addObserver(this, true);
this._placesObserver =
new PlacesWeakCallbackWrapper(this.handlePlacesEvents.bind(this));
PlacesObservers.addListener(["page-visited"], this._placesObserver);
},
/**
@ -656,11 +659,11 @@ var PlacesProvider = {
}
},
onVisits(aVisits) {
handlePlacesEvents(aEvents) {
if (!this._batchProcessingDepth) {
for (let visit of aVisits) {
if (visit.visitCount == 1 && visit.lastKnownTitle) {
this.onTitleChanged(visit.uri, visit.lastKnownTitle, visit.guid);
for (let event of aEvents) {
if (event.visitCount == 1 && event.lastKnownTitle) {
this.onTitleChanged(event.url, event.lastKnownTitle, event.pageGuid);
}
}
}
@ -711,8 +714,11 @@ var PlacesProvider = {
* Called by the history service.
*/
onTitleChanged: function PlacesProvider_onTitleChanged(aURI, aNewTitle, aGUID) {
if (aURI instanceof Ci.nsIURI) {
aURI = aURI.spec;
}
this._callObservers("onLinkChanged", {
url: aURI.spec,
url: aURI,
title: aNewTitle
});
},