1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_HISTORY_TOP_SITES_H_
6#define CHROME_BROWSER_HISTORY_TOP_SITES_H_
7#pragma once
8
9#include <list>
10#include <set>
11#include <string>
12#include <utility>
13
14#include "base/basictypes.h"
15#include "base/gtest_prod_util.h"
16#include "base/memory/ref_counted.h"
17#include "base/memory/ref_counted_memory.h"
18#include "base/synchronization/lock.h"
19#include "base/time.h"
20#include "base/timer.h"
21#include "chrome/browser/history/history_types.h"
22#include "chrome/browser/history/history.h"
23#include "chrome/browser/history/page_usage_data.h"
24#include "chrome/common/thumbnail_score.h"
25#include "content/browser/cancelable_request.h"
26#include "googleurl/src/gurl.h"
27
28class DictionaryValue;
29class FilePath;
30class SkBitmap;
31class Profile;
32
33namespace history {
34
35class TopSitesCache;
36class TopSitesBackend;
37class TopSitesTest;
38
39// Stores the data for the top "most visited" sites. This includes a cache of
40// the most visited data from history, as well as the corresponding thumbnails
41// of those sites.
42//
43// This class allows requests for most visited urls and thumbnails on any
44// thread. All other methods must be invoked on the UI thread. All mutations
45// to internal state happen on the UI thread and are scheduled to update the
46// db using TopSitesBackend.
47class TopSites
48    : public base::RefCountedThreadSafe<TopSites>,
49      public NotificationObserver,
50      public CancelableRequestProvider {
51 public:
52  explicit TopSites(Profile* profile);
53
54  // Initializes TopSites.
55  void Init(const FilePath& db_name);
56
57  // Sets the given thumbnail for the given URL. Returns true if the thumbnail
58  // was updated. False means either the URL wasn't known to us, or we felt
59  // that our current thumbnail was superior to the given one.
60  bool SetPageThumbnail(const GURL& url,
61                        const SkBitmap& thumbnail,
62                        const ThumbnailScore& score);
63
64  // Callback for GetMostVisitedURLs.
65  typedef Callback1<const MostVisitedURLList&>::Type GetTopSitesCallback;
66  typedef std::set<scoped_refptr<CancelableRequest<GetTopSitesCallback> > >
67      PendingCallbackSet;
68
69  // Returns a list of most visited URLs via a callback.
70  // This may be invoked on any thread.
71  // NOTE: the callback may be called immediately if we have the data cached.
72  void GetMostVisitedURLs(CancelableRequestConsumer* consumer,
73                          GetTopSitesCallback* callback);
74
75  // Get a thumbnail for a given page. Returns true iff we have the thumbnail.
76  // This may be invoked on any thread.
77  // As this method may be invoked on any thread the ref count needs to be
78  // upped before this method returns, so this takes a scoped_refptr*.
79  bool GetPageThumbnail(const GURL& url,
80                        scoped_refptr<RefCountedBytes>* bytes);
81
82  // Get a thumbnail score for a given page. Returns true iff we have the
83  // thumbnail score.  This may be invoked on any thread. The score will
84  // be copied to |score|.
85  virtual bool GetPageThumbnailScore(const GURL& url, ThumbnailScore* score);
86
87  // Get a temporary thumbnail score for a given page. Returns true iff we
88  // have the thumbnail score. Useful when checking if we should update a
89  // thumbnail for a given page. The score will be copied to |score|.
90  bool GetTemporaryPageThumbnailScore(const GURL& url, ThumbnailScore* score);
91
92  // Invoked from History if migration is needed. If this is invoked it will
93  // be before HistoryLoaded is invoked.
94  void MigrateFromHistory();
95
96  // Invoked with data from migrating thumbnails out of history.
97  void FinishHistoryMigration(const ThumbnailMigration& data);
98
99  // Invoked from history when it finishes loading. If MigrateFromHistory was
100  // not invoked at this point then we load from the top sites service.
101  void HistoryLoaded();
102
103  // Blacklisted URLs
104
105  // Returns true if there is at least one item in the blacklist.
106  bool HasBlacklistedItems() const;
107
108  // Add a  URL to the blacklist.
109  void AddBlacklistedURL(const GURL& url);
110
111  // Removes a URL from the blacklist.
112  void RemoveBlacklistedURL(const GURL& url);
113
114  // Returns true if the URL is blacklisted.
115  bool IsBlacklisted(const GURL& url);
116
117  // Clear the blacklist.
118  void ClearBlacklistedURLs();
119
120  // Pinned URLs
121
122  // Pin a URL at |index|.
123  void AddPinnedURL(const GURL& url, size_t index);
124
125  // Returns true if a URL is pinned.
126  bool IsURLPinned(const GURL& url);
127
128  // Unpin a URL.
129  void RemovePinnedURL(const GURL& url);
130
131  // Return a URL pinned at |index| via |out|. Returns true if there
132  // is a URL pinned at |index|.
133  bool GetPinnedURLAtIndex(size_t index, GURL* out);
134
135  // Shuts down top sites.
136  void Shutdown();
137
138  // Generates the diff of things that happened between "old" and "new."
139  //
140  // The URLs that are in "new" but not "old" will be have their index into
141  // "new" put in |added_urls|. The URLs that are in "old" but not "new" will
142  // have their index into "old" put into |deleted_urls|.
143  //
144  // URLs appearing in both old and new lists but having different indices will
145  // have their index into "new" be put into |moved_urls|.
146  static void DiffMostVisited(const MostVisitedURLList& old_list,
147                              const MostVisitedURLList& new_list,
148                              TopSitesDelta* delta);
149
150  // Query history service for the list of available thumbnails. Returns the
151  // handle for the request, or NULL if a request could not be made.
152  // Public only for testing purposes.
153  CancelableRequestProvider::Handle StartQueryForMostVisited();
154
155  bool loaded() const { return loaded_; }
156
157  // Returns true if the given URL is known to the top sites service.
158  // This function also returns false if TopSites isn't loaded yet.
159  virtual bool IsKnownURL(const GURL& url);
160
161  // Returns true if the top sites list is full (i.e. we already have the
162  // maximum number of top sites).  This function also returns false if
163  // TopSites isn't loaded yet.
164  virtual bool IsFull();
165
166 protected:
167  // For allowing inheritance.
168  virtual ~TopSites();
169
170 private:
171  friend class base::RefCountedThreadSafe<TopSites>;
172  friend class TopSitesTest;
173
174  typedef std::pair<GURL, Images> TempImage;
175  typedef std::list<TempImage> TempImages;
176
177  // Enumeration of the possible states history can be in.
178  enum HistoryLoadState {
179    // We're waiting for history to finish loading.
180    HISTORY_LOADING,
181
182    // History finished loading and we need to migrate top sites out of history.
183    HISTORY_MIGRATING,
184
185    // History is loaded.
186    HISTORY_LOADED
187  };
188
189  // Enumeration of possible states the top sites backend can be in.
190  enum TopSitesLoadState {
191    // We're waiting for the backend to finish loading.
192    TOP_SITES_LOADING,
193
194    // The backend finished loading, but we may need to migrate. This is true if
195    // the top sites db didn't exist, or if the db existed but is from an old
196    // version.
197    TOP_SITES_LOADED_WAITING_FOR_HISTORY,
198
199    // Top sites is loaded.
200    TOP_SITES_LOADED
201  };
202
203  // Sets the thumbnail without writing to the database. Useful when
204  // reading last known top sites from the DB.
205  // Returns true if the thumbnail was set, false if the existing one is better.
206  bool SetPageThumbnailNoDB(const GURL& url,
207                            const RefCountedBytes* thumbnail_data,
208                            const ThumbnailScore& score);
209
210  // A version of SetPageThumbnail that takes RefCountedBytes as
211  // returned by HistoryService.
212  bool SetPageThumbnailEncoded(const GURL& url,
213                               const RefCountedBytes* thumbnail,
214                               const ThumbnailScore& score);
215
216  // Encodes the bitmap to bytes for storage to the db. Returns true if the
217  // bitmap was successfully encoded.
218  static bool EncodeBitmap(const SkBitmap& bitmap,
219                           scoped_refptr<RefCountedBytes>* bytes);
220
221  // Removes the cached thumbnail for url. Does nothing if |url| if not cached
222  // in |temp_images_|.
223  void RemoveTemporaryThumbnailByURL(const GURL& url);
224
225  // Add a thumbnail for an unknown url. See temp_thumbnails_map_.
226  void AddTemporaryThumbnail(const GURL& url,
227                             const RefCountedBytes* thumbnail,
228                             const ThumbnailScore& score);
229
230  // Called by our timer. Starts the query for the most visited sites.
231  void TimerFired();
232
233  // Finds the given URL in the redirect chain for the given TopSite, and
234  // returns the distance from the destination in hops that the given URL is.
235  // The URL is assumed to be in the list. The destination is 0.
236  static int GetRedirectDistanceForURL(const MostVisitedURL& most_visited,
237                                       const GURL& url);
238
239  // Returns the set of prepopulate pages.
240  static MostVisitedURLList GetPrepopulatePages();
241
242  // Add prepopulated pages: 'welcome to Chrome' and themes gallery to |urls|.
243  // Returns true if any pages were added.
244  static bool AddPrepopulatedPages(MostVisitedURLList* urls);
245
246  // Convert pinned_urls_ dictionary to the new format. Use URLs as
247  // dictionary keys.
248  void MigratePinnedURLs();
249
250  // Takes |urls|, produces it's copy in |out| after removing
251  // blacklisted URLs and reordering pinned URLs.
252  void ApplyBlacklistAndPinnedURLs(const MostVisitedURLList& urls,
253                                   MostVisitedURLList* out);
254
255  // Converts a url into a canonical string representation.
256  std::string GetURLString(const GURL& url);
257
258  // Returns an MD5 hash of the URL. Hashing is required for blacklisted URLs.
259  std::string GetURLHash(const GURL& url);
260
261  // Returns the delay until the next update of history is needed.
262  // Uses num_urls_changed
263  base::TimeDelta GetUpdateDelay();
264
265  // Executes all of the callbacks in |pending_callbacks|. This is used after
266  // we finish loading if any requests came in before we loaded.
267  static void ProcessPendingCallbacks(
268      const PendingCallbackSet& pending_callbacks,
269      const MostVisitedURLList& urls);
270
271  // Implementation of NotificationObserver.
272  virtual void Observe(NotificationType type,
273                       const NotificationSource& source,
274                       const NotificationDetails& details);
275
276  // Resets top_sites_ and updates the db (in the background). All mutations to
277  // top_sites_ *must* go through this.
278  void SetTopSites(const MostVisitedURLList& new_top_sites);
279
280  // Returns the number of most visted results to request from history. This
281  // changes depending upon how many urls have been blacklisted.
282  int num_results_to_request_from_history() const;
283
284  // Invoked when transitioning to LOADED. Notifies any queued up callbacks.
285  void MoveStateToLoaded();
286
287  void ResetThreadSafeCache();
288
289  void ResetThreadSafeImageCache();
290
291  // Stops and starts timer with a delay of |delta|.
292  void RestartQueryForTopSitesTimer(base::TimeDelta delta);
293
294  // Callback after TopSitesBackend has finished migration. This tells history
295  // to finish it's side of migration (nuking thumbnails on disk).
296  void OnHistoryMigrationWrittenToDisk(
297      CancelableRequestProvider::Handle handle);
298
299  // Callback from TopSites with the top sites/thumbnails.
300  void OnGotMostVisitedThumbnails(CancelableRequestProvider::Handle handle,
301                                  scoped_refptr<MostVisitedThumbnails> data,
302                                  bool may_need_history_migration);
303
304  // Called when history service returns a list of top URLs.
305  void OnTopSitesAvailableFromHistory(CancelableRequestProvider::Handle handle,
306                                      MostVisitedURLList data);
307
308  scoped_refptr<TopSitesBackend> backend_;
309
310  // The top sites data.
311  scoped_ptr<TopSitesCache> cache_;
312
313  // Copy of the top sites data that may be accessed on any thread (assuming
314  // you hold |lock_|). The data in |thread_safe_cache_| has blacklisted and
315  // pinned urls applied (|cache_| does not).
316  scoped_ptr<TopSitesCache> thread_safe_cache_;
317
318  Profile* profile_;
319
320  // Lock used to access |thread_safe_cache_|.
321  mutable base::Lock lock_;
322
323  CancelableRequestConsumer cancelable_consumer_;
324
325  // Timer that asks history for the top sites. This is used to make sure our
326  // data stays in sync with history.
327  base::OneShotTimer<TopSites> timer_;
328
329  // The time we started |timer_| at. Only valid if |timer_| is running.
330  base::TimeTicks timer_start_time_;
331
332  NotificationRegistrar registrar_;
333
334  // The number of URLs changed on the last update.
335  size_t last_num_urls_changed_;
336
337  // The map of requests for the top sites list. Can only be
338  // non-empty at startup. After we read the top sites from the DB, we'll
339  // always have a cached list.
340  PendingCallbackSet pending_callbacks_;
341
342  // Stores thumbnails for unknown pages. When SetPageThumbnail is
343  // called, if we don't know about that URL yet and we don't have
344  // enough Top Sites (new profile), we store it until the next
345  // SetTopSites call.
346  TempImages temp_images_;
347
348  // Blacklisted and pinned URLs are stored in Preferences.
349
350  // Blacklisted URLs. They are filtered out from the list of Top
351  // Sites when GetMostVisitedURLs is called. Note that we are still
352  // storing all URLs, but filtering on access. It is a dictionary,
353  // key is the URL, value is a dummy value. This is owned by the
354  // PrefService.
355  const DictionaryValue* blacklist_;
356
357  // This is a dictionary for the pinned URLs for the the most visited part of
358  // the new tab page. Key is the URL, value is index where it is pinned at (may
359  // be the same as key). This is owned by the PrefService.
360  const DictionaryValue* pinned_urls_;
361
362  // See description above HistoryLoadState.
363  HistoryLoadState history_state_;
364
365  // See description above TopSitesLoadState.
366  TopSitesLoadState top_sites_state_;
367
368  // Are we loaded?
369  bool loaded_;
370
371  DISALLOW_COPY_AND_ASSIGN(TopSites);
372};
373
374}  // namespace history
375
376#endif  // CHROME_BROWSER_HISTORY_TOP_SITES_H_
377