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