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 22 class NavigationEntry; 23 class Profile; 24 class RefCountedMemory; 25 class SkBitmap; 26 class 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 70 class 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. current_candidate()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. preferred_icon_size()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