--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -616,79 +616,107 @@ private:
NS_IMPL_ISUPPORTS_INHERITED(
VisitedQuery
, AsyncStatementCallback
, mozIStorageCompletionCallback
)
/**
- * Notifies observers about a visit.
+ * Notifies observers about a visit or an array of visits.
*/
-class NotifyVisitObservers : public Runnable
+class NotifyManyVisitsObservers : public Runnable
{
public:
- explicit NotifyVisitObservers(VisitData& aPlace)
- : Runnable("places::NotifyVisitObservers")
+ explicit NotifyManyVisitsObservers(VisitData aPlace)
+ : Runnable("places::NotifyManyVisitsObservers")
, mPlace(aPlace)
, mHistory(History::GetService())
{
}
+ explicit NotifyManyVisitsObservers(nsTArray<VisitData>& aPlaces)
+ : Runnable("places::NotifyManyVisitsObservers")
+ , mHistory(History::GetService())
+ {
+ aPlaces.SwapElements(mPlaces);
+ }
+
+ nsresult NotifyVisit(nsNavHistory* aNavHistory,
+ nsCOMPtr<nsIObserverService>& aObsService,
+ PRTime aNow,
+ 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);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Could not notify observers");
+ }
+
+ if (aNow - aPlace.visitTime < RECENTLY_VISITED_URIS_MAX_AGE) {
+ mHistory->AppendToRecentlyVisitedURIs(uri);
+ }
+ mHistory->NotifyVisited(uri);
+
+ if (aPlace.titleChanged) {
+ aNavHistory->NotifyTitleChange(uri, aPlace.title, aPlace.guid);
+ }
+
+ return NS_OK;
+ }
+
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;
}
nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
if (!navHistory) {
- NS_WARNING("Trying to notify about a visit but cannot get the history service!");
+ NS_WARNING("Trying to notify visits observers but cannot get the history service!");
return NS_OK;
}
- nsCOMPtr<nsIURI> uri;
- MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(uri), mPlace.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 (mPlace.transitionType != nsINavHistoryService::TRANSITION_EMBED) {
- navHistory->NotifyOnVisit(uri, mPlace.visitId, mPlace.visitTime,
- mPlace.referrerVisitId, mPlace.transitionType,
- mPlace.guid, mPlace.hidden,
- mPlace.visitCount + 1, // Add current visit.
- static_cast<uint32_t>(mPlace.typed),
- mPlace.title);
- }
-
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
- if (obsService) {
- DebugOnly<nsresult> rv =
- obsService->NotifyObservers(uri, URI_VISIT_SAVED, nullptr);
- NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Could not notify observers");
+
+ PRTime now = PR_Now();
+ if (mPlaces.Length() > 0) {
+ for (uint32_t i = 0; i < mPlaces.Length(); ++i) {
+ nsresult rv = NotifyVisit(navHistory, obsService, now, mPlaces[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ } else {
+ nsresult rv = NotifyVisit(navHistory, obsService, now, mPlace);
+ NS_ENSURE_SUCCESS(rv, rv);
}
- History* history = History::GetService();
- NS_ENSURE_STATE(history);
- if (PR_Now() - mPlace.visitTime < RECENTLY_VISITED_URIS_MAX_AGE) {
- mHistory->AppendToRecentlyVisitedURIs(uri);
- }
- history->NotifyVisited(uri);
-
return NS_OK;
}
private:
+ nsTArray<VisitData> mPlaces;
VisitData mPlace;
RefPtr<History> mHistory;
};
/**
* Notifies observers about a pages title changing.
*/
class NotifyTitleObservers : public Runnable
@@ -982,17 +1010,18 @@ public:
if (mHistory->IsShuttingDown()) {
// If we were already shutting down, we cannot insert the URIs.
return NS_OK;
}
mozStorageTransaction transaction(mDBConn, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
- VisitData* lastFetchedPlace = nullptr;
+ const VisitData* lastFetchedPlace = nullptr;
+ uint32_t lastFetchedVisitCount = 0;
for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
VisitData& place = mPlaces.ElementAt(i);
// Fetching from the database can overwrite this information, so save it
// apart.
bool typed = place.typed;
bool hidden = place.hidden;
@@ -1005,26 +1034,27 @@ public:
if (!!mCallback && !mIgnoreErrors) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
return NS_DispatchToMainThread(event);
}
return NS_OK;
}
lastFetchedPlace = &mPlaces.ElementAt(i);
+ lastFetchedVisitCount = lastFetchedPlace->visitCount;
} else {
// Copy over the data from the already known place.
place.placeId = lastFetchedPlace->placeId;
place.guid = lastFetchedPlace->guid;
place.lastVisitId = lastFetchedPlace->visitId;
place.lastVisitTime = lastFetchedPlace->visitTime;
place.titleChanged = !lastFetchedPlace->title.Equals(place.title);
place.frecency = lastFetchedPlace->frecency;
// Add one visit for the previous loop.
- place.visitCount = ++(*lastFetchedPlace).visitCount;
+ place.visitCount = ++lastFetchedVisitCount;
}
// If any transition is typed, ensure the page is marked as typed.
if (typed != lastFetchedPlace->typed) {
place.typed = true;
}
// If any transition is visible, ensure the page is marked as visible.
@@ -1052,42 +1082,35 @@ public:
NS_ENSURE_SUCCESS(rv2, rv2);
}
}
NS_ENSURE_SUCCESS(rv, rv);
// If we get here, we must have been successful adding/updating this
// visit/place, so update the count:
mSuccessfulUpdatedCount++;
-
- nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(place);
- rv = NS_DispatchToMainThread(event);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // Notify about title change if needed.
- if (place.titleChanged) {
- event = new NotifyTitleObservers(place.spec, place.title, place.guid);
- rv = NS_DispatchToMainThread(event);
- NS_ENSURE_SUCCESS(rv, rv);
- }
}
{
// Trigger an update for all the hosts of the places we inserted
nsAutoCString query("DELETE FROM moz_updatehostsinsert_temp");
nsCOMPtr<mozIStorageStatement> stmt = mHistory->GetStatement(query);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
nsresult rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIRunnable> event = new NotifyManyVisitsObservers(mPlaces);
+ rv = NS_DispatchToMainThread(event);
+ NS_ENSURE_SUCCESS(rv, rv);
+
return NS_OK;
}
private:
InsertVisitedURIs(
mozIStorageConnection* aConnection,
nsTArray<VisitData>& aPlaces,
const nsMainThreadPtrHandle<mozIVisitInfoCallback>& aCallback,
bool aGroupNotifications,
@@ -1915,17 +1938,17 @@ StoreAndNotifyEmbedVisit(VisitData& aPla
Unused << aCallback->GetIgnoreResults(&ignoreResults);
if (!ignoreResults) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(callback, aPlace, true, NS_OK);
(void)NS_DispatchToMainThread(event);
}
}
- nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(aPlace);
+ nsCOMPtr<nsIRunnable> event = new NotifyManyVisitsObservers(aPlace);
(void)NS_DispatchToMainThread(event);
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
//// History