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 "components/history/core/browser/history_types.h"
20#include "components/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
28class Profile;
29
30namespace chrome {
31struct FaviconRawBitmapResult;
32}
33
34namespace browser_sync {
35
36enum IconSize {
37  SIZE_INVALID,
38  SIZE_16,
39  SIZE_32,
40  SIZE_64,
41  NUM_SIZES
42};
43
44struct SyncedFaviconInfo;
45
46// Encapsulates the logic for loading and storing synced favicons.
47// TODO(zea): make this a KeyedService.
48class 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