summaryrefslogtreecommitdiffstats
path: root/components/favicon/core/favicon_service.cc
diff options
context:
space:
mode:
Diffstat (limited to 'components/favicon/core/favicon_service.cc')
-rw-r--r--components/favicon/core/favicon_service.cc391
1 files changed, 391 insertions, 0 deletions
diff --git a/components/favicon/core/favicon_service.cc b/components/favicon/core/favicon_service.cc
new file mode 100644
index 0000000..b455f1e
--- /dev/null
+++ b/components/favicon/core/favicon_service.cc
@@ -0,0 +1,391 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/favicon/core/favicon_service.h"
+
+#include <cmath>
+
+#include "base/hash.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "components/favicon/core/favicon_client.h"
+#include "components/favicon_base/favicon_util.h"
+#include "components/favicon_base/select_favicon_frames.h"
+#include "components/history/core/browser/history_service.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/favicon_size.h"
+#include "ui/gfx/image/image_skia.h"
+#include "url/gurl.h"
+
+using base::Bind;
+
+namespace {
+
+// Helper to run callback with empty results if we cannot get the history
+// service.
+base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync(
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ scoped_refptr<base::SingleThreadTaskRunner> thread_runner(
+ base::ThreadTaskRunnerHandle::Get());
+ return tracker->PostTask(
+ thread_runner.get(), FROM_HERE,
+ Bind(callback, std::vector<favicon_base::FaviconRawBitmapResult>()));
+}
+
+// Returns a vector of pixel edge sizes from |size_in_dip| and
+// favicon_base::GetFaviconScales().
+std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) {
+ std::vector<float> scales = favicon_base::GetFaviconScales();
+ std::vector<int> sizes_in_pixel;
+ for (size_t i = 0; i < scales.size(); ++i) {
+ sizes_in_pixel.push_back(std::ceil(size_in_dip * scales[i]));
+ }
+ return sizes_in_pixel;
+}
+
+} // namespace
+
+FaviconService::FaviconService(FaviconClient* favicon_client,
+ history::HistoryService* history_service)
+ : history_service_(history_service), favicon_client_(favicon_client) {
+}
+
+FaviconService::~FaviconService() {
+}
+
+// static
+void FaviconService::FaviconResultsCallbackRunner(
+ const favicon_base::FaviconResultsCallback& callback,
+ const std::vector<favicon_base::FaviconRawBitmapResult>* results) {
+ callback.Run(*results);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImage(
+ const GURL& icon_url,
+ const favicon_base::FaviconImageCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ favicon_base::FaviconResultsCallback callback_runner =
+ Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
+ base::Unretained(this), callback, gfx::kFaviconSize);
+ if (history_service_) {
+ std::vector<GURL> icon_urls;
+ icon_urls.push_back(icon_url);
+ return history_service_->GetFavicons(
+ icon_urls,
+ favicon_base::FAVICON,
+ GetPixelSizesForFaviconScales(gfx::kFaviconSize),
+ callback_runner,
+ tracker);
+ }
+ return RunWithEmptyResultAsync(callback_runner, tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetRawFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_pixel,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ favicon_base::FaviconResultsCallback callback_runner =
+ Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
+ base::Unretained(this),
+ callback,
+ desired_size_in_pixel);
+
+ if (history_service_) {
+ std::vector<GURL> icon_urls;
+ icon_urls.push_back(icon_url);
+ std::vector<int> desired_sizes_in_pixel;
+ desired_sizes_in_pixel.push_back(desired_size_in_pixel);
+
+ return history_service_->GetFavicons(
+ icon_urls, icon_type, desired_sizes_in_pixel, callback_runner, tracker);
+ }
+ return RunWithEmptyResultAsync(callback_runner, tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ if (history_service_) {
+ std::vector<GURL> icon_urls;
+ icon_urls.push_back(icon_url);
+ return history_service_->GetFavicons(
+ icon_urls,
+ icon_type,
+ GetPixelSizesForFaviconScales(desired_size_in_dip),
+ callback,
+ tracker);
+ }
+ return RunWithEmptyResultAsync(callback, tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetFaviconImageForPageURL(
+ const GURL& page_url,
+ const favicon_base::FaviconImageCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetFaviconForPageURLImpl(
+ page_url,
+ favicon_base::FAVICON,
+ GetPixelSizesForFaviconScales(gfx::kFaviconSize),
+ Bind(&FaviconService::RunFaviconImageCallbackWithBitmapResults,
+ base::Unretained(this),
+ callback,
+ gfx::kFaviconSize),
+ tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetRawFaviconForPageURL(
+ const GURL& page_url,
+ int icon_types,
+ int desired_size_in_pixel,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ std::vector<int> desired_sizes_in_pixel;
+ desired_sizes_in_pixel.push_back(desired_size_in_pixel);
+ return GetFaviconForPageURLImpl(
+ page_url,
+ icon_types,
+ desired_sizes_in_pixel,
+ Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
+ base::Unretained(this),
+ callback,
+ desired_size_in_pixel),
+ tracker);
+}
+
+base::CancelableTaskTracker::TaskId
+FaviconService::GetLargestRawFaviconForPageURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ favicon_base::FaviconResultsCallback favicon_results_callback =
+ Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
+ base::Unretained(this),
+ callback,
+ 0);
+ if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) {
+ std::vector<int> desired_sizes_in_pixel;
+ desired_sizes_in_pixel.push_back(0);
+ return favicon_client_->GetFaviconForNativeApplicationURL(
+ page_url, desired_sizes_in_pixel, favicon_results_callback, tracker);
+ }
+ if (history_service_) {
+ return history_service_->GetLargestFaviconForURL(page_url, icon_types,
+ minimum_size_in_pixels, callback, tracker);
+ }
+ return RunWithEmptyResultAsync(favicon_results_callback, tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL(
+ const GURL& page_url,
+ int icon_types,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ return GetFaviconForPageURLImpl(
+ page_url,
+ icon_types,
+ GetPixelSizesForFaviconScales(desired_size_in_dip),
+ callback,
+ tracker);
+}
+
+base::CancelableTaskTracker::TaskId
+FaviconService::UpdateFaviconMappingsAndFetch(
+ const GURL& page_url,
+ const std::vector<GURL>& icon_urls,
+ int icon_types,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ if (history_service_) {
+ return history_service_->UpdateFaviconMappingsAndFetch(
+ page_url,
+ icon_urls,
+ icon_types,
+ GetPixelSizesForFaviconScales(desired_size_in_dip),
+ callback,
+ tracker);
+ }
+ return RunWithEmptyResultAsync(callback, tracker);
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetLargestRawFaviconForID(
+ favicon_base::FaviconID favicon_id,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ // Use 0 as |desired_size| to get the largest bitmap for |favicon_id| without
+ // any resizing.
+ int desired_size = 0;
+ favicon_base::FaviconResultsCallback callback_runner =
+ Bind(&FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults,
+ base::Unretained(this),
+ callback,
+ desired_size);
+
+ if (history_service_) {
+ return history_service_->GetFaviconForID(
+ favicon_id, desired_size, callback_runner, tracker);
+ }
+ return RunWithEmptyResultAsync(callback_runner, tracker);
+}
+
+void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
+ if (history_service_)
+ history_service_->SetFaviconsOutOfDateForPage(page_url);
+}
+
+void FaviconService::CloneFavicon(const GURL& old_page_url,
+ const GURL& new_page_url) {
+ if (history_service_)
+ history_service_->CloneFavicons(old_page_url, new_page_url);
+}
+
+void FaviconService::SetImportedFavicons(
+ const favicon_base::FaviconUsageDataList& favicon_usage) {
+ if (history_service_)
+ history_service_->SetImportedFavicons(favicon_usage);
+}
+
+void FaviconService::MergeFavicon(
+ const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ scoped_refptr<base::RefCountedMemory> bitmap_data,
+ const gfx::Size& pixel_size) {
+ if (history_service_) {
+ history_service_->MergeFavicon(page_url, icon_url, icon_type, bitmap_data,
+ pixel_size);
+ }
+}
+
+void FaviconService::SetFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image) {
+ if (!history_service_)
+ return;
+
+ gfx::ImageSkia image_skia = image.AsImageSkia();
+ image_skia.EnsureRepsForSupportedScales();
+ const std::vector<gfx::ImageSkiaRep>& image_reps = image_skia.image_reps();
+ std::vector<SkBitmap> bitmaps;
+ const std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ // Don't save if the scale isn't one of supported favicon scales.
+ if (std::find(favicon_scales.begin(),
+ favicon_scales.end(),
+ image_reps[i].scale()) == favicon_scales.end()) {
+ continue;
+ }
+ bitmaps.push_back(image_reps[i].sk_bitmap());
+ }
+ history_service_->SetFavicons(page_url, icon_type, icon_url, bitmaps);
+}
+
+void FaviconService::UnableToDownloadFavicon(const GURL& icon_url) {
+ MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
+ missing_favicon_urls_.insert(url_hash);
+}
+
+bool FaviconService::WasUnableToDownloadFavicon(const GURL& icon_url) const {
+ MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
+ return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
+}
+
+void FaviconService::ClearUnableToDownloadFavicons() {
+ missing_favicon_urls_.clear();
+}
+
+base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURLImpl(
+ const GURL& page_url,
+ int icon_types,
+ const std::vector<int>& desired_sizes_in_pixel,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ if (favicon_client_ && favicon_client_->IsNativeApplicationURL(page_url)) {
+ return favicon_client_->GetFaviconForNativeApplicationURL(
+ page_url, desired_sizes_in_pixel, callback, tracker);
+ }
+ if (history_service_) {
+ return history_service_->GetFaviconsForURL(page_url,
+ icon_types,
+ desired_sizes_in_pixel,
+ callback,
+ tracker);
+ }
+ return RunWithEmptyResultAsync(callback, tracker);
+}
+
+void FaviconService::RunFaviconImageCallbackWithBitmapResults(
+ const favicon_base::FaviconImageCallback& callback,
+ int desired_size_in_dip,
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results) {
+ favicon_base::FaviconImageResult image_result;
+ image_result.image = favicon_base::SelectFaviconFramesFromPNGs(
+ favicon_bitmap_results,
+ favicon_base::GetFaviconScales(),
+ desired_size_in_dip);
+ favicon_base::SetFaviconColorSpace(&image_result.image);
+
+ image_result.icon_url = image_result.image.IsEmpty() ?
+ GURL() : favicon_bitmap_results[0].icon_url;
+ callback.Run(image_result);
+}
+
+void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults(
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ int desired_size_in_pixel,
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results) {
+ if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid()) {
+ callback.Run(favicon_base::FaviconRawBitmapResult());
+ return;
+ }
+
+ favicon_base::FaviconRawBitmapResult bitmap_result =
+ favicon_bitmap_results[0];
+
+ // If the desired size is 0, SelectFaviconFrames() will return the largest
+ // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
+ // data for a single bitmap, return it and avoid an unnecessary decode.
+ if (desired_size_in_pixel == 0) {
+ callback.Run(bitmap_result);
+ return;
+ }
+
+ // If history bitmap is already desired pixel size, return early.
+ if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
+ bitmap_result.pixel_size.height() == desired_size_in_pixel) {
+ callback.Run(bitmap_result);
+ return;
+ }
+
+ // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
+ // convert back.
+ std::vector<float> desired_favicon_scales;
+ desired_favicon_scales.push_back(1.0f);
+ gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
+ favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
+
+ std::vector<unsigned char> resized_bitmap_data;
+ if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
+ &resized_bitmap_data)) {
+ callback.Run(favicon_base::FaviconRawBitmapResult());
+ return;
+ }
+
+ bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
+ &resized_bitmap_data);
+ callback.Run(bitmap_result);
+}