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