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_SYNC_GLUE_FAVICON_CACHE_H_ 6 #define CHROME_BROWSER_SYNC_GLUE_FAVICON_CACHE_H_ 7 8 #include <map> 9 #include <string> 10 11 #include "base/basictypes.h" 12 #include "base/compiler_specific.h" 13 #include "base/memory/linked_ptr.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/memory/ref_counted_memory.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/task/cancelable_task_tracker.h" 19 #include "chrome/browser/history/history_types.h" 20 #include "chrome/browser/sessions/session_id.h" 21 #include "content/public/browser/notification_observer.h" 22 #include "content/public/browser/notification_registrar.h" 23 #include "sync/api/sync_change.h" 24 #include "sync/api/sync_error_factory.h" 25 #include "sync/api/syncable_service.h" 26 #include "url/gurl.h" 27 28 class Profile; 29 30 namespace chrome { 31 struct FaviconRawBitmapResult; 32 } 33 34 namespace browser_sync { 35 36 enum IconSize { 37 SIZE_INVALID, 38 SIZE_16, 39 SIZE_32, 40 SIZE_64, 41 NUM_SIZES 42 }; 43 44 struct SyncedFaviconInfo; 45 46 // Encapsulates the logic for loading and storing synced favicons. 47 // TODO(zea): make this a KeyedService. 48 class FaviconCache : public syncer::SyncableService, 49 public content::NotificationObserver { 50 public: 51 FaviconCache(Profile* profile, int max_sync_favicon_limit); 52 virtual ~FaviconCache(); 53 54 // SyncableService implementation. 55 virtual syncer::SyncMergeResult MergeDataAndStartSyncing( 56 syncer::ModelType type, 57 const syncer::SyncDataList& initial_sync_data, 58 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 59 scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE; 60 virtual void StopSyncing(syncer::ModelType type) OVERRIDE; 61 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) 62 const OVERRIDE; 63 virtual syncer::SyncError ProcessSyncChanges( 64 const tracked_objects::Location& from_here, 65 const syncer::SyncChangeList& change_list) OVERRIDE; 66 67 // If a valid favicon for the icon at |favicon_url| is found, fills 68 // |favicon_png| with the png-encoded image and returns true. Else, returns 69 // false. 70 bool GetSyncedFaviconForFaviconURL( 71 const GURL& favicon_url, 72 scoped_refptr<base::RefCountedMemory>* favicon_png) const; 73 74 // If a valid favicon for the icon associated with |page_url| is found, fills 75 // |favicon_png| with the png-encoded image and returns true. Else, returns 76 // false. 77 bool GetSyncedFaviconForPageURL( 78 const GURL& page_url, 79 scoped_refptr<base::RefCountedMemory>* favicon_png) const; 80 81 // Load the favicon for |page_url|. Will create a new sync node or update 82 // an existing one as necessary, and set the last visit time to the current 83 // time. Only those favicon types defined in SupportedFaviconTypes will be 84 // synced. 85 void OnPageFaviconUpdated(const GURL& page_url); 86 87 // Update the visit count for the favicon associated with |favicon_url|. 88 // If no favicon exists associated with |favicon_url|, triggers a load 89 // for the favicon associated with |page_url|. 90 void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url); 91 92 // Consume Session sync favicon data. Will not overwrite existing favicons. 93 // If |icon_bytes| is empty, only updates the page->favicon url mapping. 94 // Safe to call within a transaction. 95 void OnReceivedSyncFavicon(const GURL& page_url, 96 const GURL& icon_url, 97 const std::string& icon_bytes, 98 int64 visit_time_ms); 99 100 // NotificationObserver implementation. 101 virtual void Observe(int type, 102 const content::NotificationSource& source, 103 const content::NotificationDetails& details) OVERRIDE; 104 105 private: 106 friend class SyncFaviconCacheTest; 107 108 // Functor for ordering SyncedFaviconInfo objects by recency; 109 struct FaviconRecencyFunctor { 110 bool operator()(const linked_ptr<SyncedFaviconInfo>& lhs, 111 const linked_ptr<SyncedFaviconInfo>& rhs) const; 112 }; 113 114 115 // Map of favicon url to favicon image. 116 typedef std::map<GURL, linked_ptr<SyncedFaviconInfo> > FaviconMap; 117 typedef std::set<linked_ptr<SyncedFaviconInfo>, 118 FaviconRecencyFunctor> RecencySet; 119 // Map of page url to task id (for favicon loading). 120 typedef std::map<GURL, base::CancelableTaskTracker::TaskId> PageTaskMap; 121 // Map of page url to favicon url. 122 typedef std::map<GURL, GURL> PageFaviconMap; 123 124 // Helper method to perform OnReceivedSyncFavicon work without worrying about 125 // whether caller holds a sync transaction. 126 void OnReceivedSyncFaviconImpl(const GURL& icon_url, 127 const std::string& icon_bytes, 128 int64 visit_time_ms); 129 130 // Callback method to store a tab's favicon into its sync node once it becomes 131 // available. Does nothing if no favicon data was available. 132 void OnFaviconDataAvailable( 133 const GURL& page_url, 134 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_result); 135 136 // Helper method to update the sync state of the favicon at |icon_url|. If 137 // either |image_change_type| or |tracking_change_type| is ACTION_INVALID, 138 // the corresponding datatype won't be updated. 139 // Note: should only be called after both FAVICON_IMAGES and FAVICON_TRACKING 140 // have been successfully set up. 141 void UpdateSyncState(const GURL& icon_url, 142 syncer::SyncChange::SyncChangeType image_change_type, 143 syncer::SyncChange::SyncChangeType tracking_change_type); 144 145 // Helper method to get favicon info from |synced_favicons_|. If no info 146 // exists for |icon_url|, creates a new SyncedFaviconInfo in both 147 // |synced_favicons_| and |recent_favicons_| and returns it. 148 SyncedFaviconInfo* GetFaviconInfo(const GURL& icon_url); 149 150 // Updates the last visit time for the favicon at |icon_url| to |time| (and 151 // correspondly updates position in |recent_favicons_|. 152 void UpdateFaviconVisitTime(const GURL& icon_url, base::Time time); 153 154 // Expiration method. Looks through |recent_favicons_| to find any favicons 155 // that should be expired in order to maintain the sync favicon limit, 156 // appending deletions to |image_changes| and |tracking_changes| as necessary. 157 void ExpireFaviconsIfNecessary(syncer::SyncChangeList* image_changes, 158 syncer::SyncChangeList* tracking_changes); 159 160 // Returns the local favicon url associated with |sync_favicon| if one exists 161 // in |synced_favicons_|, else returns an invalid GURL. 162 GURL GetLocalFaviconFromSyncedData( 163 const syncer::SyncData& sync_favicon) const; 164 165 // Merges |sync_favicon| into |synced_favicons_|, updating |local_changes| 166 // with any changes that should be pushed to the sync processor. 167 void MergeSyncFavicon(const syncer::SyncData& sync_favicon, 168 syncer::SyncChangeList* sync_changes); 169 170 // Updates |synced_favicons_| with the favicon data from |sync_favicon|. 171 void AddLocalFaviconFromSyncedData(const syncer::SyncData& sync_favicon); 172 173 // Creates a SyncData object from the |type| data of |favicon_url| 174 // from within |synced_favicons_|. 175 syncer::SyncData CreateSyncDataFromLocalFavicon( 176 syncer::ModelType type, 177 const GURL& favicon_url) const; 178 179 // Deletes all synced favicons corresponding with |favicon_urls| and pushes 180 // the deletions to sync. 181 void DeleteSyncedFavicons(const std::set<GURL>& favicon_urls); 182 183 // Deletes the favicon pointed to by |favicon_iter| and appends the necessary 184 // sync deletions to |image_changes| and |tracking_changes|. 185 void DeleteSyncedFavicon(FaviconMap::iterator favicon_iter, 186 syncer::SyncChangeList* image_changes, 187 syncer::SyncChangeList* tracking_changes); 188 189 // Locally drops the favicon pointed to by |favicon_iter|. 190 void DropSyncedFavicon(FaviconMap::iterator favicon_iter); 191 192 // Only drops the data associated with |type| of |favicon_iter|. 193 void DropPartialFavicon(FaviconMap::iterator favicon_iter, 194 syncer::ModelType type); 195 196 // For testing only. 197 size_t NumFaviconsForTest() const; 198 size_t NumTasksForTest() const; 199 200 // Trask tracker for loading favicons. 201 base::CancelableTaskTracker cancelable_task_tracker_; 202 203 // Our actual cached favicon data. 204 FaviconMap synced_favicons_; 205 206 // An LRU ordering of the favicons comprising |synced_favicons_| (oldest to 207 // newest). 208 RecencySet recent_favicons_; 209 210 // Our set of pending favicon loads, indexed by page url. 211 PageTaskMap page_task_map_; 212 213 // Map of page and associated favicon urls. 214 PageFaviconMap page_favicon_map_; 215 216 Profile* profile_; 217 218 // TODO(zea): consider creating a favicon handler here for fetching unsynced 219 // favicons from the web. 220 221 scoped_ptr<syncer::SyncChangeProcessor> favicon_images_sync_processor_; 222 scoped_ptr<syncer::SyncChangeProcessor> favicon_tracking_sync_processor_; 223 224 // For listening to history deletions. 225 content::NotificationRegistrar notification_registrar_; 226 227 // Maximum number of favicons to sync. 0 means no limit. 228 const size_t max_sync_favicon_limit_; 229 230 // Weak pointer factory for favicon loads. 231 base::WeakPtrFactory<FaviconCache> weak_ptr_factory_; 232 233 DISALLOW_COPY_AND_ASSIGN(FaviconCache); 234 }; 235 236 } // namespace browser_sync 237 238 #endif // CHROME_BROWSER_SYNC_GLUE_FAVICON_CACHE_H_ 239