// 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_