// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_HISTORY_TOP_SITES_H_ #define CHROME_BROWSER_HISTORY_TOP_SITES_H_ #pragma once #include <list> #include <set> #include <string> #include <utility> #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" #include "base/synchronization/lock.h" #include "base/time.h" #include "base/timer.h" #include "chrome/browser/history/history_types.h" #include "chrome/browser/history/history.h" #include "chrome/browser/history/page_usage_data.h" #include "chrome/common/thumbnail_score.h" #include "content/browser/cancelable_request.h" #include "googleurl/src/gurl.h" class DictionaryValue; class FilePath; class SkBitmap; class Profile; namespace history { class TopSitesCache; class TopSitesBackend; class TopSitesTest; // Stores the data for the top "most visited" sites. This includes a cache of // the most visited data from history, as well as the corresponding thumbnails // of those sites. // // This class allows requests for most visited urls and thumbnails on any // thread. All other methods must be invoked on the UI thread. All mutations // to internal state happen on the UI thread and are scheduled to update the // db using TopSitesBackend. class TopSites : public base::RefCountedThreadSafe<TopSites>, public NotificationObserver, public CancelableRequestProvider { public: explicit TopSites(Profile* profile); // Initializes TopSites. void Init(const FilePath& db_name); // Sets the given thumbnail for the given URL. Returns true if the thumbnail // was updated. False means either the URL wasn't known to us, or we felt // that our current thumbnail was superior to the given one. bool SetPageThumbnail(const GURL& url, const SkBitmap& thumbnail, const ThumbnailScore& score); // Callback for GetMostVisitedURLs. typedef Callback1<const MostVisitedURLList&>::Type GetTopSitesCallback; typedef std::set<scoped_refptr<CancelableRequest<GetTopSitesCallback> > > PendingCallbackSet; // Returns a list of most visited URLs via a callback. // This may be invoked on any thread. // NOTE: the callback may be called immediately if we have the data cached. void GetMostVisitedURLs(CancelableRequestConsumer* consumer, GetTopSitesCallback* callback); // Get a thumbnail for a given page. Returns true iff we have the thumbnail. // This may be invoked on any thread. // As this method may be invoked on any thread the ref count needs to be // upped before this method returns, so this takes a scoped_refptr*. bool GetPageThumbnail(const GURL& url, scoped_refptr<RefCountedBytes>* bytes); // Get a thumbnail score for a given page. Returns true iff we have the // thumbnail score. This may be invoked on any thread. The score will // be copied to |score|. virtual bool GetPageThumbnailScore(const GURL& url, ThumbnailScore* score); // Get a temporary thumbnail score for a given page. Returns true iff we // have the thumbnail score. Useful when checking if we should update a // thumbnail for a given page. The score will be copied to |score|. bool GetTemporaryPageThumbnailScore(const GURL& url, ThumbnailScore* score); // Invoked from History if migration is needed. If this is invoked it will // be before HistoryLoaded is invoked. void MigrateFromHistory(); // Invoked with data from migrating thumbnails out of history. void FinishHistoryMigration(const ThumbnailMigration& data); // Invoked from history when it finishes loading. If MigrateFromHistory was // not invoked at this point then we load from the top sites service. void HistoryLoaded(); // Blacklisted URLs // Returns true if there is at least one item in the blacklist. bool HasBlacklistedItems() const; // Add a URL to the blacklist. void AddBlacklistedURL(const GURL& url); // Removes a URL from the blacklist. void RemoveBlacklistedURL(const GURL& url); // Returns true if the URL is blacklisted. bool IsBlacklisted(const GURL& url); // Clear the blacklist. void ClearBlacklistedURLs(); // Pinned URLs // Pin a URL at |index|. void AddPinnedURL(const GURL& url, size_t index); // Returns true if a URL is pinned. bool IsURLPinned(const GURL& url); // Unpin a URL. void RemovePinnedURL(const GURL& url); // Return a URL pinned at |index| via |out|. Returns true if there // is a URL pinned at |index|. bool GetPinnedURLAtIndex(size_t index, GURL* out); // Shuts down top sites. void Shutdown(); // Generates the diff of things that happened between "old" and "new." // // The URLs that are in "new" but not "old" will be have their index into // "new" put in |added_urls|. The URLs that are in "old" but not "new" will // have their index into "old" put into |deleted_urls|. // // URLs appearing in both old and new lists but having different indices will // have their index into "new" be put into |moved_urls|. static void DiffMostVisited(const MostVisitedURLList& old_list, const MostVisitedURLList& new_list, TopSitesDelta* delta); // Query history service for the list of available thumbnails. Returns the // handle for the request, or NULL if a request could not be made. // Public only for testing purposes. CancelableRequestProvider::Handle StartQueryForMostVisited(); bool loaded() const { return loaded_; } // Returns true if the given URL is known to the top sites service. // This function also returns false if TopSites isn't loaded yet. virtual bool IsKnownURL(const GURL& url); // Returns true if the top sites list is full (i.e. we already have the // maximum number of top sites). This function also returns false if // TopSites isn't loaded yet. virtual bool IsFull(); protected: // For allowing inheritance. virtual ~TopSites(); private: friend class base::RefCountedThreadSafe<TopSites>; friend class TopSitesTest; typedef std::pair<GURL, Images> TempImage; typedef std::list<TempImage> TempImages; // Enumeration of the possible states history can be in. enum HistoryLoadState { // We're waiting for history to finish loading. HISTORY_LOADING, // History finished loading and we need to migrate top sites out of history. HISTORY_MIGRATING, // History is loaded. HISTORY_LOADED }; // Enumeration of possible states the top sites backend can be in. enum TopSitesLoadState { // We're waiting for the backend to finish loading. TOP_SITES_LOADING, // The backend finished loading, but we may need to migrate. This is true if // the top sites db didn't exist, or if the db existed but is from an old // version. TOP_SITES_LOADED_WAITING_FOR_HISTORY, // Top sites is loaded. TOP_SITES_LOADED }; // Sets the thumbnail without writing to the database. Useful when // reading last known top sites from the DB. // Returns true if the thumbnail was set, false if the existing one is better. bool SetPageThumbnailNoDB(const GURL& url, const RefCountedBytes* thumbnail_data, const ThumbnailScore& score); // A version of SetPageThumbnail that takes RefCountedBytes as // returned by HistoryService. bool SetPageThumbnailEncoded(const GURL& url, const RefCountedBytes* thumbnail, const ThumbnailScore& score); // Encodes the bitmap to bytes for storage to the db. Returns true if the // bitmap was successfully encoded. static bool EncodeBitmap(const SkBitmap& bitmap, scoped_refptr<RefCountedBytes>* bytes); // Removes the cached thumbnail for url. Does nothing if |url| if not cached // in |temp_images_|. void RemoveTemporaryThumbnailByURL(const GURL& url); // Add a thumbnail for an unknown url. See temp_thumbnails_map_. void AddTemporaryThumbnail(const GURL& url, const RefCountedBytes* thumbnail, const ThumbnailScore& score); // Called by our timer. Starts the query for the most visited sites. void TimerFired(); // Finds the given URL in the redirect chain for the given TopSite, and // returns the distance from the destination in hops that the given URL is. // The URL is assumed to be in the list. The destination is 0. static int GetRedirectDistanceForURL(const MostVisitedURL& most_visited, const GURL& url); // Returns the set of prepopulate pages. static MostVisitedURLList GetPrepopulatePages(); // Add prepopulated pages: 'welcome to Chrome' and themes gallery to |urls|. // Returns true if any pages were added. static bool AddPrepopulatedPages(MostVisitedURLList* urls); // Convert pinned_urls_ dictionary to the new format. Use URLs as // dictionary keys. void MigratePinnedURLs(); // Takes |urls|, produces it's copy in |out| after removing // blacklisted URLs and reordering pinned URLs. void ApplyBlacklistAndPinnedURLs(const MostVisitedURLList& urls, MostVisitedURLList* out); // Converts a url into a canonical string representation. std::string GetURLString(const GURL& url); // Returns an MD5 hash of the URL. Hashing is required for blacklisted URLs. std::string GetURLHash(const GURL& url); // Returns the delay until the next update of history is needed. // Uses num_urls_changed base::TimeDelta GetUpdateDelay(); // Executes all of the callbacks in |pending_callbacks|. This is used after // we finish loading if any requests came in before we loaded. static void ProcessPendingCallbacks( const PendingCallbackSet& pending_callbacks, const MostVisitedURLList& urls); // Implementation of NotificationObserver. virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); // Resets top_sites_ and updates the db (in the background). All mutations to // top_sites_ *must* go through this. void SetTopSites(const MostVisitedURLList& new_top_sites); // Returns the number of most visted results to request from history. This // changes depending upon how many urls have been blacklisted. int num_results_to_request_from_history() const; // Invoked when transitioning to LOADED. Notifies any queued up callbacks. void MoveStateToLoaded(); void ResetThreadSafeCache(); void ResetThreadSafeImageCache(); // Stops and starts timer with a delay of |delta|. void RestartQueryForTopSitesTimer(base::TimeDelta delta); // Callback after TopSitesBackend has finished migration. This tells history // to finish it's side of migration (nuking thumbnails on disk). void OnHistoryMigrationWrittenToDisk( CancelableRequestProvider::Handle handle); // Callback from TopSites with the top sites/thumbnails. void OnGotMostVisitedThumbnails(CancelableRequestProvider::Handle handle, scoped_refptr<MostVisitedThumbnails> data, bool may_need_history_migration); // Called when history service returns a list of top URLs. void OnTopSitesAvailableFromHistory(CancelableRequestProvider::Handle handle, MostVisitedURLList data); scoped_refptr<TopSitesBackend> backend_; // The top sites data. scoped_ptr<TopSitesCache> cache_; // Copy of the top sites data that may be accessed on any thread (assuming // you hold |lock_|). The data in |thread_safe_cache_| has blacklisted and // pinned urls applied (|cache_| does not). scoped_ptr<TopSitesCache> thread_safe_cache_; Profile* profile_; // Lock used to access |thread_safe_cache_|. mutable base::Lock lock_; CancelableRequestConsumer cancelable_consumer_; // Timer that asks history for the top sites. This is used to make sure our // data stays in sync with history. base::OneShotTimer<TopSites> timer_; // The time we started |timer_| at. Only valid if |timer_| is running. base::TimeTicks timer_start_time_; NotificationRegistrar registrar_; // The number of URLs changed on the last update. size_t last_num_urls_changed_; // The map of requests for the top sites list. Can only be // non-empty at startup. After we read the top sites from the DB, we'll // always have a cached list. PendingCallbackSet pending_callbacks_; // Stores thumbnails for unknown pages. When SetPageThumbnail is // called, if we don't know about that URL yet and we don't have // enough Top Sites (new profile), we store it until the next // SetTopSites call. TempImages temp_images_; // Blacklisted and pinned URLs are stored in Preferences. // Blacklisted URLs. They are filtered out from the list of Top // Sites when GetMostVisitedURLs is called. Note that we are still // storing all URLs, but filtering on access. It is a dictionary, // key is the URL, value is a dummy value. This is owned by the // PrefService. const DictionaryValue* blacklist_; // This is a dictionary for the pinned URLs for the the most visited part of // the new tab page. Key is the URL, value is index where it is pinned at (may // be the same as key). This is owned by the PrefService. const DictionaryValue* pinned_urls_; // See description above HistoryLoadState. HistoryLoadState history_state_; // See description above TopSitesLoadState. TopSitesLoadState top_sites_state_; // Are we loaded? bool loaded_; DISALLOW_COPY_AND_ASSIGN(TopSites); }; } // namespace history #endif // CHROME_BROWSER_HISTORY_TOP_SITES_H_