1 // Copyright (c) 2013 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_IMPL_H_ 6 #define CHROME_BROWSER_HISTORY_TOP_SITES_IMPL_H_ 7 8 #include <list> 9 #include <set> 10 #include <string> 11 #include <utility> 12 #include <vector> 13 14 #include "base/basictypes.h" 15 #include "base/callback.h" 16 #include "base/gtest_prod_util.h" 17 #include "base/memory/ref_counted.h" 18 #include "base/synchronization/lock.h" 19 #include "base/time/time.h" 20 #include "base/timer/timer.h" 21 #include "chrome/browser/common/cancelable_request.h" 22 #include "chrome/browser/history/history_service.h" 23 #include "chrome/browser/history/history_types.h" 24 #include "chrome/browser/history/page_usage_data.h" 25 #include "chrome/browser/history/top_sites.h" 26 #include "chrome/browser/history/top_sites_backend.h" 27 #include "chrome/common/cancelable_task_tracker.h" 28 #include "chrome/common/thumbnail_score.h" 29 #include "third_party/skia/include/core/SkColor.h" 30 #include "ui/gfx/image/image.h" 31 #include "url/gurl.h" 32 33 class Profile; 34 35 namespace base { 36 class FilePath; 37 class RefCountedBytes; 38 class RefCountedMemory; 39 } 40 41 namespace history { 42 43 class TopSitesCache; 44 class TopSitesImplTest; 45 46 // This class allows requests for most visited urls and thumbnails on any 47 // thread. All other methods must be invoked on the UI thread. All mutations 48 // to internal state happen on the UI thread and are scheduled to update the 49 // db using TopSitesBackend. 50 class TopSitesImpl : public TopSites { 51 public: 52 explicit TopSitesImpl(Profile* profile); 53 54 // Initializes TopSitesImpl. 55 void Init(const base::FilePath& db_name); 56 57 virtual bool SetPageThumbnail(const GURL& url, 58 const gfx::Image& thumbnail, 59 const ThumbnailScore& score) OVERRIDE; 60 virtual bool SetPageThumbnailToJPEGBytes( 61 const GURL& url, 62 const base::RefCountedMemory* memory, 63 const ThumbnailScore& score) OVERRIDE; 64 virtual void GetMostVisitedURLs( 65 const GetMostVisitedURLsCallback& callback, 66 bool include_forced_urls) OVERRIDE; 67 virtual bool GetPageThumbnail( 68 const GURL& url, 69 bool prefix_match, 70 scoped_refptr<base::RefCountedMemory>* bytes) OVERRIDE; 71 virtual bool GetPageThumbnailScore(const GURL& url, 72 ThumbnailScore* score) OVERRIDE; 73 virtual bool GetTemporaryPageThumbnailScore(const GURL& url, 74 ThumbnailScore* score) OVERRIDE; 75 virtual void SyncWithHistory() OVERRIDE; 76 virtual bool HasBlacklistedItems() const OVERRIDE; 77 virtual void AddBlacklistedURL(const GURL& url) OVERRIDE; 78 virtual void RemoveBlacklistedURL(const GURL& url) OVERRIDE; 79 virtual bool IsBlacklisted(const GURL& url) OVERRIDE; 80 virtual void ClearBlacklistedURLs() OVERRIDE; 81 virtual void Shutdown() OVERRIDE; 82 virtual CancelableRequestProvider::Handle StartQueryForMostVisited() OVERRIDE; 83 virtual bool IsKnownURL(const GURL& url) OVERRIDE; 84 virtual const std::string& GetCanonicalURLString( 85 const GURL& url) const OVERRIDE; 86 virtual bool IsNonForcedFull() OVERRIDE; 87 virtual bool IsForcedFull() OVERRIDE; 88 virtual MostVisitedURLList GetPrepopulatePages() OVERRIDE; 89 virtual bool loaded() const OVERRIDE; 90 virtual bool AddForcedURL(const GURL& url, const base::Time& time) OVERRIDE; 91 92 protected: 93 virtual ~TopSitesImpl(); 94 95 private: 96 friend class TopSitesImplTest; 97 FRIEND_TEST_ALL_PREFIXES(TopSitesImplTest, DiffMostVisited); 98 FRIEND_TEST_ALL_PREFIXES(TopSitesImplTest, DiffMostVisitedWithForced); 99 100 typedef base::Callback<void(const MostVisitedURLList&, 101 const MostVisitedURLList&)> PendingCallback; 102 103 typedef std::pair<GURL, Images> TempImage; 104 typedef std::list<TempImage> TempImages; 105 typedef std::vector<PendingCallback> PendingCallbacks; 106 107 // Generates the diff of things that happened between "old" and "new." 108 // 109 // This treats forced URLs separately than non-forced URLs. 110 // 111 // The URLs that are in "new" but not "old" will be have their index into 112 // "new" put in |added_urls|. The non-forced URLs that are in "old" but not 113 // "new" will have their index into "old" put into |deleted_urls|. 114 // 115 // URLs appearing in both old and new lists but having different indices will 116 // have their index into "new" be put into |moved_urls|. 117 static void DiffMostVisited(const MostVisitedURLList& old_list, 118 const MostVisitedURLList& new_list, 119 TopSitesDelta* delta); 120 121 // Sets the thumbnail without writing to the database. Useful when 122 // reading last known top sites from the DB. 123 // Returns true if the thumbnail was set, false if the existing one is better. 124 bool SetPageThumbnailNoDB(const GURL& url, 125 const base::RefCountedMemory* thumbnail_data, 126 const ThumbnailScore& score); 127 128 // A version of SetPageThumbnail that takes RefCountedBytes as 129 // returned by HistoryService. 130 bool SetPageThumbnailEncoded(const GURL& url, 131 const base::RefCountedMemory* thumbnail, 132 const ThumbnailScore& score); 133 134 // Encodes the bitmap to bytes for storage to the db. Returns true if the 135 // bitmap was successfully encoded. 136 static bool EncodeBitmap(const gfx::Image& bitmap, 137 scoped_refptr<base::RefCountedBytes>* bytes); 138 139 // Removes the cached thumbnail for url. Does nothing if |url| if not cached 140 // in |temp_images_|. 141 void RemoveTemporaryThumbnailByURL(const GURL& url); 142 143 // Add a thumbnail for an unknown url. See temp_thumbnails_map_. 144 void AddTemporaryThumbnail(const GURL& url, 145 const base::RefCountedMemory* thumbnail, 146 const ThumbnailScore& score); 147 148 // Called by our timer. Starts the query for the most visited sites. 149 void TimerFired(); 150 151 // Finds the given URL in the redirect chain for the given TopSite, and 152 // returns the distance from the destination in hops that the given URL is. 153 // The URL is assumed to be in the list. The destination is 0. 154 static int GetRedirectDistanceForURL(const MostVisitedURL& most_visited, 155 const GURL& url); 156 157 // Add prepopulated pages: 'welcome to Chrome' and themes gallery to |urls|. 158 // Returns true if any pages were added. 159 bool AddPrepopulatedPages(MostVisitedURLList* urls, 160 size_t num_forced_urls); 161 162 // Add all the forced URLs from |cache_| into |new_list|, making sure not to 163 // add any URL that's already in |new_list|'s non-forced URLs. The forced URLs 164 // in |cache_| and |new_list| are assumed to appear at the front of the list 165 // and be sorted in increasing |last_forced_time|. This will still be true 166 // after the call. If the list of forced URLs overflows the older ones are 167 // dropped. Returns the number of forced URLs after the merge. 168 size_t MergeCachedForcedURLs(MostVisitedURLList* new_list); 169 170 // Takes |urls|, produces it's copy in |out| after removing blacklisted URLs. 171 // Also ensures we respect the maximum number of forced URLs and non-forced 172 // URLs. 173 void ApplyBlacklist(const MostVisitedURLList& urls, MostVisitedURLList* out); 174 175 // Returns an MD5 hash of the URL. Hashing is required for blacklisted URLs. 176 std::string GetURLHash(const GURL& url); 177 178 // Returns the delay until the next update of history is needed. 179 // Uses num_urls_changed 180 base::TimeDelta GetUpdateDelay(); 181 182 // Implementation of content::NotificationObserver. 183 virtual void Observe(int type, 184 const content::NotificationSource& source, 185 const content::NotificationDetails& details) OVERRIDE; 186 187 // Updates URLs in |cache_| and the db (in the background). 188 // The non-forced URLs in |new_top_sites| replace those in |cache_|. 189 // The forced URLs of |new_top_sites| are merged with those in |cache_|, 190 // if the list of forced URLs overflows, the oldest ones are dropped. 191 // All mutations to cache_ *must* go through this. Should 192 // be called from the UI thread. 193 void SetTopSites(const MostVisitedURLList& new_top_sites); 194 195 // Returns the number of most visited results to request from history. This 196 // changes depending upon how many urls have been blacklisted. Should be 197 // called from the UI thread. 198 int num_results_to_request_from_history() const; 199 200 // Invoked when transitioning to LOADED. Notifies any queued up callbacks. 201 // Should be called from the UI thread. 202 void MoveStateToLoaded(); 203 204 void ResetThreadSafeCache(); 205 206 void ResetThreadSafeImageCache(); 207 208 void NotifyTopSitesChanged(); 209 210 // Stops and starts timer with a delay of |delta|. 211 void RestartQueryForTopSitesTimer(base::TimeDelta delta); 212 213 // Callback from TopSites with the top sites/thumbnails. Should be called 214 // from the UI thread. 215 void OnGotMostVisitedThumbnails( 216 const scoped_refptr<MostVisitedThumbnails>& thumbnails); 217 218 // Called when history service returns a list of top URLs. 219 void OnTopSitesAvailableFromHistory(CancelableRequestProvider::Handle handle, 220 MostVisitedURLList data); 221 222 scoped_refptr<TopSitesBackend> backend_; 223 224 // The top sites data. 225 scoped_ptr<TopSitesCache> cache_; 226 227 // Copy of the top sites data that may be accessed on any thread (assuming 228 // you hold |lock_|). The data in |thread_safe_cache_| has blacklisted and 229 // pinned urls applied (|cache_| does not). 230 scoped_ptr<TopSitesCache> thread_safe_cache_; 231 232 Profile* profile_; 233 234 // Lock used to access |thread_safe_cache_|. 235 mutable base::Lock lock_; 236 237 // Need a separate consumer for each CancelableRequestProvider we interact 238 // with (HistoryService and TopSitesBackend). 239 CancelableRequestConsumer history_consumer_; 240 CancelableTaskTracker cancelable_task_tracker_; 241 242 // Timer that asks history for the top sites. This is used to make sure our 243 // data stays in sync with history. 244 base::OneShotTimer<TopSitesImpl> timer_; 245 246 // The time we started |timer_| at. Only valid if |timer_| is running. 247 base::TimeTicks timer_start_time_; 248 249 content::NotificationRegistrar registrar_; 250 251 // The number of URLs changed on the last update. 252 size_t last_num_urls_changed_; 253 254 // The pending requests for the top sites list. Can only be non-empty at 255 // startup. After we read the top sites from the DB, we'll always have a 256 // cached list and be able to run callbacks immediately. 257 PendingCallbacks pending_callbacks_; 258 259 // Stores thumbnails for unknown pages. When SetPageThumbnail is 260 // called, if we don't know about that URL yet and we don't have 261 // enough Top Sites (new profile), we store it until the next 262 // SetNonForcedTopSites call. 263 TempImages temp_images_; 264 265 // URL List of prepopulated page. 266 std::vector<GURL> prepopulated_page_urls_; 267 268 // Are we loaded? 269 bool loaded_; 270 271 DISALLOW_COPY_AND_ASSIGN(TopSitesImpl); 272 }; 273 274 } // namespace history 275 276 #endif // CHROME_BROWSER_HISTORY_TOP_SITES_IMPL_H_ 277