favicon_service.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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#include "chrome/browser/favicon/favicon_service.h" 6 7#include "base/message_loop/message_loop_proxy.h" 8#include "chrome/browser/favicon/favicon_util.h" 9#include "chrome/browser/favicon/imported_favicon_usage.h" 10#include "chrome/browser/history/history_backend.h" 11#include "chrome/browser/history/history_service.h" 12#include "chrome/browser/history/history_service_factory.h" 13#include "chrome/browser/history/select_favicon_frames.h" 14#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" 15#include "chrome/common/url_constants.h" 16#include "extensions/common/constants.h" 17#include "third_party/skia/include/core/SkBitmap.h" 18#include "ui/gfx/codec/png_codec.h" 19#include "ui/gfx/favicon_size.h" 20#include "ui/gfx/image/image_skia.h" 21 22using base::Bind; 23 24namespace { 25 26void CancelOrRunFaviconResultsCallback( 27 const CancelableTaskTracker::IsCanceledCallback& is_canceled, 28 const FaviconService::FaviconResultsCallback& callback, 29 const std::vector<history::FaviconBitmapResult>& results) { 30 if (is_canceled.Run()) 31 return; 32 callback.Run(results); 33} 34 35// Helper to run callback with empty results if we cannot get the history 36// service. 37CancelableTaskTracker::TaskId RunWithEmptyResultAsync( 38 const FaviconService::FaviconResultsCallback& callback, 39 CancelableTaskTracker* tracker) { 40 return tracker->PostTask( 41 base::MessageLoopProxy::current(), 42 FROM_HERE, 43 Bind(callback, std::vector<history::FaviconBitmapResult>())); 44} 45 46} // namespace 47 48FaviconService::FaviconService(HistoryService* history_service) 49 : history_service_(history_service) { 50} 51 52// static 53void FaviconService::FaviconResultsCallbackRunner( 54 const FaviconResultsCallback& callback, 55 const std::vector<history::FaviconBitmapResult>* results) { 56 callback.Run(*results); 57} 58 59CancelableTaskTracker::TaskId FaviconService::GetFaviconImage( 60 const GURL& icon_url, 61 history::IconType icon_type, 62 int desired_size_in_dip, 63 const FaviconImageCallback& callback, 64 CancelableTaskTracker* tracker) { 65 FaviconResultsCallback callback_runner = 66 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, 67 base::Unretained(this), callback, desired_size_in_dip); 68 if (history_service_) { 69 std::vector<GURL> icon_urls; 70 icon_urls.push_back(icon_url); 71 return history_service_->GetFavicons( 72 icon_urls, icon_type, desired_size_in_dip, 73 FaviconUtil::GetFaviconScaleFactors(), callback_runner, tracker); 74 } else { 75 return RunWithEmptyResultAsync(callback_runner, tracker); 76 } 77} 78 79CancelableTaskTracker::TaskId FaviconService::GetRawFavicon( 80 const GURL& icon_url, 81 history::IconType icon_type, 82 int desired_size_in_dip, 83 ui::ScaleFactor desired_scale_factor, 84 const FaviconRawCallback& callback, 85 CancelableTaskTracker* tracker) { 86 FaviconResultsCallback callback_runner = 87 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults, 88 base::Unretained(this), 89 callback, desired_size_in_dip, desired_scale_factor); 90 91 if (history_service_) { 92 std::vector<GURL> icon_urls; 93 icon_urls.push_back(icon_url); 94 std::vector<ui::ScaleFactor> desired_scale_factors; 95 desired_scale_factors.push_back(desired_scale_factor); 96 97 return history_service_->GetFavicons( 98 icon_urls, icon_type, desired_size_in_dip, desired_scale_factors, 99 callback_runner, tracker); 100 } else { 101 return RunWithEmptyResultAsync(callback_runner, tracker); 102 } 103} 104 105CancelableTaskTracker::TaskId FaviconService::GetFavicon( 106 const GURL& icon_url, 107 history::IconType icon_type, 108 int desired_size_in_dip, 109 const FaviconResultsCallback& callback, 110 CancelableTaskTracker* tracker) { 111 if (history_service_) { 112 std::vector<GURL> icon_urls; 113 icon_urls.push_back(icon_url); 114 return history_service_->GetFavicons( 115 icon_urls, icon_type, desired_size_in_dip, 116 FaviconUtil::GetFaviconScaleFactors(), callback, tracker); 117 } else { 118 return RunWithEmptyResultAsync(callback, tracker); 119 } 120} 121 122CancelableTaskTracker::TaskId FaviconService::UpdateFaviconMappingsAndFetch( 123 const GURL& page_url, 124 const std::vector<GURL>& icon_urls, 125 int icon_types, 126 int desired_size_in_dip, 127 const FaviconResultsCallback& callback, 128 CancelableTaskTracker* tracker) { 129 if (history_service_) { 130 return history_service_->UpdateFaviconMappingsAndFetch( 131 page_url, icon_urls, icon_types, desired_size_in_dip, 132 FaviconUtil::GetFaviconScaleFactors(), callback, tracker); 133 } else { 134 return RunWithEmptyResultAsync(callback, tracker); 135 } 136} 137 138CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForURL( 139 const FaviconForURLParams& params, 140 const FaviconImageCallback& callback, 141 CancelableTaskTracker* tracker) { 142 return GetFaviconForURLImpl( 143 params, 144 FaviconUtil::GetFaviconScaleFactors(), 145 Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults, 146 base::Unretained(this), 147 callback, 148 params.desired_size_in_dip), 149 tracker); 150} 151 152CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForURL( 153 const FaviconForURLParams& params, 154 ui::ScaleFactor desired_scale_factor, 155 const FaviconRawCallback& callback, 156 CancelableTaskTracker* tracker) { 157 std::vector<ui::ScaleFactor> desired_scale_factors; 158 desired_scale_factors.push_back(desired_scale_factor); 159 return GetFaviconForURLImpl( 160 params, 161 desired_scale_factors, 162 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults, 163 base::Unretained(this), 164 callback, 165 params.desired_size_in_dip, 166 desired_scale_factor), 167 tracker); 168} 169 170CancelableTaskTracker::TaskId FaviconService::GetFaviconForURL( 171 const FaviconForURLParams& params, 172 const FaviconResultsCallback& callback, 173 CancelableTaskTracker* tracker) { 174 return GetFaviconForURLImpl(params, 175 FaviconUtil::GetFaviconScaleFactors(), 176 callback, 177 tracker); 178} 179 180CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID( 181 history::FaviconID favicon_id, 182 const FaviconRawCallback& callback, 183 CancelableTaskTracker* tracker) { 184 // Use 0 as |desired_size_in_dip| to get the largest bitmap for |favicon_id| 185 // without any resizing. 186 int desired_size_in_dip = 0; 187 ui::ScaleFactor desired_scale_factor = ui::SCALE_FACTOR_100P; 188 FaviconResultsCallback callback_runner = 189 Bind(&FaviconService::RunFaviconRawCallbackWithBitmapResults, 190 base::Unretained(this), 191 callback, desired_size_in_dip, desired_scale_factor); 192 193 if (history_service_) { 194 return history_service_->GetFaviconForID( 195 favicon_id, desired_size_in_dip, desired_scale_factor, 196 callback_runner, tracker); 197 } else { 198 return RunWithEmptyResultAsync(callback_runner, tracker); 199 } 200} 201 202void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) { 203 if (history_service_) 204 history_service_->SetFaviconsOutOfDateForPage(page_url); 205} 206 207void FaviconService::CloneFavicon(const GURL& old_page_url, 208 const GURL& new_page_url) { 209 if (history_service_) 210 history_service_->CloneFavicons(old_page_url, new_page_url); 211} 212 213void FaviconService::SetImportedFavicons( 214 const std::vector<ImportedFaviconUsage>& favicon_usage) { 215 if (history_service_) 216 history_service_->SetImportedFavicons(favicon_usage); 217} 218 219void FaviconService::MergeFavicon( 220 const GURL& page_url, 221 const GURL& icon_url, 222 history::IconType icon_type, 223 scoped_refptr<base::RefCountedMemory> bitmap_data, 224 const gfx::Size& pixel_size) { 225 if (history_service_) { 226 history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data, 227 pixel_size); 228 } 229} 230 231void FaviconService::SetFavicons( 232 const GURL& page_url, 233 const GURL& icon_url, 234 history::IconType icon_type, 235 const gfx::Image& image) { 236 if (!history_service_) 237 return; 238 239 gfx::ImageSkia image_skia = image.AsImageSkia(); 240 image_skia.EnsureRepsForSupportedScaleFactors(); 241 const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps(); 242 std::vector<history::FaviconBitmapData> favicon_bitmap_data; 243 for (size_t i = 0; i < image_reps.size(); ++i) { 244 scoped_refptr<base::RefCountedBytes> bitmap_data( 245 new base::RefCountedBytes()); 246 if (gfx::PNGCodec::EncodeBGRASkBitmap(image_reps[i].sk_bitmap(), 247 false, 248 &bitmap_data->data())) { 249 gfx::Size pixel_size(image_reps[i].pixel_width(), 250 image_reps[i].pixel_height()); 251 history::FaviconBitmapData bitmap_data_element; 252 bitmap_data_element.bitmap_data = bitmap_data; 253 bitmap_data_element.pixel_size = pixel_size; 254 bitmap_data_element.icon_url = icon_url; 255 256 favicon_bitmap_data.push_back(bitmap_data_element); 257 } 258 } 259 260 history_service_->SetFavicons(page_url, icon_type, favicon_bitmap_data); 261} 262 263FaviconService::~FaviconService() {} 264 265CancelableTaskTracker::TaskId FaviconService::GetFaviconForURLImpl( 266 const FaviconForURLParams& params, 267 const std::vector<ui::ScaleFactor>& desired_scale_factors, 268 const FaviconResultsCallback& callback, 269 CancelableTaskTracker* tracker) { 270 if (params.page_url.SchemeIs(chrome::kChromeUIScheme) || 271 params.page_url.SchemeIs(extensions::kExtensionScheme)) { 272 CancelableTaskTracker::IsCanceledCallback is_canceled_cb; 273 CancelableTaskTracker::TaskId id = 274 tracker->NewTrackedTaskId(&is_canceled_cb); 275 276 FaviconResultsCallback cancelable_cb = 277 Bind(&CancelOrRunFaviconResultsCallback, is_canceled_cb, callback); 278 ChromeWebUIControllerFactory::GetInstance()->GetFaviconForURL( 279 params.profile, params.page_url, desired_scale_factors, cancelable_cb); 280 return id; 281 } else if (history_service_) { 282 return history_service_->GetFaviconsForURL(params.page_url, 283 params.icon_types, 284 params.desired_size_in_dip, 285 desired_scale_factors, 286 callback, 287 tracker); 288 } else { 289 return RunWithEmptyResultAsync(callback, tracker); 290 } 291} 292 293void FaviconService::RunFaviconImageCallbackWithBitmapResults( 294 const FaviconImageCallback& callback, 295 int desired_size_in_dip, 296 const std::vector<history::FaviconBitmapResult>& favicon_bitmap_results) { 297 history::FaviconImageResult image_result; 298 image_result.image = FaviconUtil::SelectFaviconFramesFromPNGs( 299 favicon_bitmap_results, 300 FaviconUtil::GetFaviconScaleFactors(), 301 desired_size_in_dip); 302 image_result.icon_url = image_result.image.IsEmpty() ? 303 GURL() : favicon_bitmap_results[0].icon_url; 304 callback.Run(image_result); 305} 306 307void FaviconService::RunFaviconRawCallbackWithBitmapResults( 308 const FaviconRawCallback& callback, 309 int desired_size_in_dip, 310 ui::ScaleFactor desired_scale_factor, 311 const std::vector<history::FaviconBitmapResult>& favicon_bitmap_results) { 312 if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) { 313 callback.Run(history::FaviconBitmapResult()); 314 return; 315 } 316 317 DCHECK_EQ(1u, favicon_bitmap_results.size()); 318 history::FaviconBitmapResult bitmap_result = favicon_bitmap_results[0]; 319 320 // If the desired size is 0, SelectFaviconFrames() will return the largest 321 // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap 322 // data for a single bitmap, return it and avoid an unnecessary decode. 323 if (desired_size_in_dip == 0) { 324 callback.Run(bitmap_result); 325 return; 326 } 327 328 // If history bitmap is already desired pixel size, return early. 329 float desired_scale = ui::GetScaleFactorScale(desired_scale_factor); 330 int desired_edge_width_in_pixel = static_cast<int>( 331 desired_size_in_dip * desired_scale + 0.5f); 332 gfx::Size desired_size_in_pixel(desired_edge_width_in_pixel, 333 desired_edge_width_in_pixel); 334 if (bitmap_result.pixel_size == desired_size_in_pixel) { 335 callback.Run(bitmap_result); 336 return; 337 } 338 339 // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then 340 // convert back. 341 std::vector<ui::ScaleFactor> desired_scale_factors; 342 desired_scale_factors.push_back(desired_scale_factor); 343 gfx::Image resized_image = FaviconUtil::SelectFaviconFramesFromPNGs( 344 favicon_bitmap_results, desired_scale_factors, desired_size_in_dip); 345 346 std::vector<unsigned char> resized_bitmap_data; 347 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false, 348 &resized_bitmap_data)) { 349 callback.Run(history::FaviconBitmapResult()); 350 return; 351 } 352 353 bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector( 354 &resized_bitmap_data); 355 callback.Run(bitmap_result); 356} 357