1// Copyright (c) 2011 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_HELPER_H__
6#define CHROME_BROWSER_FAVICON_HELPER_H__
7#pragma once
8
9#include <map>
10
11#include "base/basictypes.h"
12#include "base/callback.h"
13#include "base/memory/ref_counted.h"
14#include "chrome/browser/favicon_service.h"
15#include "chrome/common/favicon_url.h"
16#include "chrome/common/ref_counted_util.h"
17#include "content/browser/cancelable_request.h"
18#include "content/browser/tab_contents/tab_contents_observer.h"
19#include "googleurl/src/gurl.h"
20#include "ui/gfx/favicon_size.h"
21
22class NavigationEntry;
23class Profile;
24class RefCountedMemory;
25class SkBitmap;
26class TabContents;
27
28// FaviconHelper is used to fetch the favicon for TabContents.
29//
30// FetchFavicon requests the favicon from the favicon service which in turn
31// requests the favicon from the history database. At this point
32// we only know the URL of the page, and not necessarily the url of the
33// favicon. To ensure we handle reloading stale favicons as well as
34// reloading a favicon on page reload we always request the favicon from
35// history regardless of whether the NavigationEntry has a favicon.
36//
37// After the navigation two types of events are delivered (which is
38// first depends upon who is faster): notification from the history
39// db on our request for the favicon (OnFaviconDataForInitialURL),
40// or a message from the renderer giving us the URL of the favicon for
41// the page (SetFaviconURL).
42// . If the history db has a valid up to date favicon for the page, we update
43//   the NavigationEntry and use the favicon.
44// . When we receive the favicon url if it matches that of the NavigationEntry
45//   and the NavigationEntry's favicon is set, we do nothing (everything is
46//   ok).
47// . On the other hand if the database does not know the favicon for url, or
48//   the favicon is out date, or the URL from the renderer does not match that
49//   NavigationEntry we proceed to DownloadFaviconOrAskHistory. Before we
50//   invoke DownloadFaviconOrAskHistory we wait until we've received both
51//   the favicon url and the callback from history. We wait to ensure we
52//   truly know both the favicon url and the state of the database.
53//
54// DownloadFaviconOrAskHistory does the following:
55// . If we have a valid favicon, but it is expired we ask the renderer to
56//   download the favicon.
57// . Otherwise we ask the history database to update the mapping from
58//   page url to favicon url and call us back with the favicon. Remember, it is
59//   possible for the db to already have the favicon, just not the mapping
60//   between page to favicon url. The callback for this is OnFaviconData.
61//
62// OnFaviconData either updates the favicon of the NavigationEntry (if the
63// db knew about the favicon), or requests the renderer to download the
64// favicon.
65//
66// When the renderer downloads the favicon SetFaviconImageData is invoked,
67// at which point we update the favicon of the NavigationEntry and notify
68// the database to save the favicon.
69
70class FaviconHelper : public TabContentsObserver {
71 public:
72  enum Type {
73    FAVICON,
74    TOUCH,
75  };
76
77  FaviconHelper(TabContents* tab_contents, Type icon_type);
78  virtual ~FaviconHelper();
79
80  // Initiates loading the favicon for the specified url.
81  void FetchFavicon(const GURL& url);
82
83  // Initiates loading an image from given |image_url|. Returns a download id
84  // for caller to track the request. When download completes, |callback| is
85  // called with the three params: the download_id, a boolean flag to indicate
86  // whether the download succeeds and a SkBitmap as the downloaded image.
87  // Note that |image_size| is a hint for images with multiple sizes. The
88  // downloaded image is not resized to the given image_size. If 0 is passed,
89  // the first frame of the image is returned.
90  typedef Callback3<int, bool, const SkBitmap&>::Type ImageDownloadCallback;
91  int DownloadImage(const GURL& image_url,
92                    int image_size,
93                    history::IconType icon_type,
94                    ImageDownloadCallback* callback);
95
96  // Message Handler.  Must be public, because also called from
97  // PrerenderContents.
98  void OnUpdateFaviconURL(int32 page_id,
99                          const std::vector<FaviconURL>& candidates);
100
101 protected:
102  // These virtual methods make FaviconHelper testable and are overridden by
103  // TestFaviconHelper
104  //
105  // Return the NavigationEntry for the active entry, or NULL if the active
106  // entries URL does not match that of the URL last passed to FetchFavicon.
107  virtual NavigationEntry* GetEntry();
108
109  // Asks the render to download favicon, returns the request id.
110  virtual int DownloadFavicon(const GURL& image_url, int image_size);
111
112  // Ask the favicon from history
113  virtual void UpdateFaviconMappingAndFetch(
114      const GURL& page_url,
115      const GURL& icon_url,
116      history::IconType icon_type,
117      CancelableRequestConsumerBase* consumer,
118      FaviconService::FaviconDataCallback* callback);
119
120  virtual void GetFavicon(
121      const GURL& icon_url,
122      history::IconType icon_type,
123      CancelableRequestConsumerBase* consumer,
124      FaviconService::FaviconDataCallback* callback);
125
126  virtual void GetFaviconForURL(
127      const GURL& page_url,
128      int icon_types,
129      CancelableRequestConsumerBase* consumer,
130      FaviconService::FaviconDataCallback* callback);
131
132  virtual void SetHistoryFavicon(const GURL& page_url,
133                                 const GURL& icon_url,
134                                 const std::vector<unsigned char>& image_data,
135                                 history::IconType icon_type);
136
137  virtual FaviconService* GetFaviconService();
138
139  // Returns true if the favicon should be saved.
140  virtual bool ShouldSaveFavicon(const GURL& url);
141
142 private:
143  friend class TestFaviconHelper; // For testing
144
145  struct DownloadRequest {
146    DownloadRequest();
147
148    DownloadRequest(const GURL& url,
149                    const GURL& image_url,
150                    ImageDownloadCallback* callback,
151                    history::IconType icon_type);
152
153    GURL url;
154    GURL image_url;
155    ImageDownloadCallback* callback;
156    history::IconType icon_type;
157  };
158
159  // TabContentsObserver overrides.
160  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
161
162  void OnDidDownloadFavicon(int id,
163                            const GURL& image_url,
164                            bool errored,
165                            const SkBitmap& image);
166
167  // See description above class for details.
168  void OnFaviconDataForInitialURL(FaviconService::Handle handle,
169                                  history::FaviconData favicon);
170
171  // If the favicon has expired, asks the renderer to download the favicon.
172  // Otherwise asks history to update the mapping between page url and icon
173  // url with a callback to OnFaviconData when done.
174  void DownloadFaviconOrAskHistory(const GURL& page_url,
175                                   const GURL& icon_url,
176                                   history::IconType icon_type);
177
178  // See description above class for details.
179  void OnFaviconData(FaviconService::Handle handle,
180                     history::FaviconData favicon);
181
182  // Schedules a download for the specified entry. This adds the request to
183  // download_requests_.
184  int ScheduleDownload(const GURL& url,
185                       const GURL& image_url,
186                       int image_size,
187                       history::IconType icon_type,
188                       ImageDownloadCallback* callback);
189
190  // Sets the image data for the favicon. This is invoked asynchronously after
191  // we request the TabContents to download the favicon.
192  void SetFavicon(const GURL& url,
193                  const GURL& icon_url,
194                  const SkBitmap& image,
195                  history::IconType icon_type);
196
197  // Converts the FAVICON's image data to an SkBitmap and sets it on the
198  // NavigationEntry.
199  // If the TabContents has a delegate, it is notified of the new favicon
200  // (INVALIDATE_FAVICON).
201  void UpdateFavicon(NavigationEntry* entry,
202                     scoped_refptr<RefCountedMemory> data);
203  void UpdateFavicon(NavigationEntry* entry, const SkBitmap& image);
204
205  // Scales the image such that either the width and/or height is 16 pixels
206  // wide. Does nothing if the image is empty.
207  SkBitmap ConvertToFaviconSize(const SkBitmap& image);
208
209  void FetchFaviconInternal();
210
211  // Return the current candidate if any.
212  FaviconURL* current_candidate() {
213    return (urls_.size() > current_url_index_) ?
214        &urls_[current_url_index_] : NULL;
215  }
216
217  // Returns the preferred_icon_size according icon_types_, 0 means no
218  // preference.
219  int preferred_icon_size() {
220    return icon_types_ == history::FAVICON ? kFaviconSize : 0;
221  }
222
223  // Used for history requests.
224  CancelableRequestConsumer cancelable_consumer_;
225
226  // URL of the page we're requesting the favicon for.
227  GURL url_;
228
229  // Whether we got the initial response for the favicon back from the renderer.
230  // See "Favicon Details" in tab_contents.cc for more details.
231  bool got_favicon_from_history_;
232
233  // Whether the favicon is out of date. If true, it means history knows about
234  // the favicon, but we need to download the favicon because the icon has
235  // expired.
236  // See "Favicon Details" in tab_contents.cc for more details.
237  bool favicon_expired_;
238
239  // Requests to the renderer to download favicons.
240  typedef std::map<int, DownloadRequest> DownloadRequests;
241  DownloadRequests download_requests_;
242
243  // The combination of the supported icon types.
244  const int icon_types_;
245
246  // The prioritized favicon candidates from the page back from the renderer.
247  std::vector<FaviconURL> urls_;
248
249  // The current candidate's index in urls_.
250  size_t current_url_index_;
251
252  // The FaviconData from history.
253  history::FaviconData history_icon_;
254
255  DISALLOW_COPY_AND_ASSIGN(FaviconHelper);
256};
257
258#endif  // CHROME_BROWSER_FAVICON_HELPER_H__
259