favicon_service.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/favicon/favicon_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop_proxy.h"
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/favicon/favicon_util.h"
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/history/history_backend.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service_factory.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/history/select_favicon_frames.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/skia/include/core/SkBitmap.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Bind;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CancelOrRunFaviconResultsCallback(
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const CancelableTaskTracker::IsCanceledCallback& is_canceled,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FaviconService::FaviconResultsCallback& callback,
283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    const std::vector<history::FaviconBitmapResult>& results) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_canceled.Run())
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.Run(results);
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
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