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