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