| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/fav_icon_helper.h" | 5 #include "chrome/browser/fav_icon_helper.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 8 | 8 |
| 9 #include "app/gfx/codec/png_codec.h" | 9 #include "app/gfx/codec/png_codec.h" |
| 10 #include "app/gfx/favicon_size.h" | 10 #include "app/gfx/favicon_size.h" |
| 11 #include "chrome/browser/profile.h" | 11 #include "chrome/browser/profile.h" |
| 12 #include "chrome/browser/renderer_host/render_view_host.h" | 12 #include "chrome/browser/renderer_host/render_view_host.h" |
| 13 #include "chrome/browser/tab_contents/navigation_controller.h" | 13 #include "chrome/browser/tab_contents/navigation_controller.h" |
| 14 #include "chrome/browser/tab_contents/navigation_entry.h" | 14 #include "chrome/browser/tab_contents/navigation_entry.h" |
| 15 #include "chrome/browser/tab_contents/tab_contents_delegate.h" | 15 #include "chrome/browser/tab_contents/tab_contents_delegate.h" |
| 16 #include "chrome/browser/tab_contents/tab_contents.h" | 16 #include "chrome/browser/tab_contents/tab_contents.h" |
| 17 #include "skia/ext/image_operations.h" | 17 #include "skia/ext/image_operations.h" |
| 18 | 18 |
| 19 FavIconHelper::FavIconHelper(TabContents* tab_contents) | 19 FavIconHelper::FavIconHelper(TabContents* tab_contents) |
| 20 : tab_contents_(tab_contents), | 20 : tab_contents_(tab_contents), |
| 21 got_fav_icon_url_(false), | 21 got_fav_icon_url_(false), |
| 22 got_fav_icon_from_history_(false), | 22 got_fav_icon_from_history_(false), |
| 23 fav_icon_expired_(false) { | 23 fav_icon_expired_(false) { |
| 24 } | 24 } |
| 25 | 25 |
| 26 FavIconHelper::~FavIconHelper() { |
| 27 SkBitmap empty_image; |
| 28 |
| 29 // Call pending download callbacks with error to allow caller to clean up. |
| 30 for (DownloadRequests::iterator i = download_requests_.begin(); |
| 31 i != download_requests_.end(); ++i) { |
| 32 if (i->second.callback) { |
| 33 i->second.callback->Run(i->first, true, empty_image); |
| 34 } |
| 35 } |
| 36 } |
| 37 |
| 26 void FavIconHelper::FetchFavIcon(const GURL& url) { | 38 void FavIconHelper::FetchFavIcon(const GURL& url) { |
| 27 cancelable_consumer_.CancelAllRequests(); | 39 cancelable_consumer_.CancelAllRequests(); |
| 28 | 40 |
| 29 url_ = url; | 41 url_ = url; |
| 30 | 42 |
| 31 fav_icon_expired_ = got_fav_icon_from_history_ = got_fav_icon_url_ = false; | 43 fav_icon_expired_ = got_fav_icon_from_history_ = got_fav_icon_url_ = false; |
| 32 | 44 |
| 33 // Request the favicon from the history service. In parallel to this the | 45 // Request the favicon from the history service. In parallel to this the |
| 34 // renderer is going to notify us (well TabContents) when the favicon url is | 46 // renderer is going to notify us (well TabContents) when the favicon url is |
| 35 // available. | 47 // available. |
| 36 if (GetFaviconService()) { | 48 if (GetFaviconService()) { |
| 37 GetFaviconService()->GetFaviconForURL(url_, &cancelable_consumer_, | 49 GetFaviconService()->GetFaviconForURL(url_, &cancelable_consumer_, |
| 38 NewCallback(this, &FavIconHelper::OnFavIconDataForInitialURL)); | 50 NewCallback(this, &FavIconHelper::OnFavIconDataForInitialURL)); |
| 39 } | 51 } |
| 40 } | 52 } |
| 41 | 53 |
| 54 int FavIconHelper::DownloadImage(const GURL& image_url, |
| 55 int image_size, |
| 56 ImageDownloadCallback* callback) { |
| 57 DCHECK(callback); // Must provide a callback. |
| 58 return ScheduleDownload(GURL(), image_url, image_size, callback); |
| 59 } |
| 60 |
| 42 Profile* FavIconHelper::profile() { | 61 Profile* FavIconHelper::profile() { |
| 43 return tab_contents_->profile(); | 62 return tab_contents_->profile(); |
| 44 } | 63 } |
| 45 | 64 |
| 46 FaviconService* FavIconHelper::GetFaviconService() { | 65 FaviconService* FavIconHelper::GetFaviconService() { |
| 47 return profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); | 66 return profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); |
| 48 } | 67 } |
| 49 | 68 |
| 50 void FavIconHelper::SetFavIcon( | 69 void FavIconHelper::SetFavIcon( |
| 51 int download_id, | 70 const GURL& url, |
| 52 const GURL& image_url, | 71 const GURL& image_url, |
| 53 const SkBitmap& image) { | 72 const SkBitmap& image) { |
| 54 DownloadRequests::iterator i = download_requests_.find(download_id); | |
| 55 if (i == download_requests_.end()) { | |
| 56 // Currently TabContents notifies us of ANY downloads so that it is | |
| 57 // possible to get here. | |
| 58 return; | |
| 59 } | |
| 60 | |
| 61 const SkBitmap& sized_image = | 73 const SkBitmap& sized_image = |
| 62 (image.width() == kFavIconSize && image.height() == kFavIconSize) | 74 (image.width() == kFavIconSize && image.height() == kFavIconSize) |
| 63 ? image : ConvertToFavIconSize(image); | 75 ? image : ConvertToFavIconSize(image); |
| 64 | 76 |
| 65 if (GetFaviconService() && !profile()->IsOffTheRecord()) { | 77 if (GetFaviconService() && !profile()->IsOffTheRecord()) { |
| 66 std::vector<unsigned char> image_data; | 78 std::vector<unsigned char> image_data; |
| 67 gfx::PNGCodec::EncodeBGRASkBitmap(sized_image, false, &image_data); | 79 gfx::PNGCodec::EncodeBGRASkBitmap(sized_image, false, &image_data); |
| 68 GetFaviconService()->SetFavicon(i->second.url, i->second.fav_icon_url, | 80 GetFaviconService()->SetFavicon(url, image_url, image_data); |
| 69 image_data); | |
| 70 } | 81 } |
| 71 | 82 |
| 72 if (i->second.url == url_) { | 83 if (url == url_) { |
| 73 NavigationEntry* entry = GetEntry(); | 84 NavigationEntry* entry = GetEntry(); |
| 74 if (entry) | 85 if (entry) |
| 75 UpdateFavIcon(entry, sized_image); | 86 UpdateFavIcon(entry, sized_image); |
| 76 } | 87 } |
| 77 | |
| 78 download_requests_.erase(i); | |
| 79 } | |
| 80 | |
| 81 void FavIconHelper::FavIconDownloadFailed(int download_id) { | |
| 82 DownloadRequests::iterator i = download_requests_.find(download_id); | |
| 83 if (i != download_requests_.end()) | |
| 84 download_requests_.erase(i); | |
| 85 } | 88 } |
| 86 | 89 |
| 87 void FavIconHelper::UpdateFavIcon(NavigationEntry* entry, | 90 void FavIconHelper::UpdateFavIcon(NavigationEntry* entry, |
| 88 const std::vector<unsigned char>& data) { | 91 const std::vector<unsigned char>& data) { |
| 89 SkBitmap image; | 92 SkBitmap image; |
| 90 gfx::PNGCodec::Decode(&data.front(), data.size(), &image); | 93 gfx::PNGCodec::Decode(&data.front(), data.size(), &image); |
| 91 UpdateFavIcon(entry, image); | 94 UpdateFavIcon(entry, image); |
| 92 } | 95 } |
| 93 | 96 |
| 94 void FavIconHelper::UpdateFavIcon(NavigationEntry* entry, | 97 void FavIconHelper::UpdateFavIcon(NavigationEntry* entry, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 125 | 128 |
| 126 if (got_fav_icon_from_history_) | 129 if (got_fav_icon_from_history_) |
| 127 DownloadFavIconOrAskHistory(entry); | 130 DownloadFavIconOrAskHistory(entry); |
| 128 } | 131 } |
| 129 | 132 |
| 130 void FavIconHelper::DidDownloadFavIcon(RenderViewHost* render_view_host, | 133 void FavIconHelper::DidDownloadFavIcon(RenderViewHost* render_view_host, |
| 131 int id, | 134 int id, |
| 132 const GURL& image_url, | 135 const GURL& image_url, |
| 133 bool errored, | 136 bool errored, |
| 134 const SkBitmap& image) { | 137 const SkBitmap& image) { |
| 135 if (errored) | 138 DownloadRequests::iterator i = download_requests_.find(id); |
| 136 FavIconDownloadFailed(id); | 139 if (i == download_requests_.end()) { |
| 137 else | 140 // Currently TabContents notifies us of ANY downloads so that it is |
| 138 SetFavIcon(id, image_url, image); | 141 // possible to get here. |
| 142 return; |
| 143 } |
| 144 |
| 145 if (i->second.callback) { |
| 146 i->second.callback->Run(id, errored, image); |
| 147 } else if (!errored) { |
| 148 SetFavIcon(i->second.url, image_url, image); |
| 149 } |
| 150 |
| 151 download_requests_.erase(i); |
| 139 } | 152 } |
| 140 | 153 |
| 141 NavigationEntry* FavIconHelper::GetEntry() { | 154 NavigationEntry* FavIconHelper::GetEntry() { |
| 142 NavigationEntry* entry = tab_contents_->controller().GetActiveEntry(); | 155 NavigationEntry* entry = tab_contents_->controller().GetActiveEntry(); |
| 143 if (entry && entry->url() == url_ && | 156 if (entry && entry->url() == url_ && |
| 144 tab_contents_->IsActiveEntry(entry->page_id())) { | 157 tab_contents_->IsActiveEntry(entry->page_id())) { |
| 145 return entry; | 158 return entry; |
| 146 } | 159 } |
| 147 // If the URL has changed out from under us (as will happen with redirects) | 160 // If the URL has changed out from under us (as will happen with redirects) |
| 148 // return NULL. | 161 // return NULL. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 DownloadFavIconOrAskHistory(entry); | 202 DownloadFavIconOrAskHistory(entry); |
| 190 } | 203 } |
| 191 // else we haven't got the icon url. When we get it we'll ask the | 204 // else we haven't got the icon url. When we get it we'll ask the |
| 192 // renderer to download the icon. | 205 // renderer to download the icon. |
| 193 } | 206 } |
| 194 | 207 |
| 195 void FavIconHelper::DownloadFavIconOrAskHistory(NavigationEntry* entry) { | 208 void FavIconHelper::DownloadFavIconOrAskHistory(NavigationEntry* entry) { |
| 196 DCHECK(entry); // We should only get here if entry is valid. | 209 DCHECK(entry); // We should only get here if entry is valid. |
| 197 if (fav_icon_expired_) { | 210 if (fav_icon_expired_) { |
| 198 // We have the mapping, but the favicon is out of date. Download it now. | 211 // We have the mapping, but the favicon is out of date. Download it now. |
| 199 ScheduleDownload(entry); | 212 ScheduleDownload(entry->url(), entry->favicon().url(), kFavIconSize, NULL); |
| 200 } else if (GetFaviconService()) { | 213 } else if (GetFaviconService()) { |
| 201 // We don't know the favicon, but we may have previously downloaded the | 214 // We don't know the favicon, but we may have previously downloaded the |
| 202 // favicon for another page that shares the same favicon. Ask for the | 215 // favicon for another page that shares the same favicon. Ask for the |
| 203 // favicon given the favicon URL. | 216 // favicon given the favicon URL. |
| 204 if (profile()->IsOffTheRecord()) { | 217 if (profile()->IsOffTheRecord()) { |
| 205 GetFaviconService()->GetFavicon( | 218 GetFaviconService()->GetFavicon( |
| 206 entry->favicon().url(), | 219 entry->favicon().url(), |
| 207 &cancelable_consumer_, | 220 &cancelable_consumer_, |
| 208 NewCallback(this, &FavIconHelper::OnFavIconData)); | 221 NewCallback(this, &FavIconHelper::OnFavIconData)); |
| 209 } else { | 222 } else { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 236 | 249 |
| 237 if (know_favicon && data && !data->data.empty()) { | 250 if (know_favicon && data && !data->data.empty()) { |
| 238 // There is a favicon, set it now. If expired we'll download the current | 251 // There is a favicon, set it now. If expired we'll download the current |
| 239 // one again, but at least the user will get some icon instead of the | 252 // one again, but at least the user will get some icon instead of the |
| 240 // default and most likely the current one is fine anyway. | 253 // default and most likely the current one is fine anyway. |
| 241 UpdateFavIcon(entry, data->data); | 254 UpdateFavIcon(entry, data->data); |
| 242 } | 255 } |
| 243 | 256 |
| 244 if (!know_favicon || expired) { | 257 if (!know_favicon || expired) { |
| 245 // We don't know the favicon, or it is out of date. Request the current one. | 258 // We don't know the favicon, or it is out of date. Request the current one. |
| 246 ScheduleDownload(entry); | 259 ScheduleDownload(entry->url(), entry->favicon().url(), kFavIconSize, NULL); |
| 247 } | 260 } |
| 248 } | 261 } |
| 249 | 262 |
| 250 void FavIconHelper::ScheduleDownload(NavigationEntry* entry) { | 263 int FavIconHelper::ScheduleDownload(const GURL& url, |
| 264 const GURL& image_url, |
| 265 int image_size, |
| 266 ImageDownloadCallback* callback) { |
| 251 const int download_id = tab_contents_->render_view_host()->DownloadFavIcon( | 267 const int download_id = tab_contents_->render_view_host()->DownloadFavIcon( |
| 252 entry->favicon().url(), kFavIconSize); | 268 image_url, image_size); |
| 253 if (!download_id) | |
| 254 return; // Download request failed. | |
| 255 | 269 |
| 256 // Download ids should be unique. | 270 if (download_id) { |
| 257 DCHECK(download_requests_.find(download_id) == download_requests_.end()); | 271 // Download ids should be unique. |
| 258 download_requests_[download_id] = | 272 DCHECK(download_requests_.find(download_id) == download_requests_.end()); |
| 259 DownloadRequest(entry->url(), entry->favicon().url()); | 273 download_requests_[download_id] = DownloadRequest(url, image_url, callback); |
| 274 } |
| 275 |
| 276 return download_id; |
| 260 } | 277 } |
| 261 | 278 |
| 262 SkBitmap FavIconHelper::ConvertToFavIconSize(const SkBitmap& image) { | 279 SkBitmap FavIconHelper::ConvertToFavIconSize(const SkBitmap& image) { |
| 263 int width = image.width(); | 280 int width = image.width(); |
| 264 int height = image.height(); | 281 int height = image.height(); |
| 265 if (width > 0 && height > 0) { | 282 if (width > 0 && height > 0) { |
| 266 calc_favicon_target_size(&width, &height); | 283 calc_favicon_target_size(&width, &height); |
| 267 return skia::ImageOperations::Resize( | 284 return skia::ImageOperations::Resize( |
| 268 image, skia::ImageOperations::RESIZE_LANCZOS3, | 285 image, skia::ImageOperations::RESIZE_LANCZOS3, |
| 269 width, height); | 286 width, height); |
| 270 } | 287 } |
| 271 return image; | 288 return image; |
| 272 } | 289 } |
| OLD | NEW |