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