--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -92,26 +92,28 @@ const convertNavHistoryContainerResultNo
var _observer;
const getHistoryObserver = () => {
if (!_observer) {
_observer = new class extends EventEmitter {
onDeleteURI(uri, guid, reason) {
this.emit("visitRemoved", {allHistory: false, urls: [uri.spec]});
}
- onVisit(uri, visitId, time, sessionId, referringId, transitionType, guid, hidden, visitCount, typed, lastKnownTitle) {
- let data = {
- id: guid,
- url: uri.spec,
- title: lastKnownTitle || "",
- lastVisitTime: time / 1000, // time from Places is microseconds,
- visitCount,
- typedCount: typed,
- };
- this.emit("visited", data);
+ 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,
+ };
+ this.emit("visited", data);
+ }
}
onBeginUpdateBatch() {}
onEndUpdateBatch() {}
onTitleChanged(uri, title) {
this.emit("titleChanged", {url: uri.spec, title: title});
}
onClearHistory() {
this.emit("visitRemoved", {allHistory: true, urls: []});
--- a/browser/extensions/activity-stream/lib/PlacesFeed.jsm
+++ b/browser/extensions/activity-stream/lib/PlacesFeed.jsm
@@ -67,17 +67,17 @@ class HistoryObserver extends Observer {
*/
onClearHistory() {
this.dispatch({type: at.PLACES_HISTORY_CLEARED});
}
// Empty functions to make xpconnect happy
onBeginUpdateBatch() {}
onEndUpdateBatch() {}
- onVisit() {}
+ onVisits() {}
onTitleChanged() {}
onFrecencyChanged() {}
onManyFrecenciesChanged() {}
onPageChanged() {}
onDeleteVisits() {}
}
/**
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -838,17 +838,17 @@ this.AeroPeek = {
});
break;
}
},
/* nsINavHistoryObserver implementation */
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
- onVisit() {},
+ onVisits() {},
onTitleChanged() {},
onFrecencyChanged() {},
onManyFrecenciesChanged() {},
onDeleteURI() {},
onClearHistory() {},
onDeleteVisits() {},
onPageChanged(uri, changedConst, newValue) {
if (this.enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -465,25 +465,27 @@ HistoryTracker.prototype = {
onDeleteVisits(uri, visitTime, guid, reason) {
this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteVisits", SCORE_INCREMENT_SMALL);
},
onDeleteURI(uri, guid, reason) {
this.onDeleteAffectsGUID(uri, guid, reason, "onDeleteURI", SCORE_INCREMENT_XLARGE);
},
- onVisit(uri, vid, time, session, referrer, trans, guid) {
+ onVisits(aVisits) {
if (this.ignoreAll) {
- this._log.trace("ignoreAll: ignoring visit for " + guid);
+ this._log.trace("ignoreAll: ignoring visits [" +
+ aVisits.map(v => v.guid).join(",") + "]");
return;
}
-
- this._log.trace("onVisit: " + uri.spec);
- if (this.engine.shouldSyncURL(uri.spec) && this.addChangedID(guid)) {
- this.score += SCORE_INCREMENT_SMALL;
+ for (let {uri, guid} of aVisits) {
+ this._log.trace("onVisits: " + uri.spec);
+ if (this.engine.shouldSyncURL(uri.spec) && this.addChangedID(guid)) {
+ this.score += SCORE_INCREMENT_SMALL;
+ }
}
},
onClearHistory() {
this._log.trace("onClearHistory");
// Note that we're going to trigger a sync, but none of the cleared
// pages are tracked, so the deletions will not be propagated.
// See Bug 578694.
--- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
+++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm
@@ -1023,17 +1023,17 @@ this.DownloadHistoryObserver.prototype =
// nsINavHistoryObserver
onClearHistory: function DL_onClearHistory() {
this._list.removeFinished();
},
onTitleChanged() {},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
- onVisit() {},
+ onVisits() {},
onPageChanged() {},
onDeleteVisits() {},
};
/**
* This view can be added to a DownloadList object to trigger a save operation
* in the given DownloadStore object when a relevant change occurs. You should
* call the "initialize" method in order to register the view and load the
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -164,16 +164,131 @@ struct VisitData {
// Indicates whether frecency should be updated for this visit.
bool shouldUpdateFrecency;
// Whether this is a redirect source.
bool redirect;
};
////////////////////////////////////////////////////////////////////////////////
+//// nsVisitData
+
+class nsVisitData : public nsIVisitData
+{
+public:
+ explicit nsVisitData(nsIURI* aURI,
+ int64_t aVisitId,
+ PRTime aTime,
+ int64_t aReferrerVisitId,
+ int32_t aTransitionType,
+ const nsACString& aGuid,
+ bool aHidden,
+ uint32_t aVisitCount,
+ uint32_t aTyped,
+ const nsAString& aLastKnownTitle)
+ : mURI(aURI)
+ , mVisitId(aVisitId)
+ , mTime(aTime)
+ , mReferrerVisitId(aReferrerVisitId)
+ , mTransitionType(aTransitionType)
+ , mGuid(aGuid)
+ , mHidden(aHidden)
+ , mVisitCount(aVisitCount)
+ , mTyped(aTyped)
+ , mLastKnownTitle(aLastKnownTitle)
+ {
+ MOZ_ASSERT(NS_IsMainThread(),
+ "nsVisitData should only be constructed on the main thread.");
+ }
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD GetUri(nsIURI** aUri) override
+ {
+ NS_ENSURE_ARG_POINTER(aUri);
+ *aUri = mURI;
+ NS_IF_ADDREF(*aUri);
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetVisitId(int64_t* aVisitId) override
+ {
+ *aVisitId = mVisitId;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetTime(PRTime* aTime) override
+ {
+ *aTime = mTime;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetReferrerId(int64_t* aReferrerVisitId) override
+ {
+ *aReferrerVisitId = mReferrerVisitId;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetTransitionType(uint32_t* aTransitionType) override
+ {
+ *aTransitionType = mTransitionType;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetGuid(nsACString& aGuid) override
+ {
+ aGuid.Assign(mGuid);
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetHidden(bool* aHidden) override
+ {
+ *aHidden = mHidden;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetVisitCount(uint32_t* aVisitCount) override
+ {
+ *aVisitCount = mVisitCount;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetTyped(uint32_t* aTyped) override
+ {
+ *aTyped = mTyped;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetLastKnownTitle(nsAString& aLastKnownTitle) override
+ {
+ aLastKnownTitle.Assign(mLastKnownTitle);
+ return NS_OK;
+ }
+
+private:
+ virtual ~nsVisitData() {
+ MOZ_ASSERT(NS_IsMainThread(),
+ "nsVisitData should only be destructed on the main thread.");
+ };
+
+ nsCOMPtr<nsIURI> mURI;
+ int64_t mVisitId;
+ PRTime mTime;
+ int64_t mReferrerVisitId;
+ uint32_t mTransitionType;
+ nsCString mGuid;
+ bool mHidden;
+ uint32_t mVisitCount;
+ uint32_t mTyped;
+ nsString mLastKnownTitle;
+};
+
+NS_IMPL_ISUPPORTS(nsVisitData, nsIVisitData)
+
+////////////////////////////////////////////////////////////////////////////////
//// RemoveVisitsFilter
/**
* Used to store visit filters for RemoveVisits.
*/
struct RemoveVisitsFilter {
RemoveVisitsFilter()
: transitionType(UINT32_MAX)
@@ -643,56 +758,51 @@ public:
, mHistory(History::GetService())
{
aPlaces.SwapElements(mPlaces);
}
nsresult NotifyVisit(nsNavHistory* aNavHistory,
nsCOMPtr<nsIObserverService>& aObsService,
PRTime aNow,
- nsTArray<URIParams>& aNotifyVisitedURIs,
+ nsIURI* aURI,
const VisitData& aPlace) {
- nsCOMPtr<nsIURI> uri;
- MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), aPlace.spec));
- if (!uri) {
- return NS_ERROR_UNEXPECTED;
- }
- // Notify the visit. Note that TRANSITION_EMBED visits are never added
- // to the database, thus cannot be queried and we don't notify them.
- if (aPlace.transitionType != nsINavHistoryService::TRANSITION_EMBED) {
- aNavHistory->NotifyOnVisit(uri, 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);
- }
-
if (aObsService) {
DebugOnly<nsresult> rv =
- aObsService->NotifyObservers(uri, URI_VISIT_SAVED, nullptr);
+ aObsService->NotifyObservers(aURI, URI_VISIT_SAVED, nullptr);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Could not notify observers");
}
if (aNow - aPlace.visitTime < RECENTLY_VISITED_URIS_MAX_AGE) {
- mHistory->AppendToRecentlyVisitedURIs(uri);
+ mHistory->AppendToRecentlyVisitedURIs(aURI);
}
- mHistory->NotifyVisited(uri);
+ mHistory->NotifyVisited(aURI);
if (aPlace.titleChanged) {
- aNavHistory->NotifyTitleChange(uri, aPlace.title, aPlace.guid);
+ aNavHistory->NotifyTitleChange(aURI, aPlace.title, aPlace.guid);
}
- URIParams serialized;
- SerializeURI(uri, serialized);
- aNotifyVisitedURIs.AppendElement(Move(serialized));
-
return NS_OK;
}
+ void AddPlaceForNotify(const VisitData& aPlace,
+ nsIURI* aURI,
+ nsCOMArray<nsIVisitData>& aPlaces) {
+ 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());
+ }
+ }
+
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
// We are in the main thread, no need to lock.
if (mHistory->IsShuttingDown()) {
// If we are shutting down, we cannot notify the observers.
return NS_OK;
@@ -702,29 +812,62 @@ public:
if (!navHistory) {
NS_WARNING("Trying to notify visits observers but cannot get the history service!");
return NS_OK;
}
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
+ nsCOMArray<nsIVisitData> places;
+ nsCOMArray<nsIURI> uris;
+ if (mPlaces.Length() > 0) {
+ for (uint32_t i = 0; i < mPlaces.Length(); ++i) {
+ nsCOMPtr<nsIURI> uri;
+ MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), mPlaces[i].spec));
+ if (!uri) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ AddPlaceForNotify(mPlaces[i], uri, places);
+ uris.AppendElement(uri.forget());
+ }
+ } else {
+ nsCOMPtr<nsIURI> uri;
+ MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), mPlace.spec));
+ if (!uri) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ AddPlaceForNotify(mPlace, uri, places);
+ uris.AppendElement(uri.forget());
+ }
+ if (places.Length() > 0) {
+ navHistory->NotifyOnVisits(places.Elements(), places.Length());
+ }
+
PRTime now = PR_Now();
if (mPlaces.Length() > 0) {
- InfallibleTArray<URIParams> uris(mPlaces.Length());
+ InfallibleTArray<URIParams> serializableUris(mPlaces.Length());
for (uint32_t i = 0; i < mPlaces.Length(); ++i) {
- nsresult rv = NotifyVisit(navHistory, obsService, now, uris, mPlaces[i]);
+ nsresult rv = NotifyVisit(navHistory, obsService, now, uris[i], mPlaces[i]);
NS_ENSURE_SUCCESS(rv, rv);
+
+ URIParams serializedUri;
+ SerializeURI(uris[i], serializedUri);
+ serializableUris.AppendElement(Move(serializedUri));
}
- mHistory->NotifyVisitedParent(uris);
+ mHistory->NotifyVisitedParent(serializableUris);
} else {
- AutoTArray<URIParams, 1> uris;
- nsresult rv = NotifyVisit(navHistory, obsService, now, uris, mPlace);
+ AutoTArray<URIParams, 1> serializableUris;
+ nsresult rv = NotifyVisit(navHistory, obsService, now, uris[0], mPlace);
NS_ENSURE_SUCCESS(rv, rv);
- mHistory->NotifyVisitedParent(uris);
+
+ URIParams serializedUri;
+ SerializeURI(uris[0], serializedUri);
+ serializableUris.AppendElement(Move(serializedUri));
+ mHistory->NotifyVisitedParent(serializableUris);
}
return NS_OK;
}
private:
nsTArray<VisitData> mPlaces;
VisitData mPlace;
RefPtr<History> mHistory;
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -18,16 +18,77 @@ interface nsIFile;
interface nsINavHistoryContainerResultNode;
interface nsINavHistoryQueryResultNode;
interface nsINavHistoryQuery;
interface nsINavHistoryQueryOptions;
interface nsINavHistoryResult;
interface nsINavHistoryBatchCallback;
+/**
+ * This interface exists specifically for passing visit information
+ * in bulk to onVisits below.
+ */
+[scriptable, uuid(9d8df1ff-142f-4ca7-9f45-3c62a508c7e2)]
+interface nsIVisitData : nsISupports
+{
+ /**
+ * URI of the visit that was just created.
+ */
+ readonly attribute nsIURI uri;
+
+ /**
+ * Id of the visit that was just created.
+ */
+ readonly attribute long long visitId;
+
+ /**
+ * Time of the visit.
+ */
+ readonly attribute PRTime time;
+
+ /**
+ * The id of the visit the user came from, defaults to 0 for no referrer.
+ */
+ readonly attribute long long referrerId;
+
+ /**
+ * One of nsINavHistory.TRANSITION_*
+ */
+ readonly attribute unsigned long transitionType;
+
+ /**
+ * The unique id associated with the page.
+ */
+ readonly attribute ACString guid;
+
+ /**
+ * Whether the visited page is marked as hidden.
+ */
+ readonly attribute boolean hidden;
+
+ /**
+ * Number of visits (included this one) for this URI.
+ */
+ readonly attribute unsigned long visitCount;
+
+ /**
+ * Whether the URI has been typed or not.
+ * TODO (Bug 1271801): This will become a count, rather than a boolean.
+ * For future compatibility, always compare it with "> 0".
+ */
+ readonly attribute unsigned long typed;
+
+ /**
+ * The last known title of the page. Might not be from the current visit,
+ * and might be null if it is not known.
+ */
+ readonly attribute AString lastKnownTitle;
+};
+
[scriptable, uuid(91d104bb-17ef-404b-9f9a-d9ed8de6824c)]
interface nsINavHistoryResultNode : nsISupports
{
/**
* Indentifies the parent result node in the result set. This is null for
* top level nodes.
*/
readonly attribute nsINavHistoryContainerResultNode parent;
@@ -618,58 +679,26 @@ interface nsINavHistoryObserver : nsISup
/**
* Notifies you that we are done doing a bunch of things and you should go
* ahead and update UI, etc.
*/
void onEndUpdateBatch();
/**
- * Called everytime a URI is visited.
+ * Called everytime a URI is visited, or once for a batch of visits if visits were
+ * added in bulk.
*
* @note TRANSITION_EMBED visits (corresponding to images in a page, for
* example) are not displayed in history results. Most observers can
* ignore TRANSITION_EMBED visit notifications (which will comprise the
* majority of visit notifications) to save work.
- *
- * @param aVisitId
- * Id of the visit that was just created.
- * @param aTime
- * Time of the visit.
- * @param aSessionId
- * No longer supported and always set to 0.
- * @param aReferrerVisitId
- * The id of the visit the user came from, defaults to 0 for no referrer.
- * @param aTransitionType
- * One of nsINavHistory.TRANSITION_*
- * @param aGuid
- * The unique id associated with the page.
- * @param aHidden
- * Whether the visited page is marked as hidden.
- * @param aVisitCount
- * Number of visits (included this one) for this URI.
- * @param aTyped
- * Whether the URI has been typed or not.
- * TODO (Bug 1271801): This will become a count, rather than a boolean.
- * For future compatibility, always compare it with "> 0".
- * @param aLastKnownTitle
- * The last known title of the page. Might not be from the current visit,
- * and might be null if it is not known.
*/
- void onVisit(in nsIURI aURI,
- in long long aVisitId,
- in PRTime aTime,
- in long long aSessionId,
- in long long aReferrerVisitId,
- in unsigned long aTransitionType,
- in ACString aGuid,
- in boolean aHidden,
- in unsigned long aVisitCount,
- in unsigned long aTyped,
- in AString aLastKnownTitle);
+ void onVisits([array, size_is(aVisitsCount)] in nsIVisitData aVisits,
+ in unsigned long aVisitsCount);
/**
* Called whenever either the "real" title or the custom title of the page
* changed. BOTH TITLES ARE ALWAYS INCLUDED in this notification, even though
* only one will change at a time. Often, consumers will want to display the
* user title if it is available, and fall back to the page title (the one
* specified in the <title> tag of the page).
*
--- a/toolkit/components/places/nsLivemarkService.js
+++ b/toolkit/components/places/nsLivemarkService.js
@@ -409,20 +409,22 @@ LivemarkService.prototype = {
onDeleteURI(aURI) {
this._withLivemarksMap(livemarksMap => {
for (let livemark of livemarksMap.values()) {
livemark.updateURIVisitedStatus(aURI, false);
}
});
},
- onVisit(aURI) {
+ onVisits(aVisits) {
this._withLivemarksMap(livemarksMap => {
- for (let livemark of livemarksMap.values()) {
- livemark.updateURIVisitedStatus(aURI, true);
+ for (let {uri} of aVisits) {
+ for (let livemark of livemarksMap.values()) {
+ livemark.updateURIVisitedStatus(uri, true);
+ }
}
});
},
// nsISupports
classID: Components.ID("{dca61eb5-c7cd-4df1-b0fb-d0722baba251}"),
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -3151,35 +3151,38 @@ nsNavBookmarks::OnEndUpdateBatch()
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavBookmarkObserver, OnEndUpdateBatch());
return NS_OK;
}
NS_IMETHODIMP
-nsNavBookmarks::OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
- int64_t aSessionID, int64_t aReferringID,
- uint32_t aTransitionType, const nsACString& aGUID,
- bool aHidden, uint32_t aVisitCount, uint32_t aTyped,
- const nsAString& aLastKnownTitle)
+nsNavBookmarks::OnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount)
{
- NS_ENSURE_ARG(aURI);
-
- // If the page is bookmarked, notify observers for each associated bookmark.
- ItemVisitData visitData;
- nsresult rv = aURI->GetSpec(visitData.bookmark.url);
- NS_ENSURE_SUCCESS(rv, rv);
- visitData.visitId = aVisitId;
- visitData.time = aTime;
- visitData.transitionType = aTransitionType;
-
- RefPtr< AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData> > notifier =
- new AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData>(this, &nsNavBookmarks::NotifyItemVisited, visitData);
- notifier->Init();
+ NS_ENSURE_ARG(aVisits);
+ NS_ENSURE_ARG(aVisitsCount);
+
+ for (uint32_t i = 0; i < aVisitsCount; ++i) {
+ nsIVisitData* place = aVisits[i];
+ nsCOMPtr<nsIURI> uri;
+ MOZ_ALWAYS_SUCCEEDS(place->GetUri(getter_AddRefs(uri)));
+
+ // 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));
+
+ RefPtr< AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData> > notifier =
+ new AsyncGetBookmarksForURI<ItemVisitMethod, ItemVisitData>(this, &nsNavBookmarks::NotifyItemVisited, visitData);
+ notifier->Init();
+ }
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::OnDeleteURI(nsIURI* aURI,
const nsACString& aGUID,
uint16_t aReason)
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -110,16 +110,22 @@ public:
return gBookmarksService;
}
typedef mozilla::places::BookmarkData BookmarkData;
typedef mozilla::places::ItemVisitData ItemVisitData;
typedef mozilla::places::ItemChangeData ItemChangeData;
typedef mozilla::places::BookmarkStatementId BookmarkStatementId;
+ nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
+ int64_t aSessionId, int64_t aReferringId,
+ uint32_t aTransitionType, const nsACString& aGUID,
+ bool aHidden, uint32_t aVisitCount,
+ uint32_t aTyped, const nsAString& aLastKnownTitle);
+
nsresult ResultNodeForContainer(int64_t aID,
nsNavHistoryQueryOptions* aOptions,
nsNavHistoryResultNode** aNode);
// Find all the children of a folder, using the given query and options.
// For each child, a ResultNode is created and added to |children|.
// The results are ordered by folder position.
nsresult QueryFolderChildren(int64_t aFolderId,
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -513,45 +513,37 @@ nsNavHistory::LoadPrefs()
FRECENCY_PREF(mSecondBucketWeight, PREF_FREC_SECOND_BUCKET_WEIGHT);
FRECENCY_PREF(mThirdBucketWeight, PREF_FREC_THIRD_BUCKET_WEIGHT);
FRECENCY_PREF(mFourthBucketWeight, PREF_FREC_FOURTH_BUCKET_WEIGHT);
FRECENCY_PREF(mDefaultWeight, PREF_FREC_DEFAULT_BUCKET_WEIGHT);
#undef FRECENCY_PREF
}
-
void
-nsNavHistory::NotifyOnVisit(nsIURI* aURI,
- int64_t aVisitId,
- PRTime aTime,
- int64_t aReferrerVisitId,
- int32_t aTransitionType,
- const nsACString& aGuid,
- bool aHidden,
- uint32_t aVisitCount,
- uint32_t aTyped,
- const nsAString& aLastKnownTitle)
+nsNavHistory::NotifyOnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount)
{
- MOZ_ASSERT(!aGuid.IsEmpty());
- MOZ_ASSERT(aVisitCount, "Should have at least 1 visit when notifying");
- // If there's no history, this visit will surely add a day. If the visit is
- // added before or after the last cached day, the day count may have changed.
- // Otherwise adding multiple visits in the same day should not invalidate
- // the cache.
+ 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;
- } else if (aTime > mLastCachedEndOfDay || aTime < mLastCachedStartOfDay) {
- 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;
+ }
}
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
- OnVisit(aURI, aVisitId, aTime, 0, aReferrerVisitId,
- aTransitionType, aGuid, aHidden, aVisitCount, aTyped, aLastKnownTitle));
+ OnVisits(aVisits, aVisitsCount));
}
void
nsNavHistory::NotifyTitleChange(nsIURI* aURI,
const nsString& aTitle,
const nsACString& aGUID)
{
MOZ_ASSERT(!aGUID.IsEmpty());
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -432,28 +432,19 @@ public:
}
int32_t GetNumVisitsForFrecency() const
{
return mNumVisitsForFrecency;
}
/**
- * Fires onVisit event to nsINavHistoryService observers
+ * Fires onVisits event to nsINavHistoryService observers
*/
- void NotifyOnVisit(nsIURI* aURI,
- int64_t aVisitId,
- PRTime aTime,
- int64_t aReferrerVisitId,
- int32_t aTransitionType,
- const nsACString& aGuid,
- bool aHidden,
- uint32_t aVisitCount,
- uint32_t aTyped,
- const nsAString& aLastKnownTitle);
+ void NotifyOnVisits(nsIVisitData** aVisits, uint32_t aVisitsCount);
/**
* Fires onTitleChanged event to nsINavHistoryService observers
*/
void NotifyTitleChange(nsIURI* aURI,
const nsString& title,
const nsACString& aGUID);
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -2367,24 +2367,20 @@ static nsresult setHistoryDetailsCallbac
}
/**
* Here we need to update all copies of the URI we have with the new visit
* count, and potentially add a new entry in our query. This is the most
* common update operation and it is important that it be as efficient as
* possible.
*/
-NS_IMETHODIMP
+nsresult
nsNavHistoryQueryResultNode::OnVisit(nsIURI* aURI, int64_t aVisitId,
- PRTime aTime, int64_t aSessionId,
- int64_t aReferringId,
- uint32_t aTransitionType,
- const nsACString& aGUID,
- bool aHidden,
- uint32_t* aAdded)
+ PRTime aTime, uint32_t aTransitionType,
+ bool aHidden, uint32_t* aAdded)
{
if (aHidden && !mOptions->IncludeHidden())
return NS_OK;
nsNavHistoryResult* result = GetResult();
NS_ENSURE_STATE(result);
if (result->mBatchInProgress &&
++mBatchChanges > MAX_BATCH_CHANGES_BEFORE_REFRESH) {
@@ -4617,34 +4613,31 @@ nsNavHistoryResult::OnItemMoved(int64_t
ENUMERATE_HISTORY_OBSERVERS(OnItemMoved(aItemId, aOldParent, aOldIndex,
aNewParent, aNewIndex, aItemType,
aGUID, aOldParentGUID,
aNewParentGUID, aSource));
return NS_OK;
}
-NS_IMETHODIMP
+nsresult
nsNavHistoryResult::OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
- int64_t aSessionId, int64_t aReferringId,
- uint32_t aTransitionType, const nsACString& aGUID,
- bool aHidden, uint32_t aVisitCount, uint32_t aTyped,
- const nsAString& aLastKnownTitle)
+ uint32_t aTransitionType, const nsACString& aGUID, bool aHidden,
+ uint32_t aVisitCount, const nsAString& aLastKnownTitle)
{
NS_ENSURE_ARG(aURI);
// Embed visits are never shown in our views.
if (aTransitionType == nsINavHistoryService::TRANSITION_EMBED) {
return NS_OK;
}
uint32_t added = 0;
- ENUMERATE_HISTORY_OBSERVERS(OnVisit(aURI, aVisitId, aTime, aSessionId,
- aReferringId, aTransitionType, aGUID,
+ ENUMERATE_HISTORY_OBSERVERS(OnVisit(aURI, aVisitId, aTime, aTransitionType,
aHidden, &added));
// When we add visits through UpdatePlaces, we don't bother telling
// the world that the title 'changed' from nothing to the first title
// we ever see for a history entry. Our consumers here might still
// care, though, so we have to tell them - but only for the first
// visit we add. For subsequent changes, updateplaces will dispatch
// ontitlechanged notifications as normal.
@@ -4709,16 +4702,45 @@ nsNavHistoryResult::OnVisit(nsIURI* aURI
ENUMERATE_QUERY_OBSERVERS(Refresh(), mHistoryObservers, IsContainersQuery());
}
return NS_OK;
}
NS_IMETHODIMP
+nsNavHistoryResult::OnVisits(nsIVisitData** aVisits,
+ uint32_t aVisitsCount) {
+ for (uint32_t i = 0; i < aVisitsCount; ++i) {
+ nsIVisitData* place = aVisits[i];
+ 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);
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
nsNavHistoryResult::OnTitleChanged(nsIURI* aURI,
const nsAString& aPageTitle,
const nsACString& aGUID)
{
NS_ENSURE_ARG(aURI);
ENUMERATE_HISTORY_OBSERVERS(OnTitleChanged(aURI, aPageTitle, aGUID));
return NS_OK;
--- a/toolkit/components/places/nsNavHistoryResult.h
+++ b/toolkit/components/places/nsNavHistoryResult.h
@@ -73,35 +73,23 @@ private:
NS_IMETHOD OnClearHistory() __VA_ARGS__; \
NS_IMETHOD OnPageChanged(nsIURI *aURI, uint32_t aChangedAttribute, \
const nsAString &aNewValue, \
const nsACString &aGUID) __VA_ARGS__; \
NS_IMETHOD OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime, \
const nsACString& aGUID, uint16_t aReason, \
uint32_t aTransitionType) __VA_ARGS__;
-// The internal version has an output aAdded parameter, it is incremented by
-// query nodes when the visited uri belongs to them. If no such query exists,
-// the history result creates a new query node dynamically.
+// The internal version is used by query nodes.
#define NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL \
- NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE() \
- NS_IMETHOD OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime, \
- int64_t aSessionId, int64_t aReferringId, \
- uint32_t aTransitionType, const nsACString& aGUID, \
- bool aHidden, uint32_t* aAdded);
+ 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__) \
- NS_IMETHOD OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime, \
- int64_t aSessionId, int64_t aReferringId, \
- uint32_t aTransitionType, const nsACString& aGUID, \
- bool aHidden, uint32_t aVisitCount, \
- uint32_t aTyped, const nsAString& aLastKnownTitle) \
- __VA_ARGS__;
+ NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE(__VA_ARGS__)
// nsNavHistoryResult
//
// nsNavHistory creates this object and fills in mChildren (by getting
// it through GetTopLevel()). Then FilledAllResults() is called to finish
// object initialization.
#define NS_NAVHISTORYRESULT_IID \
@@ -119,27 +107,34 @@ public:
nsNavHistoryContainerResultNode* aRoot,
bool aBatchInProgress,
nsNavHistoryResult** result);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSINAVHISTORYRESULT
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, nsINavHistoryResult)
NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(override)
- NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, nsINavHistoryResult)
+ NS_IMETHOD OnVisits(nsIVisitData** aVisits,
+ uint32_t aVisitsCount) override;
void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode);
void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, int64_t aFolder);
void AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
void RemoveHistoryObserver(nsNavHistoryQueryResultNode* aNode);
void RemoveBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, int64_t aFolder);
void RemoveAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
void StopObserving();
+ nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
+ uint32_t aTransitionType, const nsACString& aGUID,
+ bool aHidden, uint32_t aVisitCount,
+ const nsAString& aLastKnownTitle);
+
public:
// two-stage init, use NewHistoryResult to construct
explicit nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot);
nsresult Init(nsINavHistoryQuery** aQueries,
uint32_t aQueryCount,
nsNavHistoryQueryOptions *aOptions);
RefPtr<nsNavHistoryContainerResultNode> mRootNode;
@@ -634,16 +629,23 @@ public:
NS_DECL_NSINAVHISTORYQUERYRESULTNODE
bool CanExpand();
bool IsContainersQuery();
virtual nsresult OpenContainer() override;
NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL
+
+ // The internal version has an output aAdded parameter, it is incremented by
+ // query nodes when the visited uri belongs to them. If no such query exists,
+ // the history result creates a new query node dynamically.
+ nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
+ uint32_t aTransitionType, bool aHidden,
+ uint32_t* aAdded);
virtual void OnRemoving() override;
public:
// this constructs lazily mURI from mQueries and mOptions, call
// VerifyQueriesSerialized either this or mQueries/mOptions should be valid
nsresult VerifyQueriesSerialized();
// these may be constructed lazily from mURI, call VerifyQueriesParsed
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -531,17 +531,17 @@ nsPlacesExpiration.prototype = {
this._newTimer();
},
onClearHistory: function PEX_onClearHistory() {
// History status is clean after a clear history.
this.status = STATUS.CLEAN;
},
- onVisit() {},
+ onVisits() {},
onTitleChanged() {},
onDeleteURI() {},
onPageChanged() {},
onDeleteVisits() {},
// nsITimerCallback
notify: function PEX_timerCallback() {
--- a/toolkit/components/thumbnails/PageThumbs.jsm
+++ b/toolkit/components/thumbnails/PageThumbs.jsm
@@ -827,15 +827,15 @@ var PageThumbsHistoryObserver = {
onClearHistory() {
PageThumbsStorage.wipe();
},
onTitleChanged() {},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
- onVisit() {},
+ onVisits() {},
onPageChanged() {},
onDeleteVisits() {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference])
};
--- a/toolkit/modules/NewTabUtils.jsm
+++ b/toolkit/modules/NewTabUtils.jsm
@@ -742,21 +742,23 @@ var PlacesProvider = {
onEndUpdateBatch() {
this._batchProcessingDepth -= 1;
if (this._batchProcessingDepth == 0 && this._batchCalledFrecencyChanged) {
this.onManyFrecenciesChanged();
this._batchCalledFrecencyChanged = false;
}
},
- onVisit(aURI, aVisitId, aTime, aSessionId, aReferrerVisitId, aTransitionType,
- aGuid, aHidden, aVisitCount, aTyped, aLastKnownTitle) {
- // For new visits, if we're not batch processing, notify for a title // update
- if (!this._batchProcessingDepth && aVisitCount == 1 && aLastKnownTitle) {
- this.onTitleChanged(aURI, aLastKnownTitle, aGuid);
+ onVisits(aVisits) {
+ if (!this._batchProcessingDepth) {
+ for (let visit of aVisits) {
+ if (visit.visitCount == 1 && visit.lastKnownTitle) {
+ this.onTitleChanged(visit.uri, visit.lastKnownTitle, visit.guid);
+ }
+ }
}
},
onDeleteURI: function PlacesProvider_onDeleteURI(aURI, aGUID, aReason) {
// let observers remove sensetive data associated with deleted visit
this._callObservers("onDeleteURI", {
url: aURI.spec,
});