13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/top_sites.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <set>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/command_line.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/md5.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/values.h"
16513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/history/history_backend.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/page_usage_data.h"
19513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/history/top_sites_backend.h"
20513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/browser/history/top_sites_cache.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/scoped_user_pref_update.h"
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/webui/most_visited_handler.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/chrome_switches.h"
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/pref_names.h"
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/thumbnail_score.h"
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_controller.h"
30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/navigation_entry.h"
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/chromium_strings.h"
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/generated_resources.h"
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "grit/locale_settings.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/codec/jpeg_codec.h"
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How many top sites to store in the cache.
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const size_t kTopSitesNumber = 20;
43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Max number of temporary images we'll cache. See comment above
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// temp_images_ for details.
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const size_t kMaxTempTopImages = 8;
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic const size_t kTopSitesShown = 8;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kDaysOfHistory = 90;
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Time from startup to first HistoryService query.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int64 kUpdateIntervalSecs = 15;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Intervals between requests to HistoryService.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int64 kMinUpdateIntervalMinutes = 1;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int64 kMaxUpdateIntervalMinutes = 60;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// IDs of the sites we force into top sites.
57513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kPrepopulatePageIDs[] =
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    { IDS_CHROME_WELCOME_URL, IDS_THEMES_GALLERY_URL };
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Favicons of the sites we force into top sites.
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const char kPrepopulateFaviconURLs[][54] =
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    { "chrome://theme/IDR_NEWTAB_CHROME_WELCOME_PAGE_FAVICON",
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      "chrome://theme/IDR_NEWTAB_THEMES_GALLERY_FAVICON" };
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kPrepopulateTitleIDs[] =
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    { IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE,
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      IDS_NEW_TAB_THEMES_GALLERY_PAGE_TITLE };
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace {
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// HistoryDBTask used during migration of thumbnails from history to top sites.
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// When run on the history thread it collects the top sites and the
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// corresponding thumbnails. When run back on the ui thread it calls into
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// TopSites::FinishHistoryMigration.
75513209b27ff55e2841eac0e4120199c23acce758Ben Murdochclass LoadThumbnailsFromHistoryTask : public HistoryDBTask {
76513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch public:
77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  LoadThumbnailsFromHistoryTask(TopSites* top_sites,
78513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                int result_count)
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      : top_sites_(top_sites),
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        result_count_(result_count) {
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // l10n_util isn't thread safe, so cache for use on the db thread.
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL));
83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_THEMES_GALLERY_URL));
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual bool RunOnDBThread(history::HistoryBackend* backend,
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             history::HistoryDatabase* db) {
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Get the most visited urls.
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    backend->QueryMostVisitedURLsImpl(result_count_,
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                      kDaysOfHistory,
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                      &data_.most_visited);
92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // And fetch the thumbnails.
94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    for (size_t i = 0; i < data_.most_visited.size(); ++i) {
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      const GURL& url = data_.most_visited[i].url;
96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (ShouldFetchThumbnailFor(url)) {
97513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        scoped_refptr<RefCountedBytes> data;
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        backend->GetPageThumbnailDirectly(url, &data);
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        data_.url_to_thumbnail_map[url] = data;
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
102513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return true;
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
104513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
105513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  virtual void DoneRunOnMainThread() {
106513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    top_sites_->FinishHistoryMigration(data_);
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch private:
110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  bool ShouldFetchThumbnailFor(const GURL& url) {
111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return ignore_urls_.find(url.spec()) == ignore_urls_.end();
112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Set of URLs we don't load thumbnails for. This is created on the UI thread
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // and used on the history thread.
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::set<std::string> ignore_urls_;
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<TopSites> top_sites_;
119513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Number of results to request from history.
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const int result_count_;
122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ThumbnailMigration data_;
124513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(LoadThumbnailsFromHistoryTask);
126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch};
127513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
128513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130513209b27ff55e2841eac0e4120199c23acce758Ben MurdochTopSites::TopSites(Profile* profile)
13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    : backend_(NULL),
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      cache_(new TopSitesCache()),
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      thread_safe_cache_(new TopSitesCache()),
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      profile_(profile),
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      last_num_urls_changed_(0),
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      blacklist_(NULL),
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      pinned_urls_(NULL),
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      history_state_(HISTORY_LOADING),
139513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      top_sites_state_(TOP_SITES_LOADING),
140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      loaded_(false) {
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!profile_)
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (NotificationService::current()) {
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   Source<Profile>(profile_));
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   NotificationService::AllSources());
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We create update objects here to be sure that dictionaries are created
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // in the user preferences.
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DictionaryPrefUpdate(profile_->GetPrefs(),
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       prefs::kNTPMostVisitedURLsBlacklist).Get();
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DictionaryPrefUpdate(profile_->GetPrefs(),
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       prefs::kNTPMostVisitedPinnedURLs).Get();
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Now the dictionaries are guaranteed to exist and we can cache pointers
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to them.
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  blacklist_ =
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_->GetPrefs()->GetDictionary(prefs::kNTPMostVisitedURLsBlacklist);
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  pinned_urls_ =
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_->GetPrefs()->GetDictionary(prefs::kNTPMostVisitedPinnedURLs);
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TopSites::Init(const FilePath& db_name) {
16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Create the backend here, rather than in the constructor, so that
16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // unit tests that do not need the backend can run without a problem.
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  backend_ = new TopSitesBackend;
170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  backend_->Init(db_name);
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  backend_->GetMostVisitedThumbnails(
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      &cancelable_consumer_,
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NewCallback(this, &TopSites::OnGotMostVisitedThumbnails));
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // History may have already finished loading by the time we're created.
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  HistoryService* history = profile_->GetHistoryServiceWithoutCreating();
177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (history && history->backend_loaded()) {
178513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (history->needs_top_sites_migration())
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      MigrateFromHistory();
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    else
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      history_state_ = HISTORY_LOADED;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TopSites::SetPageThumbnail(const GURL& url,
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                const SkBitmap& thumbnail,
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                const ThumbnailScore& score) {
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!loaded_) {
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // TODO(sky): I need to cache these and apply them after the load
192513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // completes.
193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
194513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool add_temp_thumbnail = false;
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!IsKnownURL(url)) {
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!IsFull()) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      add_temp_thumbnail = true;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // This URL is not known to us.
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!HistoryService::CanAddURL(url))
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;  // It's not a real webpage.
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<RefCountedBytes> thumbnail_data;
209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!EncodeBitmap(thumbnail, &thumbnail_data))
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (add_temp_thumbnail) {
213513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Always remove the existing entry and then add it back. That way if we end
214513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // up with too many temp thumbnails we'll prune the oldest first.
215513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    RemoveTemporaryThumbnailByURL(url);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddTemporaryThumbnail(url, thumbnail_data, score);
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return SetPageThumbnailEncoded(url, thumbnail_data, score);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::GetMostVisitedURLs(CancelableRequestConsumer* consumer,
224513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                  GetTopSitesCallback* callback) {
225513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // WARNING: this may be invoked on any thread.
226513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<CancelableRequest<GetTopSitesCallback> > request(
227513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new CancelableRequest<GetTopSitesCallback>(callback));
2283f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // This ensures cancellation of requests when either the consumer or the
229513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // provider is deleted. Deletion of requests is also guaranteed.
230513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  AddRequest(request, consumer);
231513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList filtered_urls;
232513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  {
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(lock_);
234513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!loaded_) {
235513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // A request came in before we finished loading. Put the request in
236513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // pending_callbacks_ and we'll notify it when we finish loading.
237513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      pending_callbacks_.insert(request);
238513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return;
239513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
241513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    filtered_urls = thread_safe_cache_->top_sites();
242513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
243513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  request->ForwardResult(GetTopSitesCallback::TupleType(filtered_urls));
244513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::GetPageThumbnail(const GURL& url,
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                scoped_refptr<RefCountedBytes>* bytes) {
248513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // WARNING: this may be invoked on any thread.
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
250513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return thread_safe_cache_->GetPageThumbnail(url, bytes);
251513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
252513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool TopSites::GetPageThumbnailScore(const GURL& url,
25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                     ThumbnailScore* score) {
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // WARNING: this may be invoked on any thread.
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return thread_safe_cache_->GetPageThumbnailScore(url, score);
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool TopSites::GetTemporaryPageThumbnailScore(const GURL& url,
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                              ThumbnailScore* score) {
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (TempImages::iterator i = temp_images_.begin(); i != temp_images_.end();
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       ++i) {
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (i->first == url) {
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *score = i->second.thumbnail_score;
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
273513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Returns the index of |url| in |urls|, or -1 if not found.
274513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic int IndexOf(const MostVisitedURLList& urls, const GURL& url) {
275513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < urls.size(); i++) {
276513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (urls[i].url == url)
277513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return i;
278513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
279513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return -1;
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
282513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::MigrateFromHistory() {
283513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK_EQ(history_state_, HISTORY_LOADING);
285513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
286513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  history_state_ = HISTORY_MIGRATING;
287513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->ScheduleDBTask(
288513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      new LoadThumbnailsFromHistoryTask(
289513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          this,
290513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          num_results_to_request_from_history()),
291513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      &cancelable_consumer_);
292513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MigratePinnedURLs();
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::FinishHistoryMigration(const ThumbnailMigration& data) {
296513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
297513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK_EQ(history_state_, HISTORY_MIGRATING);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
299513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  history_state_ = HISTORY_LOADED;
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SetTopSites(data.most_visited);
302513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
303513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < data.most_visited.size(); ++i) {
304513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    URLToThumbnailMap::const_iterator image_i =
305513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        data.url_to_thumbnail_map.find(data.most_visited[i].url);
306513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (image_i != data.url_to_thumbnail_map.end()) {
307513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetPageThumbnailEncoded(data.most_visited[i].url,
308513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                              image_i->second,
309513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                              ThumbnailScore());
310513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MoveStateToLoaded();
314513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
315513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeImageCache();
316513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
317513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We've scheduled all the thumbnails and top sites to be written to the top
318513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // sites db, but it hasn't happened yet. Schedule a request on the db thread
319513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // that notifies us when done. When done we'll know everything was written and
320513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // we can tell history to finish its part of migration.
321513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  backend_->DoEmptyRequest(
322513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      &cancelable_consumer_,
323513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NewCallback(this, &TopSites::OnHistoryMigrationWrittenToDisk));
324513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
325513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
326513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::HistoryLoaded() {
327513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
328513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK_NE(history_state_, HISTORY_LOADED);
329513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
330513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (history_state_ != HISTORY_MIGRATING) {
331513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // No migration from history is needed.
332513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    history_state_ = HISTORY_LOADED;
333513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (top_sites_state_ == TOP_SITES_LOADED_WAITING_FOR_HISTORY) {
334513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // TopSites thought it needed migration, but it really didn't. This
335513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // typically happens the first time a profile is run with Top Sites
336513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // enabled
337513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetTopSites(MostVisitedURLList());
338513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      MoveStateToLoaded();
339513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
340513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
341513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
342513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
343513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::HasBlacklistedItems() const {
344513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return !blacklist_->empty();
345513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
346513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
347513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::AddBlacklistedURL(const GURL& url) {
348513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
349513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
350513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  RemovePinnedURL(url);
351513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Value* dummy = Value::CreateNullValue();
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedURLsBlacklist);
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* blacklist = update.Get();
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blacklist->SetWithoutPathExpansion(GetURLHash(url), dummy);
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
358513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
359513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
360513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
361513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
362513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::RemoveBlacklistedURL(const GURL& url) {
363513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedURLsBlacklist);
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* blacklist = update.Get();
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blacklist->RemoveWithoutPathExpansion(GetURLHash(url), NULL);
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
370513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
371513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
372513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
373513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::IsBlacklisted(const GURL& url) {
374513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
375513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return blacklist_->HasKey(GetURLHash(url));
376513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
377513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
378513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::ClearBlacklistedURLs() {
379513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedURLsBlacklist);
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* blacklist = update.Get();
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blacklist->Clear();
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
386513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
387513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
388513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
389513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::AddPinnedURL(const GURL& url, size_t pinned_index) {
390513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
391513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
392513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  GURL old;
393513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (GetPinnedURLAtIndex(pinned_index, &old))
394513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    RemovePinnedURL(old);
395513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
396513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (IsURLPinned(url))
397513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    RemovePinnedURL(url);
398513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
399513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Value* index = Value::CreateIntegerValue(pinned_index);
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedPinnedURLs);
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* pinned_urls = update.Get();
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pinned_urls->SetWithoutPathExpansion(GetURLString(url), index);
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
407513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
408513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
409513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
410513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
411513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::IsURLPinned(const GURL& url) {
412513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int tmp;
413513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return pinned_urls_->GetIntegerWithoutPathExpansion(GetURLString(url), &tmp);
414513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
415513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
416513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::RemovePinnedURL(const GURL& url) {
417513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
418513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedPinnedURLs);
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* pinned_urls = update.Get();
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pinned_urls->RemoveWithoutPathExpansion(GetURLString(url), NULL);
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
425513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
426513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
427513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
428513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
429513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::GetPinnedURLAtIndex(size_t index, GURL* url) {
430513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (DictionaryValue::key_iterator it = pinned_urls_->begin_keys();
431513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       it != pinned_urls_->end_keys(); ++it) {
432513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int current_index;
433513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (pinned_urls_->GetIntegerWithoutPathExpansion(*it, &current_index)) {
434513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (static_cast<size_t>(current_index) == index) {
435513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        *url = GURL(*it);
436513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        return true;
437513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
438513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
439513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
440513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
441513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
442513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
443513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::Shutdown() {
444513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  profile_ = NULL;
445513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Cancel all requests so that the service doesn't callback to us after we've
446513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // invoked Shutdown (this could happen if we have a pending request and
447513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Shutdown is invoked).
448513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  cancelable_consumer_.CancelAllRequests();
449513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  backend_->Shutdown();
450513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
451513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
452513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
453513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::DiffMostVisited(const MostVisitedURLList& old_list,
454513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                               const MostVisitedURLList& new_list,
455513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                               TopSitesDelta* delta) {
456513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Add all the old URLs for quick lookup. This maps URLs to the corresponding
457513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // index in the input.
458513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::map<GURL, size_t> all_old_urls;
459513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < old_list.size(); i++)
460513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    all_old_urls[old_list[i].url] = i;
461513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
462513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Check all the URLs in the new set to see which ones are new or just moved.
463513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // When we find a match in the old set, we'll reset its index to our special
464513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // marker. This allows us to quickly identify the deleted ones in a later
465513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // pass.
466513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const size_t kAlreadyFoundMarker = static_cast<size_t>(-1);
467513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < new_list.size(); i++) {
468513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    std::map<GURL, size_t>::iterator found = all_old_urls.find(new_list[i].url);
469513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (found == all_old_urls.end()) {
470513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      MostVisitedURLWithRank added;
471513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      added.url = new_list[i];
472513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      added.rank = i;
473513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      delta->added.push_back(added);
474513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
475513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (found->second != i) {
476513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        MostVisitedURLWithRank moved;
477513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        moved.url = new_list[i];
478513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        moved.rank = i;
479513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        delta->moved.push_back(moved);
480513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
481513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      found->second = kAlreadyFoundMarker;
482513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
483513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
484513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
485513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Any member without the special marker in the all_old_urls list means that
486513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // there wasn't a "new" URL that mapped to it, so it was deleted.
487513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (std::map<GURL, size_t>::const_iterator i = all_old_urls.begin();
488513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       i != all_old_urls.end(); ++i) {
489513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (i->second != kAlreadyFoundMarker)
490513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      delta->deleted.push_back(old_list[i->second]);
491513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
492513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
493513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
494201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochCancelableRequestProvider::Handle TopSites::StartQueryForMostVisited() {
495201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(loaded_);
496201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!profile_)
49772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return 0;
498201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
499201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
500201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // |hs| may be null during unit tests.
501201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (hs) {
502201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return hs->QueryMostVisitedURLs(
503201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        num_results_to_request_from_history(),
504201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        kDaysOfHistory,
505201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        &cancelable_consumer_,
506201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        NewCallback(this, &TopSites::OnTopSitesAvailableFromHistory));
507201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
50872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return 0;
50972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
51072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
51172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool TopSites::IsKnownURL(const GURL& url) {
51272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return loaded_ && cache_->IsKnownURL(url);
51372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
51472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
51572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool TopSites::IsFull() {
51672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return loaded_ && cache_->top_sites().size() >= kTopSitesNumber;
517201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
518201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
519513209b27ff55e2841eac0e4120199c23acce758Ben MurdochTopSites::~TopSites() {
520513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
521513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
522513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::SetPageThumbnailNoDB(const GURL& url,
523513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                    const RefCountedBytes* thumbnail_data,
524513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                    const ThumbnailScore& score) {
525513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // This should only be invoked when we know about the url.
526513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(cache_->IsKnownURL(url));
527513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
528513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const MostVisitedURL& most_visited =
529513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      cache_->top_sites()[cache_->GetURLIndex(url)];
530513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  Images* image = cache_->GetImage(url);
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // When comparing the thumbnail scores, we need to take into account the
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // redirect hops, which are not generated when the thumbnail is because the
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // redirects weren't known. We fill that in here since we know the redirects.
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ThumbnailScore new_score_with_redirects(score);
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_score_with_redirects.redirect_hops_from_dest =
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetRedirectDistanceForURL(most_visited, url);
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
539513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!ShouldReplaceThumbnailWith(image->thumbnail_score,
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  new_score_with_redirects) &&
541513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      image->thumbnail.get())
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;  // The one we already have is better.
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
544513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  image->thumbnail = const_cast<RefCountedBytes*>(thumbnail_data);
545513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  image->thumbnail_score = new_score_with_redirects;
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
547513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeImageCache();
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
551513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::SetPageThumbnailEncoded(const GURL& url,
552513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       const RefCountedBytes* thumbnail,
553513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                       const ThumbnailScore& score) {
554513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!SetPageThumbnailNoDB(url, thumbnail, score))
555513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
556513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
557513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Update the database.
558513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!cache_->IsKnownURL(url))
559513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
560513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
561513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  size_t index = cache_->GetURLIndex(url);
562513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const MostVisitedURL& most_visited = cache_->top_sites()[index];
563513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  backend_->SetPageThumbnail(most_visited,
564513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             index,
565513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             *(cache_->GetImage(most_visited.url)));
566513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return true;
567513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
568513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
569513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
570513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TopSites::EncodeBitmap(const SkBitmap& bitmap,
571513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                            scoped_refptr<RefCountedBytes>* bytes) {
572513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  *bytes = new RefCountedBytes();
573513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SkAutoLockPixels bitmap_lock(bitmap);
574513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::vector<unsigned char> data;
575513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!gfx::JPEGCodec::Encode(
576513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
577513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(),
578513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          bitmap.height(),
579513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          static_cast<int>(bitmap.rowBytes()), 90,
580513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          &data)) {
581513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
582513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
583513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // As we're going to cache this data, make sure the vector is only as big as
584513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // it needs to be.
585513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  (*bytes)->data = data;
586513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return true;
587513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
588513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
589513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::RemoveTemporaryThumbnailByURL(const GURL& url) {
590513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (TempImages::iterator i = temp_images_.begin(); i != temp_images_.end();
591513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       ++i) {
592513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (i->first == url) {
593513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      temp_images_.erase(i);
5943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return;
5953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
599513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::AddTemporaryThumbnail(const GURL& url,
600513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                     const RefCountedBytes* thumbnail,
601513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                     const ThumbnailScore& score) {
602513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (temp_images_.size() == kMaxTempTopImages)
603513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    temp_images_.erase(temp_images_.begin());
604513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
605513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TempImage image;
606513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  image.first = url;
607513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  image.second.thumbnail = const_cast<RefCountedBytes*>(thumbnail);
608513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  image.second.thumbnail_score = score;
609513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  temp_images_.push_back(image);
610513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
611513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
612201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid TopSites::TimerFired() {
613201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  StartQueryForMostVisited();
614513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
616513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
617513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint TopSites::GetRedirectDistanceForURL(const MostVisitedURL& most_visited,
618513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                        const GURL& url) {
619513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < most_visited.redirects.size(); i++) {
620513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (most_visited.redirects[i] == url)
621513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return static_cast<int>(most_visited.redirects.size() - i - 1);
622513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
623513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NOTREACHED() << "URL should always be found.";
624513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return 0;
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
627513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
628513209b27ff55e2841eac0e4120199c23acce758Ben MurdochMostVisitedURLList TopSites::GetPrepopulatePages() {
629513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList urls;
630513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  urls.resize(arraysize(kPrepopulatePageIDs));
631513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < arraysize(kPrepopulatePageIDs); ++i) {
632513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    MostVisitedURL& url = urls[i];
633513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    url.url = GURL(l10n_util::GetStringUTF8(kPrepopulatePageIDs[i]));
634513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    url.redirects.push_back(url.url);
635513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    url.favicon_url = GURL(kPrepopulateFaviconURLs[i]);
636513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    url.title = l10n_util::GetStringUTF16(kPrepopulateTitleIDs[i]);
6373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
638513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return urls;
6393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
641513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool TopSites::AddPrepopulatedPages(MostVisitedURLList* urls) {
6433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool added = false;
644513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList prepopulate_urls = GetPrepopulatePages();
645513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (size_t i = 0; i < prepopulate_urls.size(); ++i) {
646513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (urls->size() < kTopSitesNumber &&
647513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        IndexOf(*urls, prepopulate_urls[i].url) == -1) {
648513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      urls->push_back(prepopulate_urls[i]);
649513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      added = true;
650513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
6513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return added;
6533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TopSites::MigratePinnedURLs() {
656513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
657513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
6583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::map<GURL, size_t> tmp_map;
6593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (DictionaryValue::key_iterator it = pinned_urls_->begin_keys();
6603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       it != pinned_urls_->end_keys(); ++it) {
6613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    Value* value;
6623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!pinned_urls_->GetWithoutPathExpansion(*it, &value))
6633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      continue;
6643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (value->IsType(DictionaryValue::TYPE_DICTIONARY)) {
6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DictionaryValue* dict = static_cast<DictionaryValue*>(value);
6673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string url_string;
6683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      int index;
6693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (dict->GetString("url", &url_string) &&
6703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          dict->GetInteger("index", &index))
6713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        tmp_map[GURL(url_string)] = index;
6723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
6733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
676ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryPrefUpdate update(profile_->GetPrefs(),
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                prefs::kNTPMostVisitedPinnedURLs);
678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* pinned_urls = update.Get();
679ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pinned_urls->Clear();
680ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
681ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
6823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (std::map<GURL, size_t>::iterator it = tmp_map.begin();
6833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       it != tmp_map.end(); ++it)
6843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    AddPinnedURL(it->first, it->second);
6853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid TopSites::ApplyBlacklistAndPinnedURLs(const MostVisitedURLList& urls,
6883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                           MostVisitedURLList* out) {
6893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MostVisitedURLList urls_copy;
6903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (size_t i = 0; i < urls.size(); i++) {
6913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!IsBlacklisted(urls[i].url))
6923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      urls_copy.push_back(urls[i]);
6933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (size_t pinned_index = 0; pinned_index < kTopSitesShown; pinned_index++) {
6963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    GURL url;
6973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool found = GetPinnedURLAtIndex(pinned_index, &url);
6983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!found)
6993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      continue;
7003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(!url.is_empty());
7023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    int cur_index = IndexOf(urls_copy, url);
7033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    MostVisitedURL tmp;
7043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (cur_index < 0) {
7053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Pinned URL not in urls.
7063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      tmp.url = url;
7073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
7083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      tmp = urls_copy[cur_index];
7093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      urls_copy.erase(urls_copy.begin() + cur_index);
7103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
7113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (pinned_index > out->size())
7123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      out->resize(pinned_index);  // Add empty URLs as fillers.
7133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    out->insert(out->begin() + pinned_index, tmp);
7143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
7153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Add non-pinned URLs in the empty spots.
7173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  size_t current_url = 0;  // Index into the remaining URLs in urls_copy.
7183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (size_t i = 0; i < kTopSitesShown && current_url < urls_copy.size();
7193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       i++) {
7203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (i == out->size()) {
7213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      out->push_back(urls_copy[current_url]);
7223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      current_url++;
7233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (i < out->size()) {
7243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if ((*out)[i].url.is_empty()) {
7253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // Replace the filler
7263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        (*out)[i] = urls_copy[current_url];
7273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        current_url++;
7283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
7293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
7303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NOTREACHED();
7313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
7323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
7333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
7343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::string TopSites::GetURLString(const GURL& url) {
736513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return cache_->GetCanonicalURL(url).spec();
7373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
7383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::string TopSites::GetURLHash(const GURL& url) {
7403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We don't use canonical URLs here to be able to blacklist only one of
7413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the two 'duplicate' sites, e.g. 'gmail.com' and 'mail.google.com'.
7423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return MD5String(url.spec());
7433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
7443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
745513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbase::TimeDelta TopSites::GetUpdateDelay() {
746513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (cache_->top_sites().size() <= arraysize(kPrepopulateTitleIDs))
747513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return base::TimeDelta::FromSeconds(30);
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
749513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int64 range = kMaxUpdateIntervalMinutes - kMinUpdateIntervalMinutes;
750513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int64 minutes = kMaxUpdateIntervalMinutes -
751513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      last_num_urls_changed_ * range / cache_->top_sites().size();
752513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return base::TimeDelta::FromMinutes(minutes);
753513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
755513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static
756513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::ProcessPendingCallbacks(
757513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const PendingCallbackSet& pending_callbacks,
758513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const MostVisitedURLList& urls) {
759513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  PendingCallbackSet::const_iterator i;
760513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  for (i = pending_callbacks.begin();
761513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch       i != pending_callbacks.end(); ++i) {
762513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    scoped_refptr<CancelableRequest<GetTopSitesCallback> > request = *i;
763513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!request->canceled())
764513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      request->ForwardResult(GetTopSitesCallback::TupleType(urls));
765513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
766513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
7673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
768513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::Observe(NotificationType type,
769513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                       const NotificationSource& source,
770513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                       const NotificationDetails& details) {
771513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!loaded_)
772513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (type == NotificationType::HISTORY_URLS_DELETED) {
775513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    Details<history::URLsDeletedDetails> deleted_details(details);
776513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (deleted_details->all_history) {
777513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetTopSites(MostVisitedURLList());
778513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      backend_->ResetDatabase();
779513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
780513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      std::set<size_t> indices_to_delete;  // Indices into top_sites_.
781513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      for (std::set<GURL>::iterator i = deleted_details->urls.begin();
782513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           i != deleted_details->urls.end(); ++i) {
783513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        if (cache_->IsKnownURL(*i))
784513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          indices_to_delete.insert(cache_->GetURLIndex(*i));
785513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
787513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (indices_to_delete.empty())
788513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        return;
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
790513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      MostVisitedURLList new_top_sites(cache_->top_sites());
791513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      for (std::set<size_t>::reverse_iterator i = indices_to_delete.rbegin();
792513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           i != indices_to_delete.rend(); i++) {
793513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        size_t index = *i;
794513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        RemovePinnedURL(new_top_sites[index].url);
795513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        new_top_sites.erase(new_top_sites.begin() + index);
796513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      }
797513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetTopSites(new_top_sites);
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
799513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    StartQueryForMostVisited();
800513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else if (type == NotificationType::NAV_ENTRY_COMMITTED) {
80172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!IsFull()) {
802513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NavigationController::LoadCommittedDetails* load_details =
803513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          Details<NavigationController::LoadCommittedDetails>(details).ptr();
804513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (!load_details)
805513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        return;
806513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      const GURL& url = load_details->entry->url();
807513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (!cache_->IsKnownURL(url) && HistoryService::CanAddURL(url)) {
808513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // To avoid slamming history we throttle requests when the url updates.
809513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        // To do otherwise negatively impacts perf tests.
810513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        RestartQueryForTopSitesTimer(GetUpdateDelay());
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
816513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::SetTopSites(const MostVisitedURLList& new_top_sites) {
817513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
819513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList top_sites(new_top_sites);
820513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  AddPrepopulatedPages(&top_sites);
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
822513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  TopSitesDelta delta;
823513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DiffMostVisited(cache_->top_sites(), top_sites, &delta);
824513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty())
825513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    backend_->UpdateTopSites(delta);
8263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
827513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  last_num_urls_changed_ = delta.added.size() + delta.moved.size();
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
829513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // We always do the following steps (setting top sites in cache, and resetting
830513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // thread safe cache ...) as this method is invoked during startup at which
831513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // point the caches haven't been updated yet.
832513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  cache_->SetTopSites(top_sites);
8333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
834513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // See if we have any tmp thumbnails for the new sites.
835513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!temp_images_.empty()) {
836513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    for (size_t i = 0; i < top_sites.size(); ++i) {
837513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      const MostVisitedURL& mv = top_sites[i];
838513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      GURL canonical_url = cache_->GetCanonicalURL(mv.url);
839513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // At the time we get the thumbnail redirects aren't known, so we have to
840513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // iterate through all the images.
841513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      for (TempImages::iterator it = temp_images_.begin();
842513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           it != temp_images_.end(); ++it) {
843513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        if (canonical_url == cache_->GetCanonicalURL(it->first)) {
844513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          SetPageThumbnailEncoded(mv.url,
845513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                  it->second.thumbnail,
8463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  it->second.thumbnail_score);
847513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          temp_images_.erase(it);
8483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          break;
8493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
852513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
8533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
854513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (top_sites.size() >= kTopSitesNumber)
855513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    temp_images_.clear();
8563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
857513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeCache();
858513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ResetThreadSafeImageCache();
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
860513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Restart the timer that queries history for top sites. This is done to
861513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // ensure we stay in sync with history.
862513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  RestartQueryForTopSitesTimer(GetUpdateDelay());
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
865513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint TopSites::num_results_to_request_from_history() const {
866513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
868513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return kTopSitesNumber + blacklist_->size();
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
871513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::MoveStateToLoaded() {
872513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
874513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList filtered_urls;
875513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  PendingCallbackSet pending_callbacks;
876513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  {
87772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(lock_);
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
879513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (loaded_)
880513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return;  // Don't do anything if we're already loaded.
881513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    loaded_ = true;
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
883513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Now that we're loaded we can service the queued up callbacks. Copy them
884513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // here and service them outside the lock.
885513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!pending_callbacks_.empty()) {
886513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      filtered_urls = thread_safe_cache_->top_sites();
887513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      pending_callbacks.swap(pending_callbacks_);
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
891513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ProcessPendingCallbacks(pending_callbacks, filtered_urls);
8923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
893513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  NotificationService::current()->Notify(NotificationType::TOP_SITES_LOADED,
894513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                         Source<Profile>(profile_),
895513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                         Details<TopSites>(this));
8963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
8973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
898513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::ResetThreadSafeCache() {
89972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
900513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  MostVisitedURLList cached;
901513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  ApplyBlacklistAndPinnedURLs(cache_->top_sites(), &cached);
902513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  thread_safe_cache_->SetTopSites(cached);
9033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
9043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
905513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::ResetThreadSafeImageCache() {
90672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(lock_);
907513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  thread_safe_cache_->SetThumbnails(cache_->images());
908513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  thread_safe_cache_->RemoveUnreferencedThumbnails();
9093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
9103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
911513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::RestartQueryForTopSitesTimer(base::TimeDelta delta) {
912513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (timer_.IsRunning() && ((timer_start_time_ + timer_.GetCurrentDelay()) <
913513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                             (base::TimeTicks::Now() + delta))) {
914513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return;
9153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
9163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
917513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  timer_start_time_ = base::TimeTicks::Now();
918513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  timer_.Stop();
919201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  timer_.Start(delta, this, &TopSites::TimerFired);
9203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
9213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
922513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::OnHistoryMigrationWrittenToDisk(TopSitesBackend::Handle handle) {
923513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
9243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
925513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!profile_)
9263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
928513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  HistoryService* history =
929513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
930513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (history)
931513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    history->OnTopSitesReady();
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
934513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::OnGotMostVisitedThumbnails(
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CancelableRequestProvider::Handle handle,
936513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    scoped_refptr<MostVisitedThumbnails> data,
937513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    bool may_need_history_migration) {
938513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
939513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK_EQ(top_sites_state_, TOP_SITES_LOADING);
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
941513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!may_need_history_migration) {
942513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    top_sites_state_ = TOP_SITES_LOADED;
9433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
944513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Set the top sites directly in the cache so that SetTopSites diffs
945513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // correctly.
946513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    cache_->SetTopSites(data->most_visited);
947513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    SetTopSites(data->most_visited);
948513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    cache_->SetThumbnails(data->url_to_images_map);
9493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
950513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    ResetThreadSafeImageCache();
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
952513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    MoveStateToLoaded();
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
954513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // Start a timer that refreshes top sites from history.
955513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    RestartQueryForTopSitesTimer(
956513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        base::TimeDelta::FromSeconds(kUpdateIntervalSecs));
957513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else {
958513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // The top sites file didn't exist or is the wrong version. We need to wait
959513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // for history to finish loading to know if we really needed to migrate.
960513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (history_state_ == HISTORY_LOADED) {
961513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      top_sites_state_ = TOP_SITES_LOADED;
962513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetTopSites(MostVisitedURLList());
963513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      MoveStateToLoaded();
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
965513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      top_sites_state_ = TOP_SITES_LOADED_WAITING_FOR_HISTORY;
966513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Ask for history just in case it hasn't been loaded yet. When history
967513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // finishes loading we'll do migration and/or move to loaded.
968513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
973513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid TopSites::OnTopSitesAvailableFromHistory(
974513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    CancelableRequestProvider::Handle handle,
975513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    MostVisitedURLList pages) {
976513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  SetTopSites(pages);
977201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
978201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Used only in testing.
979201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  NotificationService::current()->Notify(
980201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      NotificationType::TOP_SITES_UPDATED,
981201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      Source<TopSites>(this),
982201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      Details<CancelableRequestProvider::Handle>(&handle));
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace history
986