1// Copyright (c) 2012 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_FAVICON_FAVICON_HANDLER_H_
6#define CHROME_BROWSER_FAVICON_FAVICON_HANDLER_H_
7
8#include <deque>
9#include <map>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/callback_forward.h"
14#include "base/memory/ref_counted.h"
15#include "base/task/cancelable_task_tracker.h"
16#include "components/favicon/core/favicon_url.h"
17#include "components/favicon_base/favicon_callback.h"
18#include "ui/gfx/favicon_size.h"
19#include "ui/gfx/image/image.h"
20#include "url/gurl.h"
21
22class FaviconClient;
23class FaviconDriver;
24class SkBitmap;
25
26namespace base {
27class RefCountedMemory;
28}
29
30// FaviconHandler works with FaviconDriver to fetch the specific type of
31// favicon.
32//
33// FetchFavicon requests the favicon from the favicon service which in turn
34// requests the favicon from the history database. At this point
35// we only know the URL of the page, and not necessarily the url of the
36// favicon. To ensure we handle reloading stale favicons as well as
37// reloading a favicon on page reload we always request the favicon from
38// history regardless of whether the active favicon is valid.
39//
40// After the navigation two types of events are delivered (which is
41// first depends upon who is faster): notification from the history
42// db on our request for the favicon
43// (OnFaviconDataForInitialURLFromFaviconService), or a message from the
44// renderer giving us the URL of the favicon for the page (SetFaviconURL).
45// . If the history db has a valid up to date favicon for the page, we update
46//   the current page and use the favicon.
47// . When we receive the favicon url if it matches that of the current page
48//   and the current page's favicon is set, we do nothing (everything is
49//   ok).
50// . On the other hand if the database does not know the favicon for url, or
51//   the favicon is out date, or the URL from the renderer does not match that
52//   of the current page we proceed to DownloadFaviconOrAskHistory. Before we
53//   invoke DownloadFaviconOrAskHistory we wait until we've received both
54//   the favicon url and the callback from history. We wait to ensure we
55//   truly know both the favicon url and the state of the database.
56//
57// DownloadFaviconOrAskHistory does the following:
58// . If we have a valid favicon, but it is expired we ask the renderer to
59//   download the favicon.
60// . Otherwise we ask the history database to update the mapping from
61//   page url to favicon url and call us back with the favicon. Remember, it is
62//   possible for the db to already have the favicon, just not the mapping
63//   between page to favicon url. The callback for this is OnFaviconData.
64//
65// OnFaviconData either updates the favicon of the current page (if the
66// db knew about the favicon), or requests the renderer to download the
67// favicon.
68//
69// When the renderer downloads favicons, it considers the entire list of
70// favicon candidates, if |download_largest_favicon_| is true, the largest
71// favicon will be used, otherwise the one that best matches the preferred size
72// is chosen (or the first one if there is no preferred  size). Once the
73// matching favicon has been determined, SetFavicon is called which updates
74// the page's favicon and notifies the database to save the favicon.
75
76class FaviconHandler {
77 public:
78  enum Type {
79    FAVICON,
80    TOUCH,
81  };
82
83  FaviconHandler(FaviconClient* client,
84                 FaviconDriver* driver,
85                 Type icon_type,
86                 bool download_largest_icon);
87  virtual ~FaviconHandler();
88
89  // Initiates loading the favicon for the specified url.
90  void FetchFavicon(const GURL& url);
91
92  // Message Handler.  Must be public, because also called from
93  // PrerenderContents. Collects the |image_urls| list.
94  void OnUpdateFaviconURL(const std::vector<favicon::FaviconURL>& candidates);
95
96  // Processes the current image_irls_ entry, requesting the image from the
97  // history / download service.
98  void ProcessCurrentUrl();
99
100  // Message handler for ImageHostMsg_DidDownloadImage. Called when the image
101  // at |image_url| has been downloaded.
102  // |bitmaps| is a list of all the frames of the image at |image_url|.
103  // |original_bitmap_sizes| are the sizes of |bitmaps| before they were resized
104  // to the maximum bitmap size passed to DownloadFavicon().
105  void OnDidDownloadFavicon(
106      int id,
107      const GURL& image_url,
108      const std::vector<SkBitmap>& bitmaps,
109      const std::vector<gfx::Size>& original_bitmap_sizes);
110
111  // For testing.
112  const std::vector<favicon::FaviconURL>& image_urls() const {
113    return image_urls_;
114  }
115
116 protected:
117  // These virtual methods make FaviconHandler testable and are overridden by
118  // TestFaviconHandler.
119
120  // Asks the render to download favicon, returns the request id.
121  virtual int DownloadFavicon(const GURL& image_url, int max_bitmap_size);
122
123  // Ask the favicon from history
124  virtual void UpdateFaviconMappingAndFetch(
125      const GURL& page_url,
126      const GURL& icon_url,
127      favicon_base::IconType icon_type,
128      const favicon_base::FaviconResultsCallback& callback,
129      base::CancelableTaskTracker* tracker);
130
131  virtual void GetFaviconFromFaviconService(
132      const GURL& icon_url,
133      favicon_base::IconType icon_type,
134      const favicon_base::FaviconResultsCallback& callback,
135      base::CancelableTaskTracker* tracker);
136
137  virtual void GetFaviconForURLFromFaviconService(
138      const GURL& page_url,
139      int icon_types,
140      const favicon_base::FaviconResultsCallback& callback,
141      base::CancelableTaskTracker* tracker);
142
143  virtual void SetHistoryFavicons(const GURL& page_url,
144                                  const GURL& icon_url,
145                                  favicon_base::IconType icon_type,
146                                  const gfx::Image& image);
147
148  // Returns true if the favicon should be saved.
149  virtual bool ShouldSaveFavicon(const GURL& url);
150
151  // Notifies the driver that the favicon for the active entry was updated.
152  // |icon_url_changed| is true if a favicon with a different icon URL has been
153  // selected since the previous call to NotifyFaviconUpdated().
154  virtual void NotifyFaviconUpdated(bool icon_url_changed);
155
156 private:
157  friend class TestFaviconHandler; // For testing
158
159  // Represents an in progress download of an image from the renderer.
160  struct DownloadRequest {
161    DownloadRequest();
162    ~DownloadRequest();
163
164    DownloadRequest(const GURL& url,
165                    const GURL& image_url,
166                    favicon_base::IconType icon_type);
167
168    GURL url;
169    GURL image_url;
170    favicon_base::IconType icon_type;
171  };
172
173  // Used to track a candidate for the favicon.
174  struct FaviconCandidate {
175    FaviconCandidate();
176    ~FaviconCandidate();
177
178    FaviconCandidate(const GURL& url,
179                     const GURL& image_url,
180                     const gfx::Image& image,
181                     float score,
182                     favicon_base::IconType icon_type);
183
184    GURL url;
185    GURL image_url;
186    gfx::Image image;
187    float score;
188    favicon_base::IconType icon_type;
189  };
190
191  // See description above class for details.
192  void OnFaviconDataForInitialURLFromFaviconService(const std::vector<
193      favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results);
194
195  // If the favicon has expired, asks the renderer to download the favicon.
196  // Otherwise asks history to update the mapping between page url and icon
197  // url with a callback to OnFaviconData when done.
198  void DownloadFaviconOrAskFaviconService(const GURL& page_url,
199                                          const GURL& icon_url,
200                                          favicon_base::IconType icon_type);
201
202  // See description above class for details.
203  void OnFaviconData(const std::vector<favicon_base::FaviconRawBitmapResult>&
204                         favicon_bitmap_results);
205
206  // Schedules a download for the specified entry. This adds the request to
207  // download_requests_.
208  int ScheduleDownload(const GURL& url,
209                       const GURL& image_url,
210                       favicon_base::IconType icon_type);
211
212  // Updates |favicon_candidate_| and returns true if it is an exact match.
213  bool UpdateFaviconCandidate(const GURL& url,
214                              const GURL& image_url,
215                              const gfx::Image& image,
216                              float score,
217                              favicon_base::IconType icon_type);
218
219  // Sets the image data for the favicon.
220  void SetFavicon(const GURL& url,
221                  const GURL& icon_url,
222                  const gfx::Image& image,
223                  favicon_base::IconType icon_type);
224
225  // Sets the favicon's data.
226  void SetFaviconOnActivePage(const std::vector<
227      favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results);
228  void SetFaviconOnActivePage(const GURL& icon_url, const gfx::Image& image);
229
230  // Return the current candidate if any.
231  favicon::FaviconURL* current_candidate() {
232    return (!image_urls_.empty()) ? &image_urls_.front() : NULL;
233  }
234
235  // Returns whether the page's url changed since the favicon was requested.
236  bool PageChangedSinceFaviconWasRequested();
237
238  // Returns the preferred size of the image. 0 means no preference (any size
239  // will do).
240  int preferred_icon_size() const {
241    if (download_largest_icon_)
242      return 0;
243    return icon_types_ == favicon_base::FAVICON ? gfx::kFaviconSize : 0;
244  }
245
246  // Sorts the entries in |image_urls_| by icon size in descending order.
247  // Additionally removes any entries whose sizes are all greater than the max
248  // allowed size.
249  void SortAndPruneImageUrls();
250
251  // Used for FaviconService requests.
252  base::CancelableTaskTracker cancelable_task_tracker_;
253
254  // URL of the page we're requesting the favicon for.
255  GURL url_;
256
257  // Whether we got the initial response for the favicon back from the renderer.
258  bool got_favicon_from_history_;
259
260  // Whether the favicon is out of date or the favicon data in
261  // |history_results_| is known to be incomplete. If true, it means history
262  // knows about the favicon, but we need to download the favicon because the
263  // icon has expired or the data in the database is incomplete.
264  bool favicon_expired_or_incomplete_;
265
266  // Requests to the renderer to download favicons.
267  typedef std::map<int, DownloadRequest> DownloadRequests;
268  DownloadRequests download_requests_;
269
270  // The combination of the supported icon types.
271  const int icon_types_;
272
273  // Whether the largest icon should be downloaded.
274  const bool download_largest_icon_;
275
276  // The prioritized favicon candidates from the page back from the renderer.
277  std::vector<favicon::FaviconURL> image_urls_;
278
279  // The FaviconRawBitmapResults from history.
280  std::vector<favicon_base::FaviconRawBitmapResult> history_results_;
281
282  // The client which implements embedder-specific Favicon operations.
283  FaviconClient* client_;  // weak
284
285  // This handler's driver.
286  FaviconDriver* driver_;  // weak
287
288  // Best image we've seen so far.  As images are downloaded from the page they
289  // are stored here. When there is an exact match, or no more images are
290  // available the favicon service and the current page are updated (assuming
291  // the image is for a favicon).
292  FaviconCandidate best_favicon_candidate_;
293
294  DISALLOW_COPY_AND_ASSIGN(FaviconHandler);
295};
296
297#endif  // CHROME_BROWSER_FAVICON_FAVICON_HANDLER_H_
298