summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/nsNavHistory.h
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/nsNavHistory.h')
-rw-r--r--toolkit/components/places/nsNavHistory.h465
1 files changed, 465 insertions, 0 deletions
diff --git a/toolkit/components/places/nsNavHistory.h b/toolkit/components/places/nsNavHistory.h
new file mode 100644
index 0000000000..2c291cfdbe
--- /dev/null
+++ b/toolkit/components/places/nsNavHistory.h
@@ -0,0 +1,465 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsNavHistory_h_
+#define nsNavHistory_h_
+
+#include "nsINavHistoryService.h"
+
+#include "nsIStringBundle.h"
+#include "nsITimer.h"
+#include "nsMaybeWeakPtr.h"
+#include "nsCategoryCache.h"
+#include "nsNetCID.h"
+#include "nsToolkitCompsCID.h"
+#include "nsURIHashKey.h"
+#include "nsTHashtable.h"
+
+#include "nsNavHistoryResult.h"
+#include "nsNavHistoryQuery.h"
+#include "Database.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/intl/Collator.h"
+#include "mozilla/UniquePtr.h"
+#include "mozIStorageVacuumParticipant.h"
+
+#define QUERYUPDATE_TIME 0
+#define QUERYUPDATE_SIMPLE 1
+#define QUERYUPDATE_COMPLEX 2
+#define QUERYUPDATE_COMPLEX_WITH_BOOKMARKS 3
+#define QUERYUPDATE_HOST 4
+#define QUERYUPDATE_MOBILEPREF 5
+#define QUERYUPDATE_NONE 6
+
+// Clamp title and URL to generously large, but not too large, length.
+// See bug 319004 for details.
+#define URI_LENGTH_MAX 65536
+#define TITLE_LENGTH_MAX 4096
+
+// Microsecond timeout for "recent" events such as typed and bookmark following.
+// If you typed it more than this time ago, it's not recent.
+#define RECENT_EVENT_THRESHOLD PRTime((int64_t)15 * 60 * PR_USEC_PER_SEC)
+
+// The preference we watch to know when the mobile bookmarks folder is filled by
+// sync.
+#define MOBILE_BOOKMARKS_PREF "browser.bookmarks.showMobileBookmarks"
+
+// The guid of the mobile bookmarks virtual query.
+#define MOBILE_BOOKMARKS_VIRTUAL_GUID "mobile_____v"
+
+#define ROOT_GUID "root________"
+#define MENU_ROOT_GUID "menu________"
+#define TOOLBAR_ROOT_GUID "toolbar_____"
+#define UNFILED_ROOT_GUID "unfiled_____"
+#define TAGS_ROOT_GUID "tags________"
+#define MOBILE_ROOT_GUID "mobile______"
+
+class mozIStorageValueArray;
+class nsIAutoCompleteController;
+class nsIEffectiveTLDService;
+class nsIIDNService;
+class nsNavHistory;
+class PlacesSQLQueryBuilder;
+
+// nsNavHistory
+
+class nsNavHistory final : public nsSupportsWeakReference,
+ public nsINavHistoryService,
+ public nsIObserver,
+ public mozIStorageVacuumParticipant {
+ friend class PlacesSQLQueryBuilder;
+
+ public:
+ nsNavHistory();
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSINAVHISTORYSERVICE
+ NS_DECL_NSIOBSERVER
+ NS_DECL_MOZISTORAGEVACUUMPARTICIPANT
+
+ /**
+ * Obtains the nsNavHistory object.
+ */
+ static already_AddRefed<nsNavHistory> GetSingleton();
+
+ /**
+ * Initializes the nsNavHistory object. This should only be called once.
+ */
+ nsresult Init();
+
+ /**
+ * Used by other components in the places directory such as the annotation
+ * service to get a reference to this history object. Returns a pointer to
+ * the service if it exists. Otherwise creates one. Returns nullptr on error.
+ */
+ static nsNavHistory* GetHistoryService() {
+ if (!gHistoryService) {
+ nsCOMPtr<nsINavHistoryService> serv =
+ do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(serv, nullptr);
+ NS_ASSERTION(gHistoryService, "Should have static instance pointer now");
+ }
+ return gHistoryService;
+ }
+
+ /**
+ * Used by other components in the places directory to get a reference to a
+ * const version of this history object.
+ *
+ * @return A pointer to a const version of the service if it exists,
+ * nullptr otherwise.
+ */
+ static const nsNavHistory* GetConstHistoryService() {
+ const nsNavHistory* const history = gHistoryService;
+ return history;
+ }
+
+ /**
+ * Fetches the database id and the GUID associated to the given URI.
+ *
+ * @param aURI
+ * The page to look for.
+ * @param _pageId
+ * Will be set to the database id associated with the page.
+ * If the page doesn't exist, this will be zero.
+ * @param _GUID
+ * Will be set to the unique id associated with the page.
+ * If the page doesn't exist, this will be empty.
+ * @note This DOES NOT check for bad URLs other than that they're nonempty.
+ */
+ nsresult GetIdForPage(nsIURI* aURI, int64_t* _pageId, nsCString& _GUID);
+
+ /**
+ * Fetches the database id and the GUID associated to the given URI, creating
+ * a new database entry if one doesn't exist yet.
+ *
+ * @param aURI
+ * The page to look for or create.
+ * @param _pageId
+ * Will be set to the database id associated with the page.
+ * @param _GUID
+ * Will be set to the unique id associated with the page.
+ * @note This DOES NOT check for bad URLs other than that they're nonempty.
+ * @note This DOES NOT update frecency of the page.
+ */
+ nsresult GetOrCreateIdForPage(nsIURI* aURI, int64_t* _pageId,
+ nsCString& _GUID);
+
+ /**
+ * These functions return non-owning references to the locale-specific
+ * objects for places components.
+ */
+ nsIStringBundle* GetBundle();
+ const mozilla::intl::Collator* GetCollator();
+ void GetStringFromName(const char* aName, nsACString& aResult);
+ void GetAgeInDaysString(int32_t aInt, const char* aName, nsACString& aResult);
+ static void GetMonthName(const PRExplodedTime& aTime, nsACString& aResult);
+ static void GetMonthYear(const PRExplodedTime& aTime, nsACString& aResult);
+
+ // Returns whether history is enabled or not.
+ bool IsHistoryDisabled() { return !mHistoryEnabled; }
+
+ // Returns whether or not diacritics must match in history text searches.
+ bool MatchDiacritics() const { return mMatchDiacritics; }
+
+ // Constants for the columns returned by the above statement.
+ static const int32_t kGetInfoIndex_PageID;
+ static const int32_t kGetInfoIndex_URL;
+ static const int32_t kGetInfoIndex_Title;
+ static const int32_t kGetInfoIndex_RevHost;
+ static const int32_t kGetInfoIndex_VisitCount;
+ static const int32_t kGetInfoIndex_VisitDate;
+ static const int32_t kGetInfoIndex_FaviconURL;
+ static const int32_t kGetInfoIndex_ItemId;
+ static const int32_t kGetInfoIndex_ItemDateAdded;
+ static const int32_t kGetInfoIndex_ItemLastModified;
+ static const int32_t kGetInfoIndex_ItemParentId;
+ static const int32_t kGetInfoIndex_ItemTags;
+ static const int32_t kGetInfoIndex_Frecency;
+ static const int32_t kGetInfoIndex_Hidden;
+ static const int32_t kGetInfoIndex_Guid;
+ static const int32_t kGetInfoIndex_VisitId;
+ static const int32_t kGetInfoIndex_FromVisitId;
+ static const int32_t kGetInfoIndex_VisitType;
+
+ int64_t GetTagsFolder();
+
+ // this actually executes a query and gives you results, it is used by
+ // nsNavHistoryQueryResultNode
+ nsresult GetQueryResults(nsNavHistoryQueryResultNode* aResultNode,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
+ nsCOMArray<nsNavHistoryResultNode>* aResults);
+
+ // Take a row of kGetInfoIndex_* columns and construct a ResultNode.
+ // The row must contain the full set of columns.
+ nsresult RowToResult(mozIStorageValueArray* aRow,
+ nsNavHistoryQueryOptions* aOptions,
+ nsNavHistoryResultNode** aResult);
+ nsresult QueryRowToResult(int64_t aItemId, const nsACString& aBookmarkGuid,
+ const nsACString& aURI, const nsACString& aTitle,
+ uint32_t aAccessCount, PRTime aTime,
+ nsNavHistoryResultNode** aNode);
+
+ nsresult VisitIdToResultNode(int64_t visitId,
+ nsNavHistoryQueryOptions* aOptions,
+ nsNavHistoryResultNode** aResult);
+
+ nsresult BookmarkIdToResultNode(int64_t aBookmarkId,
+ nsNavHistoryQueryOptions* aOptions,
+ nsNavHistoryResultNode** aResult);
+ nsresult URIToResultNode(nsIURI* aURI, nsNavHistoryQueryOptions* aOptions,
+ nsNavHistoryResultNode** aResult);
+
+ /**
+ * Returns current number of days stored in history.
+ */
+ int32_t GetDaysOfHistory();
+
+ void DomainNameFromURI(nsIURI* aURI, nsACString& aDomainName);
+ static PRTime NormalizeTime(uint32_t aRelative, PRTime aOffset);
+
+ typedef nsTHashMap<nsCStringHashKey, nsCString> StringHash;
+
+ enum RecentEventFlags {
+ RECENT_TYPED = 1 << 0, // User typed in URL recently
+ RECENT_ACTIVATED = 1 << 1, // User tapped URL link recently
+ RECENT_BOOKMARKED = 1 << 2 // User bookmarked URL recently
+ };
+
+ /**
+ * Returns any recent activity done with a URL.
+ * @return Any recent events associated with this URI. Each bit is set
+ * according to RecentEventFlags enum values.
+ */
+ uint32_t GetRecentFlags(nsIURI* aURI);
+
+ /**
+ * Whether there are visits.
+ * Note: This may cause synchronous I/O.
+ */
+ bool hasHistoryEntries();
+
+ /**
+ * Returns whether the specified url has a embed visit.
+ *
+ * @param aURI
+ * URI of the page.
+ * @return whether the page has a embed visit.
+ */
+ bool hasEmbedVisit(nsIURI* aURI);
+
+ int32_t GetFrecencyAgedWeight(int32_t aAgeInDays) const {
+ if (aAgeInDays <= mFirstBucketCutoffInDays) {
+ return mFirstBucketWeight;
+ }
+ if (aAgeInDays <= mSecondBucketCutoffInDays) {
+ return mSecondBucketWeight;
+ }
+ if (aAgeInDays <= mThirdBucketCutoffInDays) {
+ return mThirdBucketWeight;
+ }
+ if (aAgeInDays <= mFourthBucketCutoffInDays) {
+ return mFourthBucketWeight;
+ }
+ return mDefaultWeight;
+ }
+
+ int32_t GetFrecencyTransitionBonus(int32_t aTransitionType, bool aVisited,
+ bool aRedirect = false) const {
+ if (aRedirect) {
+ return mRedirectSourceVisitBonus;
+ }
+
+ switch (aTransitionType) {
+ case nsINavHistoryService::TRANSITION_EMBED:
+ return mEmbedVisitBonus;
+ case nsINavHistoryService::TRANSITION_FRAMED_LINK:
+ return mFramedLinkVisitBonus;
+ case nsINavHistoryService::TRANSITION_LINK:
+ return mLinkVisitBonus;
+ case nsINavHistoryService::TRANSITION_TYPED:
+ return aVisited ? mTypedVisitBonus : mUnvisitedTypedBonus;
+ case nsINavHistoryService::TRANSITION_BOOKMARK:
+ return aVisited ? mBookmarkVisitBonus : mUnvisitedBookmarkBonus;
+ case nsINavHistoryService::TRANSITION_DOWNLOAD:
+ return mDownloadVisitBonus;
+ case nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT:
+ return mPermRedirectVisitBonus;
+ case nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY:
+ return mTempRedirectVisitBonus;
+ case nsINavHistoryService::TRANSITION_RELOAD:
+ return mReloadVisitBonus;
+ default:
+ // 0 == undefined (see bug #375777 for details)
+ NS_WARNING_ASSERTION(!aTransitionType,
+ "new transition but no bonus for frecency");
+ return mDefaultVisitBonus;
+ }
+ }
+
+ int32_t GetNumVisitsForFrecency() const { return mNumVisitsForFrecency; }
+
+ /**
+ * Updates and invalidates the mDaysOfHistory cache. Should be
+ * called whenever a visit is added.
+ */
+ void UpdateDaysOfHistory(PRTime visitTime);
+
+ /**
+ * Store last insterted id for a table.
+ */
+ static mozilla::Atomic<int64_t> sLastInsertedPlaceId;
+ static mozilla::Atomic<int64_t> sLastInsertedVisitId;
+
+ /**
+ * Tracks whether frecency is currently being decayed.
+ */
+ static mozilla::Atomic<bool> sIsFrecencyDecaying;
+ /**
+ * Tracks whether there's frecency to be recalculated.
+ */
+ static mozilla::Atomic<bool> sShouldStartFrecencyRecalculation;
+
+ static void StoreLastInsertedId(const nsACString& aTable,
+ const int64_t aLastInsertedId);
+
+ static nsresult FilterResultSet(
+ nsNavHistoryQueryResultNode* aParentNode,
+ const nsCOMArray<nsNavHistoryResultNode>& aSet,
+ nsCOMArray<nsNavHistoryResultNode>* aFiltered,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ nsNavHistoryQueryOptions* aOptions);
+
+ static void InvalidateDaysOfHistory();
+
+ private:
+ ~nsNavHistory();
+
+ // used by GetHistoryService
+ static nsNavHistory* gHistoryService;
+
+ static mozilla::Atomic<int32_t> sDaysOfHistory;
+
+ protected:
+ // Database handle.
+ RefPtr<mozilla::places::Database> mDB;
+
+ /**
+ * Loads all of the preferences that we use into member variables.
+ *
+ * @note If mPrefBranch is nullptr, this does nothing.
+ */
+ void LoadPrefs();
+
+ /**
+ * Calculates and returns value for mCachedNow.
+ * This is an hack to avoid calling PR_Now() too often, as is the case when
+ * we're asked the ageindays of many history entries in a row. A timer is
+ * set which will clear our valid flag after a short timeout.
+ */
+ PRTime GetNow();
+ PRTime mCachedNow;
+ nsCOMPtr<nsITimer> mExpireNowTimer;
+ /**
+ * Called when the cached now value is expired and needs renewal.
+ */
+ static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
+
+ nsresult ConstructQueryString(
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions, nsCString& queryString,
+ bool& aParamsPresent, StringHash& aAddParams);
+
+ nsresult QueryToSelectClause(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
+ nsCString* aClause);
+ nsresult BindQueryClauseParameters(
+ mozIStorageBaseStatement* statement,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions);
+
+ nsresult ResultsAsList(mozIStorageStatement* statement,
+ nsNavHistoryQueryOptions* aOptions,
+ nsCOMArray<nsNavHistoryResultNode>* aResults);
+
+ // effective tld service
+ nsCOMPtr<nsIEffectiveTLDService> mTLDService;
+ nsCOMPtr<nsIIDNService> mIDNService;
+
+ // localization
+ nsCOMPtr<nsIStringBundle> mBundle;
+ mozilla::UniquePtr<const mozilla::intl::Collator> mCollator;
+
+ // recent events
+ typedef nsTHashMap<nsCStringHashKey, int64_t> RecentEventHash;
+ RecentEventHash mRecentTyped;
+ RecentEventHash mRecentLink;
+ RecentEventHash mRecentBookmark;
+
+ bool CheckIsRecentEvent(RecentEventHash* hashTable, const nsACString& url);
+ void ExpireNonrecentEvents(RecentEventHash* hashTable);
+
+ // Whether history is enabled or not.
+ // Will mimic value of the places.history.enabled preference.
+ bool mHistoryEnabled;
+
+ // Whether or not diacritics must match in history text searches.
+ // Will mimic value of the places.search.matchDiacritics preference.
+ bool mMatchDiacritics;
+
+ // Frecency preferences.
+ int32_t mNumVisitsForFrecency;
+ int32_t mFirstBucketCutoffInDays;
+ int32_t mSecondBucketCutoffInDays;
+ int32_t mThirdBucketCutoffInDays;
+ int32_t mFourthBucketCutoffInDays;
+ int32_t mFirstBucketWeight;
+ int32_t mSecondBucketWeight;
+ int32_t mThirdBucketWeight;
+ int32_t mFourthBucketWeight;
+ int32_t mDefaultWeight;
+ int32_t mEmbedVisitBonus;
+ int32_t mFramedLinkVisitBonus;
+ int32_t mLinkVisitBonus;
+ int32_t mTypedVisitBonus;
+ int32_t mBookmarkVisitBonus;
+ int32_t mDownloadVisitBonus;
+ int32_t mPermRedirectVisitBonus;
+ int32_t mTempRedirectVisitBonus;
+ int32_t mRedirectSourceVisitBonus;
+ int32_t mDefaultVisitBonus;
+ int32_t mUnvisitedBookmarkBonus;
+ int32_t mUnvisitedTypedBonus;
+ int32_t mReloadVisitBonus;
+
+ nsresult RecalculateOriginFrecencyStatsInternal();
+
+ // in nsNavHistoryQuery.cpp
+ nsresult TokensToQuery(
+ const nsTArray<mozilla::places::QueryKeyValuePair>& aTokens,
+ nsNavHistoryQuery* aQuery, nsNavHistoryQueryOptions* aOptions);
+
+ int64_t mTagsFolder;
+
+ int64_t mLastCachedStartOfDay;
+ int64_t mLastCachedEndOfDay;
+};
+
+#define PLACES_URI_PREFIX "place:"
+
+/* Returns true if the given URI represents a history query. */
+inline bool IsQueryURI(const nsCString& uri) {
+ return StringBeginsWith(uri, nsLiteralCString(PLACES_URI_PREFIX));
+}
+
+/* Extracts the query string from a query URI. */
+inline const nsDependentCSubstring QueryURIToQuery(const nsCString& uri) {
+ NS_ASSERTION(IsQueryURI(uri), "should only be called for query URIs");
+ return Substring(uri, nsLiteralCString(PLACES_URI_PREFIX).Length());
+}
+
+#endif // nsNavHistory_h_