summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorsdefresne <sdefresne@chromium.org>2015-03-16 09:56:03 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-16 16:56:41 +0000
commitfee69b4b384e94f03cd7d4dadf3140dd91bb9029 (patch)
treedc8bfb0c7de3326ed467998f34a5427f3eacf60d /components
parentee5ad4b13cc36b7ee494bc2b04a356d73ad32e3a (diff)
downloadchromium_src-fee69b4b384e94f03cd7d4dadf3140dd91bb9029.zip
chromium_src-fee69b4b384e94f03cd7d4dadf3140dd91bb9029.tar.gz
chromium_src-fee69b4b384e94f03cd7d4dadf3140dd91bb9029.tar.bz2
Componentize FaviconService and FaviconHandler
Move FaviconService and FaviconHandler into //components/favicon/core/browser as they have no problematic dependencies anymore. Update DEPS and dependencies of favicon component. BUG=359514,359513 Review URL: https://codereview.chromium.org/983043003 Cr-Commit-Position: refs/heads/master@{#320738}
Diffstat (limited to 'components')
-rw-r--r--components/BUILD.gn5
-rw-r--r--components/components.gyp2
-rw-r--r--components/favicon.gypi30
-rw-r--r--components/favicon/DEPS3
-rw-r--r--components/favicon/core/BUILD.gn3
-rw-r--r--components/favicon/core/browser/BUILD.gn25
-rw-r--r--components/favicon/core/browser/DEPS7
-rw-r--r--components/favicon/core/browser/favicon_handler.cc693
-rw-r--r--components/favicon/core/browser/favicon_handler.h309
-rw-r--r--components/favicon/core/browser/favicon_service.cc391
-rw-r--r--components/favicon/core/browser/favicon_service.h254
-rw-r--r--components/favicon/core/browser/favicon_tab_helper_observer.h24
12 files changed, 1737 insertions, 9 deletions
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 12e023a..ed5b887 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -38,7 +38,7 @@ group("all_components") {
"//components/dom_distiller/core",
"//components/domain_reliability",
"//components/enhanced_bookmarks",
- "//components/favicon/core",
+ "//components/favicon/core/browser",
"//components/favicon_base",
"//components/feedback",
"//components/gcm_driver",
@@ -162,8 +162,9 @@ group("all_components") {
"//components/data_reduction_proxy/core/common", # Should work, needs checking.
"//components/dom_distiller/core", # Blocked on content.
"//components/domain_reliability", # Blocked on content.
+ "//components/favicon/core/browser", # Blocked on keyed service.
"//components/favicon_base", # Should work, needs checking.
- "//components/favicon/core", # Blocked on keyed service.
+ "//components/feedback", # Blocked on content.
"//components/gcm_driver", # Should work, needs checking.
"//components/google/core/browser", # Should work, needs checking.
"//components/history/core/browser", # Should work, needs checking.
diff --git a/components/components.gyp b/components/components.gyp
index bbf2571..5160960 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -27,7 +27,6 @@
'domain_reliability.gypi',
'enhanced_bookmarks.gypi',
'error_page.gypi',
- 'favicon.gypi',
'favicon_base.gypi',
'feedback.gypi',
'google.gypi',
@@ -129,6 +128,7 @@
# Android WebView fails to build if a dependency on these targets is
# introduced.
'includes': [
+ 'favicon.gypi',
'gcm_driver.gypi',
'history.gypi',
'omnibox.gypi',
diff --git a/components/favicon.gypi b/components/favicon.gypi
index 262bd2b4..09a78f2 100644
--- a/components/favicon.gypi
+++ b/components/favicon.gypi
@@ -10,12 +10,11 @@
'type': 'static_library',
'dependencies': [
'../ui/gfx/gfx.gyp:gfx_geometry',
+ '../url/url.gyp:url_lib',
'favicon_base',
- 'keyed_service_core',
],
'sources': [
# Note: sources list duplicated in GN build.
- 'favicon/core/browser/favicon_client.h',
'favicon/core/favicon_driver.h',
'favicon/core/favicon_url.cc',
'favicon/core/favicon_url.h',
@@ -24,5 +23,32 @@
'..',
],
},
+ {
+ # GN version: //components/favicon/core/browser
+ 'target_name': 'favicon_core_browser',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../skia/skia.gyp:skia',
+ '../ui/gfx/gfx.gyp:gfx',
+ '../url/url.gyp:url_lib',
+ 'bookmarks_browser',
+ 'favicon_base',
+ 'favicon_core',
+ 'history_core_browser',
+ 'keyed_service_core',
+ ],
+ 'sources': [
+ # Note: sources list duplicated in GN build.
+ 'favicon/core/browser/favicon_client.h',
+ 'favicon/core/browser/favicon_handler.cc',
+ 'favicon/core/browser/favicon_handler.h',
+ 'favicon/core/browser/favicon_service.cc',
+ 'favicon/core/browser/favicon_service.h',
+ 'favicon/core/browser/favicon_tab_helper_observer.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ },
],
}
diff --git a/components/favicon/DEPS b/components/favicon/DEPS
index 9b38a85..b6ea2b3 100644
--- a/components/favicon/DEPS
+++ b/components/favicon/DEPS
@@ -1,5 +1,4 @@
include_rules = [
"+components/favicon_base",
- "+components/keyed_service/core",
- "+ui/gfx/geometry",
+ "+ui/gfx",
]
diff --git a/components/favicon/core/BUILD.gn b/components/favicon/core/BUILD.gn
index 0f834cb..05bd40b 100644
--- a/components/favicon/core/BUILD.gn
+++ b/components/favicon/core/BUILD.gn
@@ -4,7 +4,6 @@
static_library("core") {
sources = [
- "browser/favicon_client.h",
"favicon_driver.h",
"favicon_url.cc",
"favicon_url.h",
@@ -12,7 +11,7 @@ static_library("core") {
deps = [
"//components/favicon_base",
- "//components/keyed_service/core",
"//ui/gfx/geometry",
+ "//url",
]
}
diff --git a/components/favicon/core/browser/BUILD.gn b/components/favicon/core/browser/BUILD.gn
new file mode 100644
index 0000000..22e1246
--- /dev/null
+++ b/components/favicon/core/browser/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2015 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.
+
+static_library("browser") {
+ sources = [
+ "favicon_client.h",
+ "favicon_handler.cc",
+ "favicon_handler.h",
+ "favicon_service.cc",
+ "favicon_service.h",
+ "favicon_tab_helper_observer.h",
+ ]
+
+ deps = [
+ "//components/bookmarks/browser",
+ "//components/favicon/core",
+ "//components/favicon_base",
+ "//components/history/core/browser",
+ "//components/keyed_service/core",
+ "//skia",
+ "//ui/gfx",
+ "//url",
+ ]
+}
diff --git a/components/favicon/core/browser/DEPS b/components/favicon/core/browser/DEPS
new file mode 100644
index 0000000..8a86e5b
--- /dev/null
+++ b/components/favicon/core/browser/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+components/bookmarks/browser",
+ "+components/history/core/browser",
+ "+components/keyed_service/core",
+ "+skia",
+ "+third_party/skia",
+]
diff --git a/components/favicon/core/browser/favicon_handler.cc b/components/favicon/core/browser/favicon_handler.cc
new file mode 100644
index 0000000..1cff52c
--- /dev/null
+++ b/components/favicon/core/browser/favicon_handler.cc
@@ -0,0 +1,693 @@
+// 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/browser/favicon_handler.h"
+
+#include <algorithm>
+#include <cmath>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ref_counted_memory.h"
+#include "build/build_config.h"
+#include "components/favicon/core/browser/favicon_client.h"
+#include "components/favicon/core/browser/favicon_service.h"
+#include "components/favicon/core/favicon_driver.h"
+#include "components/favicon_base/favicon_util.h"
+#include "components/favicon_base/select_favicon_frames.h"
+#include "skia/ext/image_operations.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_util.h"
+
+using favicon::FaviconURL;
+
+namespace {
+
+// Size (along each axis) of a touch icon. This currently corresponds to
+// the apple touch icon for iPad.
+const int kTouchIconSize = 144;
+
+bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
+ const GURL& url,
+ favicon_base::IconType icon_type) {
+ return favicon_url.icon_url == url && favicon_url.icon_type == icon_type;
+}
+
+// Returns true if all of the icon URLs and icon types in |bitmap_results| are
+// identical and if they match the icon URL and icon type in |favicon_url|.
+// Returns false if |bitmap_results| is empty.
+bool DoUrlsAndIconsMatch(
+ const FaviconURL& favicon_url,
+ const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
+ if (bitmap_results.empty())
+ return false;
+
+ const favicon_base::IconType icon_type = favicon_url.icon_type;
+
+ for (const auto& bitmap_result : bitmap_results) {
+ if (favicon_url.icon_url != bitmap_result.icon_url ||
+ icon_type != bitmap_result.icon_type) {
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string UrlWithoutFragment(const GURL& gurl) {
+ GURL::Replacements replacements;
+ replacements.ClearRef();
+ return gurl.ReplaceComponents(replacements).spec();
+}
+
+bool UrlMatches(const GURL& gurl_a, const GURL& gurl_b) {
+ return UrlWithoutFragment(gurl_a) == UrlWithoutFragment(gurl_b);
+}
+
+// Return true if |bitmap_result| is expired.
+bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
+ return bitmap_result.expired;
+}
+
+// Return true if |bitmap_result| is valid.
+bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
+ return bitmap_result.is_valid();
+}
+
+// Returns true if at least one of the bitmaps in |bitmap_results| is expired or
+// if |bitmap_results| is missing favicons for |desired_size_in_dip| and one of
+// the scale factors in favicon_base::GetFaviconScales().
+bool HasExpiredOrIncompleteResult(
+ int desired_size_in_dip,
+ const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
+ // Check if at least one of the bitmaps is expired.
+ std::vector<favicon_base::FaviconRawBitmapResult>::const_iterator it =
+ std::find_if(bitmap_results.begin(), bitmap_results.end(), IsExpired);
+ if (it != bitmap_results.end())
+ return true;
+
+ // Any favicon size is good if the desired size is 0.
+ if (desired_size_in_dip == 0)
+ return false;
+
+ // Check if the favicon for at least one of the scale factors is missing.
+ // |bitmap_results| should always be complete for data inserted by
+ // FaviconHandler as the FaviconHandler stores favicons resized to all
+ // of favicon_base::GetFaviconScales() into the history backend.
+ // Examples of when |bitmap_results| can be incomplete:
+ // - Favicons inserted into the history backend by sync.
+ // - Favicons for imported bookmarks.
+ std::vector<gfx::Size> favicon_sizes;
+ for (const auto& bitmap_result : bitmap_results)
+ favicon_sizes.push_back(bitmap_result.pixel_size);
+
+ std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
+ for (float favicon_scale : favicon_scales) {
+ int edge_size_in_pixel = std::ceil(desired_size_in_dip * favicon_scale);
+ auto it = std::find(favicon_sizes.begin(), favicon_sizes.end(),
+ gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
+ if (it == favicon_sizes.end())
+ return true;
+ }
+ return false;
+}
+
+// Returns true if at least one of |bitmap_results| is valid.
+bool HasValidResult(
+ const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
+ return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
+ bitmap_results.end();
+}
+
+// Returns the index of the entry with the largest area.
+int GetLargestSizeIndex(const std::vector<gfx::Size>& sizes) {
+ DCHECK(!sizes.empty());
+ size_t ret = 0;
+ for (size_t i = 1; i < sizes.size(); ++i) {
+ if (sizes[ret].GetArea() < sizes[i].GetArea())
+ ret = i;
+ }
+ return static_cast<int>(ret);
+}
+
+// Return the index of a size which is same as the given |size|, -1 returned if
+// there is no such bitmap.
+int GetIndexBySize(const std::vector<gfx::Size>& sizes,
+ const gfx::Size& size) {
+ DCHECK(!sizes.empty());
+ std::vector<gfx::Size>::const_iterator i =
+ std::find(sizes.begin(), sizes.end(), size);
+ if (i == sizes.end())
+ return -1;
+
+ return static_cast<int>(i - sizes.begin());
+}
+
+// Compare function used for std::stable_sort to sort as descend.
+bool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
+ int area1 = 0;
+ if (!b1.icon_sizes.empty())
+ area1 = b1.icon_sizes.front().GetArea();
+
+ int area2 = 0;
+ if (!b2.icon_sizes.empty())
+ area2 = b2.icon_sizes.front().GetArea();
+
+ return area1 > area2;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
+FaviconHandler::DownloadRequest::DownloadRequest()
+ : icon_type(favicon_base::INVALID_ICON) {
+}
+
+FaviconHandler::DownloadRequest::~DownloadRequest() {
+}
+
+FaviconHandler::DownloadRequest::DownloadRequest(
+ const GURL& url,
+ const GURL& image_url,
+ favicon_base::IconType icon_type)
+ : url(url), image_url(image_url), icon_type(icon_type) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+FaviconHandler::FaviconCandidate::FaviconCandidate()
+ : score(0), icon_type(favicon_base::INVALID_ICON) {
+}
+
+FaviconHandler::FaviconCandidate::~FaviconCandidate() {
+}
+
+FaviconHandler::FaviconCandidate::FaviconCandidate(
+ const GURL& url,
+ const GURL& image_url,
+ const gfx::Image& image,
+ float score,
+ favicon_base::IconType icon_type)
+ : url(url),
+ image_url(image_url),
+ image(image),
+ score(score),
+ icon_type(icon_type) {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+FaviconHandler::FaviconHandler(FaviconService* service,
+ FaviconClient* client,
+ FaviconDriver* driver,
+ Type icon_type,
+ bool download_largest_icon)
+ : got_favicon_from_history_(false),
+ favicon_expired_or_incomplete_(false),
+ icon_types_(icon_type == FAVICON
+ ? favicon_base::FAVICON
+ : favicon_base::TOUCH_ICON |
+ favicon_base::TOUCH_PRECOMPOSED_ICON),
+ download_largest_icon_(download_largest_icon),
+ service_(service),
+ client_(client),
+ driver_(driver) {
+ DCHECK(driver_);
+}
+
+FaviconHandler::~FaviconHandler() {
+}
+
+void FaviconHandler::FetchFavicon(const GURL& url) {
+ cancelable_task_tracker_.TryCancelAll();
+
+ url_ = url;
+
+ favicon_expired_or_incomplete_ = got_favicon_from_history_ = false;
+ image_urls_.clear();
+
+ // Request the favicon from the history service. In parallel to this the
+ // renderer is going to notify us (well WebContents) when the favicon url is
+ // available.
+ GetFaviconForURLFromFaviconService(
+ url_, icon_types_,
+ base::Bind(&FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
+ base::Unretained(this)),
+ &cancelable_task_tracker_);
+}
+
+bool FaviconHandler::UpdateFaviconCandidate(const GURL& url,
+ const GURL& image_url,
+ const gfx::Image& image,
+ float score,
+ favicon_base::IconType icon_type) {
+ bool replace_best_favicon_candidate = false;
+ bool exact_match = false;
+ if (download_largest_icon_) {
+ replace_best_favicon_candidate =
+ image.Size().GetArea() >
+ best_favicon_candidate_.image.Size().GetArea();
+
+ gfx::Size largest = best_favicon_candidate_.image.Size();
+ if (replace_best_favicon_candidate)
+ largest = image.Size();
+
+ // The size of the downloaded icon may not match the declared size. Stop
+ // downloading if:
+ // - current candidate is only candidate.
+ // - next candidate doesn't have sizes attributes, in this case, the rest
+ // candidates don't have sizes attribute either, stop downloading now,
+ // otherwise, all favicon without sizes attribute are downloaded.
+ // - next candidate has sizes attribute and it is not larger than largest,
+ // - current candidate is maximal one we want.
+ const int maximal_size = GetMaximalIconSize(icon_type);
+ exact_match = image_urls_.size() == 1 ||
+ image_urls_[1].icon_sizes.empty() ||
+ image_urls_[1].icon_sizes[0].GetArea() <= largest.GetArea() ||
+ (image.Size().width() == maximal_size &&
+ image.Size().height() == maximal_size);
+ } else {
+ exact_match = score == 1 || preferred_icon_size() == 0;
+ replace_best_favicon_candidate =
+ exact_match ||
+ best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
+ score > best_favicon_candidate_.score;
+ }
+ if (replace_best_favicon_candidate) {
+ best_favicon_candidate_ = FaviconCandidate(
+ url, image_url, image, score, icon_type);
+ }
+ return exact_match;
+}
+
+void FaviconHandler::SetFavicon(const GURL& url,
+ const GURL& icon_url,
+ const gfx::Image& image,
+ favicon_base::IconType icon_type) {
+ if (ShouldSaveFavicon(url))
+ SetHistoryFavicons(url, icon_url, icon_type, image);
+
+ if (!UrlMatches(url, url_) || PageChangedSinceFaviconWasRequested())
+ return;
+
+ NotifyFaviconAvailable(
+ icon_url,
+ image,
+ icon_type == favicon_base::FAVICON && !download_largest_icon_);
+}
+
+void FaviconHandler::NotifyFaviconAvailable(
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results,
+ bool is_active_favicon) {
+ gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
+ favicon_bitmap_results,
+ favicon_base::GetFaviconScales(),
+ preferred_icon_size());
+ // The history service sends back results for a single icon URL, so it does
+ // not matter which result we get the |icon_url| from.
+ const GURL icon_url = favicon_bitmap_results.empty() ?
+ GURL() : favicon_bitmap_results[0].icon_url;
+ NotifyFaviconAvailable(icon_url, resized_image, is_active_favicon);
+}
+
+void FaviconHandler::NotifyFaviconAvailable(const GURL& icon_url,
+ const gfx::Image& image,
+ bool is_active_favicon) {
+ gfx::Image image_with_adjusted_colorspace = image;
+ favicon_base::SetFaviconColorSpace(&image_with_adjusted_colorspace);
+
+ driver_->OnFaviconAvailable(
+ image_with_adjusted_colorspace, icon_url, is_active_favicon);
+}
+
+void FaviconHandler::OnUpdateFaviconURL(
+ const std::vector<FaviconURL>& candidates) {
+ image_urls_.clear();
+ best_favicon_candidate_ = FaviconCandidate();
+ for (const FaviconURL& candidate : candidates) {
+ if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_))
+ image_urls_.push_back(candidate);
+ }
+
+ if (download_largest_icon_)
+ SortAndPruneImageUrls();
+
+ // TODO(davemoore) Should clear on empty url. Currently we ignore it.
+ // This appears to be what FF does as well.
+ if (!image_urls_.empty())
+ ProcessCurrentUrl();
+}
+
+void FaviconHandler::ProcessCurrentUrl() {
+ DCHECK(!image_urls_.empty());
+
+ // current_candidate() may return NULL if download_largest_icon_ is true and
+ // all the sizes are larger than the max.
+ if (PageChangedSinceFaviconWasRequested() || !current_candidate())
+ return;
+
+ if (current_candidate()->icon_type == favicon_base::FAVICON &&
+ !download_largest_icon_) {
+ if (!favicon_expired_or_incomplete_ &&
+ driver_->GetActiveFaviconValidity() &&
+ DoUrlAndIconMatch(*current_candidate(),
+ driver_->GetActiveFaviconURL(),
+ favicon_base::FAVICON))
+ return;
+ } else if (!favicon_expired_or_incomplete_ && got_favicon_from_history_ &&
+ HasValidResult(history_results_) &&
+ DoUrlsAndIconsMatch(*current_candidate(), history_results_)) {
+ return;
+ }
+
+ if (got_favicon_from_history_)
+ DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
+ current_candidate()->icon_url,
+ current_candidate()->icon_type);
+}
+
+void FaviconHandler::OnDidDownloadFavicon(
+ int id,
+ const GURL& image_url,
+ const std::vector<SkBitmap>& bitmaps,
+ const std::vector<gfx::Size>& original_bitmap_sizes) {
+ DownloadRequests::iterator i = download_requests_.find(id);
+ if (i == download_requests_.end()) {
+ // Currently WebContents notifies us of ANY downloads so that it is
+ // possible to get here.
+ return;
+ }
+
+ DownloadRequest download_request = i->second;
+ download_requests_.erase(i);
+
+ if (current_candidate() &&
+ DoUrlAndIconMatch(*current_candidate(),
+ image_url,
+ download_request.icon_type)) {
+ bool request_next_icon = true;
+ float score = 0.0f;
+ gfx::ImageSkia image_skia;
+ if (download_largest_icon_ && !bitmaps.empty()) {
+ int index = -1;
+ // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
+ if (current_candidate()->icon_sizes.empty()) {
+ index = GetLargestSizeIndex(original_bitmap_sizes);
+ } else {
+ index = GetIndexBySize(original_bitmap_sizes,
+ current_candidate()->icon_sizes[0]);
+ // Find largest bitmap if there is no one exactly matched.
+ if (index == -1)
+ index = GetLargestSizeIndex(original_bitmap_sizes);
+ }
+ image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
+ } else {
+ image_skia = CreateFaviconImageSkia(bitmaps,
+ original_bitmap_sizes,
+ preferred_icon_size(),
+ &score);
+ }
+
+ if (!image_skia.isNull()) {
+ gfx::Image image(image_skia);
+ // The downloaded icon is still valid when there is no FaviconURL update
+ // during the downloading.
+ if (!bitmaps.empty()) {
+ request_next_icon = !UpdateFaviconCandidate(
+ download_request.url, image_url, image, score,
+ download_request.icon_type);
+ }
+ }
+ if (request_next_icon && !PageChangedSinceFaviconWasRequested() &&
+ image_urls_.size() > 1) {
+ // Remove the first member of image_urls_ and process the remaining.
+ image_urls_.erase(image_urls_.begin());
+ ProcessCurrentUrl();
+ } else if (best_favicon_candidate_.icon_type !=
+ favicon_base::INVALID_ICON) {
+ // No more icons to request, set the favicon from the candidate.
+ SetFavicon(best_favicon_candidate_.url,
+ best_favicon_candidate_.image_url,
+ best_favicon_candidate_.image,
+ best_favicon_candidate_.icon_type);
+ // Reset candidate.
+ image_urls_.clear();
+ download_requests_.clear();
+ best_favicon_candidate_ = FaviconCandidate();
+ }
+ }
+}
+
+bool FaviconHandler::PageChangedSinceFaviconWasRequested() {
+ if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) {
+ return false;
+ }
+ // If the URL has changed out from under us (as will happen with redirects)
+ // return true.
+ return true;
+}
+
+int FaviconHandler::DownloadFavicon(const GURL& image_url,
+ int max_bitmap_size) {
+ if (!image_url.is_valid()) {
+ NOTREACHED();
+ return 0;
+ }
+ return driver_->StartDownload(image_url, max_bitmap_size);
+}
+
+void FaviconHandler::UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ // TODO(pkotwicz): pass in all of |image_urls_| to
+ // UpdateFaviconMappingsAndFetch().
+ if (service_) {
+ std::vector<GURL> icon_urls;
+ icon_urls.push_back(icon_url);
+ service_->UpdateFaviconMappingsAndFetch(page_url, icon_urls, icon_type,
+ preferred_icon_size(), callback,
+ tracker);
+ }
+}
+
+void FaviconHandler::GetFaviconFromFaviconService(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ if (service_) {
+ service_->GetFavicon(icon_url, icon_type, preferred_icon_size(), callback,
+ tracker);
+ }
+}
+
+void FaviconHandler::GetFaviconForURLFromFaviconService(
+ const GURL& page_url,
+ int icon_types,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker) {
+ if (service_) {
+ service_->GetFaviconForPageURL(page_url, icon_types, preferred_icon_size(),
+ callback, tracker);
+ }
+}
+
+void FaviconHandler::SetHistoryFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image) {
+ if (service_) {
+ service_->SetFavicons(page_url, icon_url, icon_type, image);
+ }
+}
+
+bool FaviconHandler::ShouldSaveFavicon(const GURL& url) {
+ if (!driver_->IsOffTheRecord())
+ return true;
+
+ // Otherwise store the favicon if the page is bookmarked.
+ return client_->IsBookmarked(url);
+}
+
+int FaviconHandler::GetMaximalIconSize(favicon_base::IconType icon_type) {
+ switch (icon_type) {
+ case favicon_base::FAVICON:
+#if defined(OS_ANDROID)
+ return 192;
+#else
+ return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
+#endif
+ case favicon_base::TOUCH_ICON:
+ case favicon_base::TOUCH_PRECOMPOSED_ICON:
+ return kTouchIconSize;
+ case favicon_base::INVALID_ICON:
+ return 0;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results) {
+ if (PageChangedSinceFaviconWasRequested())
+ return;
+ got_favicon_from_history_ = true;
+ history_results_ = favicon_bitmap_results;
+ bool has_results = !favicon_bitmap_results.empty();
+ favicon_expired_or_incomplete_ = has_results && HasExpiredOrIncompleteResult(
+ preferred_icon_size(), favicon_bitmap_results);
+ bool has_valid_result = HasValidResult(favicon_bitmap_results);
+
+ if (has_results && icon_types_ == favicon_base::FAVICON &&
+ !download_largest_icon_ && !driver_->GetActiveFaviconValidity() &&
+ (!current_candidate() ||
+ DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
+ if (has_valid_result) {
+ // The db knows the favicon (although it may be out of date) and the entry
+ // doesn't have an icon. Set the favicon now, and if the favicon turns out
+ // to be expired (or the wrong url) we'll fetch later on. This way the
+ // user doesn't see a flash of the default favicon.
+ NotifyFaviconAvailable(favicon_bitmap_results, true);
+ } else {
+ // If |favicon_bitmap_results| does not have any valid results, treat the
+ // favicon as if it's expired.
+ // TODO(pkotwicz): Do something better.
+ favicon_expired_or_incomplete_ = true;
+ }
+ }
+ if (has_results && !favicon_expired_or_incomplete_) {
+ if (current_candidate() &&
+ !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)) {
+ // Mapping in the database is wrong. DownloadFavIconOrAskHistory will
+ // update the mapping for this url and download the favicon if we don't
+ // already have it.
+ DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
+ current_candidate()->icon_url,
+ current_candidate()->icon_type);
+ }
+ } else if (current_candidate()) {
+ // We know the official url for the favicon, but either don't have the
+ // favicon or it's expired. Continue on to DownloadFaviconOrAskHistory to
+ // either download or check history again.
+ DownloadFaviconOrAskFaviconService(driver_->GetActiveURL(),
+ current_candidate()->icon_url,
+ current_candidate()->icon_type);
+ }
+ // else we haven't got the icon url. When we get it we'll ask the
+ // renderer to download the icon.
+
+ if (has_valid_result &&
+ (icon_types_ != favicon_base::FAVICON || download_largest_icon_))
+ NotifyFaviconAvailable(favicon_bitmap_results, false);
+}
+
+void FaviconHandler::DownloadFaviconOrAskFaviconService(
+ const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type) {
+ if (favicon_expired_or_incomplete_) {
+ // We have the mapping, but the favicon is out of date. Download it now.
+ ScheduleDownload(page_url, icon_url, icon_type);
+ } else {
+ // We don't know the favicon, but we may have previously downloaded the
+ // favicon for another page that shares the same favicon. Ask for the
+ // favicon given the favicon URL.
+ if (driver_->IsOffTheRecord()) {
+ GetFaviconFromFaviconService(
+ icon_url, icon_type,
+ base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
+ &cancelable_task_tracker_);
+ } else {
+ // Ask the history service for the icon. This does two things:
+ // 1. Attempts to fetch the favicon data from the database.
+ // 2. If the favicon exists in the database, this updates the database to
+ // include the mapping between the page url and the favicon url.
+ // This is asynchronous. The history service will call back when done.
+ UpdateFaviconMappingAndFetch(
+ page_url, icon_url, icon_type,
+ base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
+ &cancelable_task_tracker_);
+ }
+ }
+}
+
+void FaviconHandler::OnFaviconData(const std::vector<
+ favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
+ if (PageChangedSinceFaviconWasRequested())
+ return;
+
+ bool has_results = !favicon_bitmap_results.empty();
+ bool has_expired_or_incomplete_result = HasExpiredOrIncompleteResult(
+ preferred_icon_size(), favicon_bitmap_results);
+ bool has_valid_result = HasValidResult(favicon_bitmap_results);
+
+ if (has_results && icon_types_ == favicon_base::FAVICON &&
+ !download_largest_icon_) {
+ if (has_valid_result) {
+ // There is a favicon, set it now. If expired we'll download the current
+ // one again, but at least the user will get some icon instead of the
+ // default and most likely the current one is fine anyway.
+ NotifyFaviconAvailable(favicon_bitmap_results, true);
+ }
+ if (has_expired_or_incomplete_result) {
+ // The favicon is out of date. Request the current one.
+ ScheduleDownload(driver_->GetActiveURL(),
+ driver_->GetActiveFaviconURL(),
+ favicon_base::FAVICON);
+ }
+ } else if (current_candidate() &&
+ (!has_results || has_expired_or_incomplete_result ||
+ !(DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results)))) {
+ // We don't know the favicon, it is out of date or its type is not same as
+ // one got from page. Request the current one.
+ ScheduleDownload(driver_->GetActiveURL(),
+ current_candidate()->icon_url,
+ current_candidate()->icon_type);
+ }
+ history_results_ = favicon_bitmap_results;
+
+ if (has_valid_result &&
+ (icon_types_ != favicon_base::FAVICON || download_largest_icon_)) {
+ NotifyFaviconAvailable(favicon_bitmap_results, false);
+ }
+}
+
+int FaviconHandler::ScheduleDownload(const GURL& url,
+ const GURL& image_url,
+ favicon_base::IconType icon_type) {
+ // A max bitmap size is specified to avoid receiving huge bitmaps in
+ // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
+ // for more details about the max bitmap size.
+ const int download_id = DownloadFavicon(image_url,
+ GetMaximalIconSize(icon_type));
+ if (download_id) {
+ // Download ids should be unique.
+ DCHECK(download_requests_.find(download_id) == download_requests_.end());
+ download_requests_[download_id] =
+ DownloadRequest(url, image_url, icon_type);
+ }
+
+ return download_id;
+}
+
+void FaviconHandler::SortAndPruneImageUrls() {
+ // Not using const-reference since the loop mutates FaviconURL::icon_sizes.
+ for (favicon::FaviconURL& image_url : image_urls_) {
+ if (image_url.icon_sizes.empty())
+ continue;
+
+ gfx::Size largest =
+ image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)];
+ image_url.icon_sizes.clear();
+ image_url.icon_sizes.push_back(largest);
+ }
+ std::stable_sort(image_urls_.begin(), image_urls_.end(),
+ CompareIconSize);
+}
diff --git a/components/favicon/core/browser/favicon_handler.h b/components/favicon/core/browser/favicon_handler.h
new file mode 100644
index 0000000..5d890c0
--- /dev/null
+++ b/components/favicon/core/browser/favicon_handler.h
@@ -0,0 +1,309 @@
+// 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.
+
+#ifndef COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_HANDLER_H_
+#define COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_HANDLER_H_
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "components/favicon/core/favicon_url.h"
+#include "components/favicon_base/favicon_callback.h"
+#include "ui/gfx/favicon_size.h"
+#include "ui/gfx/image/image.h"
+#include "url/gurl.h"
+
+class FaviconClient;
+class FaviconDriver;
+class FaviconService;
+class SkBitmap;
+
+namespace base {
+class RefCountedMemory;
+}
+
+// FaviconHandler works with FaviconDriver to fetch the specific type of
+// favicon.
+//
+// FetchFavicon requests the favicon from the favicon service which in turn
+// requests the favicon from the history database. At this point
+// we only know the URL of the page, and not necessarily the url of the
+// favicon. To ensure we handle reloading stale favicons as well as
+// reloading a favicon on page reload we always request the favicon from
+// history regardless of whether the active favicon is valid.
+//
+// After the navigation two types of events are delivered (which is
+// first depends upon who is faster): notification from the history
+// db on our request for the favicon
+// (OnFaviconDataForInitialURLFromFaviconService), or a message from the
+// renderer giving us the URL of the favicon for the page (SetFaviconURL).
+// . If the history db has a valid up to date favicon for the page, we update
+// the current page and use the favicon.
+// . When we receive the favicon url if it matches that of the current page
+// and the current page's favicon is set, we do nothing (everything is
+// ok).
+// . On the other hand if the database does not know the favicon for url, or
+// the favicon is out date, or the URL from the renderer does not match that
+// of the current page we proceed to DownloadFaviconOrAskHistory. Before we
+// invoke DownloadFaviconOrAskHistory we wait until we've received both
+// the favicon url and the callback from history. We wait to ensure we
+// truly know both the favicon url and the state of the database.
+//
+// DownloadFaviconOrAskHistory does the following:
+// . If we have a valid favicon, but it is expired we ask the renderer to
+// download the favicon.
+// . Otherwise we ask the history database to update the mapping from
+// page url to favicon url and call us back with the favicon. Remember, it is
+// possible for the db to already have the favicon, just not the mapping
+// between page to favicon url. The callback for this is OnFaviconData.
+//
+// OnFaviconData either updates the favicon of the current page (if the
+// db knew about the favicon), or requests the renderer to download the
+// favicon.
+//
+// When the renderer downloads favicons, it considers the entire list of
+// favicon candidates, if |download_largest_favicon_| is true, the largest
+// favicon will be used, otherwise the one that best matches the preferred size
+// is chosen (or the first one if there is no preferred size). Once the
+// matching favicon has been determined, SetFavicon is called which updates
+// the page's favicon and notifies the database to save the favicon.
+
+class FaviconHandler {
+ public:
+ enum Type { FAVICON, TOUCH };
+
+ FaviconHandler(FaviconService* service,
+ FaviconClient* client,
+ FaviconDriver* driver,
+ Type icon_type,
+ bool download_largest_icon);
+ virtual ~FaviconHandler();
+
+ // Initiates loading the favicon for the specified url.
+ void FetchFavicon(const GURL& url);
+
+ // Message Handler. Must be public, because also called from
+ // PrerenderContents. Collects the |image_urls| list.
+ void OnUpdateFaviconURL(const std::vector<favicon::FaviconURL>& candidates);
+
+ // Processes the current image_irls_ entry, requesting the image from the
+ // history / download service.
+ void ProcessCurrentUrl();
+
+ // Message handler for ImageHostMsg_DidDownloadImage. Called when the image
+ // at |image_url| has been downloaded.
+ // |bitmaps| is a list of all the frames of the image at |image_url|.
+ // |original_bitmap_sizes| are the sizes of |bitmaps| before they were resized
+ // to the maximum bitmap size passed to DownloadFavicon().
+ void OnDidDownloadFavicon(
+ int id,
+ const GURL& image_url,
+ const std::vector<SkBitmap>& bitmaps,
+ const std::vector<gfx::Size>& original_bitmap_sizes);
+
+ // For testing.
+ const std::vector<favicon::FaviconURL>& image_urls() const {
+ return image_urls_;
+ }
+
+ protected:
+ // These virtual methods make FaviconHandler testable and are overridden by
+ // TestFaviconHandler.
+
+ // Asks the render to download favicon, returns the request id.
+ virtual int DownloadFavicon(const GURL& image_url, int max_bitmap_size);
+
+ // Ask the favicon from history
+ virtual void UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ virtual void GetFaviconFromFaviconService(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ virtual void GetFaviconForURLFromFaviconService(
+ const GURL& page_url,
+ int icon_types,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ virtual void SetHistoryFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image);
+
+ // Returns true if the favicon should be saved.
+ virtual bool ShouldSaveFavicon(const GURL& url);
+
+ private:
+ // For testing:
+ friend class FaviconTabHelperTest;
+ friend class TestFaviconHandler;
+
+ // Represents an in progress download of an image from the renderer.
+ struct DownloadRequest {
+ DownloadRequest();
+ ~DownloadRequest();
+
+ DownloadRequest(const GURL& url,
+ const GURL& image_url,
+ favicon_base::IconType icon_type);
+
+ GURL url;
+ GURL image_url;
+ favicon_base::IconType icon_type;
+ };
+
+ // Used to track a candidate for the favicon.
+ struct FaviconCandidate {
+ FaviconCandidate();
+ ~FaviconCandidate();
+
+ FaviconCandidate(const GURL& url,
+ const GURL& image_url,
+ const gfx::Image& image,
+ float score,
+ favicon_base::IconType icon_type);
+
+ GURL url;
+ GURL image_url;
+ gfx::Image image;
+ float score;
+ favicon_base::IconType icon_type;
+ };
+
+ // Get the maximal icon size in pixels for a icon of type |icon_type| for the
+ // current platform.
+ static int GetMaximalIconSize(favicon_base::IconType icon_type);
+
+ // See description above class for details.
+ void OnFaviconDataForInitialURLFromFaviconService(const std::vector<
+ favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results);
+
+ // If the favicon has expired, asks the renderer to download the favicon.
+ // Otherwise asks history to update the mapping between page url and icon
+ // url with a callback to OnFaviconData when done.
+ void DownloadFaviconOrAskFaviconService(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type);
+
+ // See description above class for details.
+ void OnFaviconData(const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results);
+
+ // Schedules a download for the specified entry. This adds the request to
+ // download_requests_.
+ int ScheduleDownload(const GURL& url,
+ const GURL& image_url,
+ favicon_base::IconType icon_type);
+
+ // Updates |favicon_candidate_| and returns true if it is an exact match.
+ bool UpdateFaviconCandidate(const GURL& url,
+ const GURL& image_url,
+ const gfx::Image& image,
+ float score,
+ favicon_base::IconType icon_type);
+
+ // Sets the image data for the favicon.
+ void SetFavicon(const GURL& url,
+ const GURL& icon_url,
+ const gfx::Image& image,
+ favicon_base::IconType icon_type);
+
+ // Notifies |driver_| favicon available. See
+ // FaviconDriver::NotifyFaviconAvailable() for |is_active_favicon| in detail.
+ void NotifyFaviconAvailable(
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results,
+ bool is_active_favicon);
+ void NotifyFaviconAvailable(const GURL& icon_url,
+ const gfx::Image& image,
+ bool is_active_favicon);
+
+ // Return the current candidate if any.
+ favicon::FaviconURL* current_candidate() {
+ return (!image_urls_.empty()) ? &image_urls_.front() : NULL;
+ }
+
+ // Returns whether the page's url changed since the favicon was requested.
+ bool PageChangedSinceFaviconWasRequested();
+
+ // Returns the preferred size of the image. 0 means no preference (any size
+ // will do).
+ int preferred_icon_size() const {
+ if (download_largest_icon_)
+ return 0;
+ return icon_types_ == favicon_base::FAVICON ? gfx::kFaviconSize : 0;
+ }
+
+ // Sorts the entries in |image_urls_| by icon size in descending order.
+ // Additionally removes any entries whose sizes are all greater than the max
+ // allowed size.
+ void SortAndPruneImageUrls();
+
+ // Used for FaviconService requests.
+ base::CancelableTaskTracker cancelable_task_tracker_;
+
+ // URL of the page we're requesting the favicon for.
+ GURL url_;
+
+ // Whether we are waiting for data from the FaviconService.
+ bool waiting_for_favicon_service_data_;
+
+ // Whether we got data back for the initial request to the FaviconService.
+ bool got_favicon_from_history_;
+
+ // Whether the favicon is out of date or the favicon data in
+ // |history_results_| is known to be incomplete. If true, it means history
+ // knows about the favicon, but we need to download the favicon because the
+ // icon has expired or the data in the database is incomplete.
+ bool favicon_expired_or_incomplete_;
+
+ // Requests to the renderer to download favicons.
+ typedef std::map<int, DownloadRequest> DownloadRequests;
+ DownloadRequests download_requests_;
+
+ // The combination of the supported icon types.
+ const int icon_types_;
+
+ // Whether the largest icon should be downloaded.
+ const bool download_largest_icon_;
+
+ // The prioritized favicon candidates from the page back from the renderer.
+ std::vector<favicon::FaviconURL> image_urls_;
+
+ // The FaviconRawBitmapResults from history.
+ std::vector<favicon_base::FaviconRawBitmapResult> history_results_;
+
+ // The FaviconService which implements favicon operations. May be null during
+ // testing.
+ FaviconService* service_;
+
+ // The client which implements embedder-specific Favicon operations.
+ FaviconClient* client_; // weak
+
+ // This handler's driver.
+ FaviconDriver* driver_; // weak
+
+ // Best image we've seen so far. As images are downloaded from the page they
+ // are stored here. When there is an exact match, or no more images are
+ // available the favicon service and the current page are updated (assuming
+ // the image is for a favicon).
+ FaviconCandidate best_favicon_candidate_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconHandler);
+};
+
+#endif // COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_HANDLER_H_
diff --git a/components/favicon/core/browser/favicon_service.cc b/components/favicon/core/browser/favicon_service.cc
new file mode 100644
index 0000000..f0173e4
--- /dev/null
+++ b/components/favicon/core/browser/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/browser/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/browser/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);
+}
diff --git a/components/favicon/core/browser/favicon_service.h b/components/favicon/core/browser/favicon_service.h
new file mode 100644
index 0000000..4149344
--- /dev/null
+++ b/components/favicon/core/browser/favicon_service.h
@@ -0,0 +1,254 @@
+// 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.
+
+#ifndef COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_SERVICE_H_
+#define COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_SERVICE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "components/favicon_base/favicon_callback.h"
+#include "components/favicon_base/favicon_types.h"
+#include "components/favicon_base/favicon_usage_data.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class FaviconClient;
+class GURL;
+
+namespace history {
+class HistoryService;
+}
+
+// The favicon service provides methods to access favicons. It calls the history
+// backend behind the scenes. The callbacks are run asynchronously, even in the
+// case of an error.
+class FaviconService : public KeyedService {
+ public:
+ // The FaviconClient must outlive the constructed FaviconService.
+ FaviconService(FaviconClient* favicon_client,
+ history::HistoryService* history_service);
+
+ ~FaviconService() override;
+
+ // We usually pass parameters with pointer to avoid copy. This function is a
+ // helper to run FaviconResultsCallback with pointer parameters.
+ static void FaviconResultsCallbackRunner(
+ const favicon_base::FaviconResultsCallback& callback,
+ const std::vector<favicon_base::FaviconRawBitmapResult>* results);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Methods to request favicon bitmaps from the history backend for |icon_url|.
+ // |icon_url| is the URL of the icon itself.
+ // (e.g. <http://www.google.com/favicon.ico>)
+
+ // Requests the favicon at |icon_url| of type favicon_base::FAVICON and of
+ // size gfx::kFaviconSize. The returned gfx::Image is populated with
+ // representations for all of the scale factors supported by the platform
+ // (e.g. MacOS). If data is unavailable for some or all of the scale factors,
+ // the bitmaps with the best matching sizes are resized.
+ base::CancelableTaskTracker::TaskId GetFaviconImage(
+ const GURL& icon_url,
+ const favicon_base::FaviconImageCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Requests the favicon at |icon_url| of |icon_type| of size
+ // |desired_size_in_pixel|. If there is no favicon of size
+ // |desired_size_in_pixel|, the favicon bitmap which best matches
+ // |desired_size_in_pixel| is resized. If |desired_size_in_pixel| is 0,
+ // the largest favicon bitmap is returned.
+ base::CancelableTaskTracker::TaskId GetRawFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_pixel,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // The first argument for |callback| is the set of bitmaps for the passed in
+ // URL and icon types whose pixel sizes best match the passed in
+ // |desired_size_in_dip| at the resource scale factors supported by the
+ // current platform (eg MacOS) in addition to 1x. The vector has at most one
+ // result for each of the resource scale factors. There are less entries if a
+ // single/ result is the best bitmap to use for several resource scale
+ // factors.
+ base::CancelableTaskTracker::TaskId GetFavicon(
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Methods to request favicon bitmaps from the history backend for |page_url|.
+ // |page_url| is the web page the favicon is associated with.
+ // (e.g. <http://www.google.com>)
+
+ // Requests the favicon for the page at |page_url| of type
+ // favicon_base::FAVICON and of size gfx::kFaviconSize. The returned
+ // gfx::Image is populated with representations for all of the scale factors
+ // supported by the platform (e.g. MacOS). If data is unavailable for some or
+ // all of the scale factors, the bitmaps with the best matching sizes are
+ // resized.
+ base::CancelableTaskTracker::TaskId GetFaviconImageForPageURL(
+ const GURL& page_url,
+ const favicon_base::FaviconImageCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Requests the favicon for the page at |page_url| with one of |icon_types|
+ // and with |desired_size_in_pixel|. |icon_types| can be any combination of
+ // IconTypes. If favicon bitmaps for several IconTypes are available, the
+ // favicon bitmap is chosen in the priority of TOUCH_PRECOMPOSED_ICON,
+ // TOUCH_ICON and FAVICON. If there is no favicon bitmap of size
+ // |desired_size_in_pixel|, the favicon bitmap which best matches
+ // |desired_size_in_pixel| is resized. If |desired_size_in_pixel| is 0,
+ // the largest favicon bitmap is returned. Results with a higher priority
+ // IconType are preferred over an exact match of the favicon bitmap size.
+ base::CancelableTaskTracker::TaskId GetRawFaviconForPageURL(
+ const GURL& page_url,
+ int icon_types,
+ int desired_size_in_pixel,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // See HistoryService::GetLargestFaviconForPageURL().
+ base::CancelableTaskTracker::TaskId GetLargestRawFaviconForPageURL(
+ const GURL& page_url,
+ const std::vector<int>& icon_types,
+ int minimum_size_in_pixels,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ base::CancelableTaskTracker::TaskId GetFaviconForPageURL(
+ const GURL& page_url,
+ int icon_types,
+ int desired_size_in_dip,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Set the favicon mappings to |page_url| for |icon_types| in the history
+ // database.
+ // Sample |icon_urls|:
+ // { ICON_URL1 -> TOUCH_ICON, known to the database,
+ // ICON_URL2 -> TOUCH_ICON, not known to the database,
+ // ICON_URL3 -> TOUCH_PRECOMPOSED_ICON, known to the database }
+ // The new mappings are computed from |icon_urls| with these rules:
+ // 1) Any urls in |icon_urls| which are not already known to the database are
+ // rejected.
+ // Sample new mappings to |page_url|: { ICON_URL1, ICON_URL3 }
+ // 2) If |icon_types| has multiple types, the mappings are only set for the
+ // largest icon type.
+ // Sample new mappings to |page_url|: { ICON_URL3 }
+ // |icon_types| can only have multiple IconTypes if
+ // |icon_types| == TOUCH_ICON | TOUCH_PRECOMPOSED_ICON.
+ // The favicon bitmaps which most closely match |desired_size_in_dip|
+ // at the reosurce scale factors supported by the current platform (eg MacOS)
+ // in addition to 1x from the favicons which were just mapped to |page_url|
+ // are returned. If |desired_size_in_dip| is 0, the largest favicon bitmap is
+ // returned.
+ base::CancelableTaskTracker::TaskId 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);
+
+ // Used to request a bitmap for the favicon with |favicon_id| which is not
+ // resized from the size it is stored at in the database. If there are
+ // multiple favicon bitmaps for |favicon_id|, the largest favicon bitmap is
+ // returned.
+ base::CancelableTaskTracker::TaskId GetLargestRawFaviconForID(
+ favicon_base::FaviconID favicon_id,
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Marks all types of favicon for the page as being out of date.
+ void SetFaviconOutOfDateForPage(const GURL& page_url);
+
+ // Clones all icons from an existing page. This associates the icons from
+ // |old_page_url| with |new_page_url|, provided |new_page_url| has no
+ // recorded associations to any other icons.
+ // Needed if you want to declare favicons (tentatively) in advance, before a
+ // page is ever visited.
+ void CloneFavicon(const GURL& old_page_url, const GURL& new_page_url);
+
+ // Allows the importer to set many favicons for many pages at once. The pages
+ // must exist, any favicon sets for unknown pages will be discarded. Existing
+ // favicons will not be overwritten.
+ void SetImportedFavicons(
+ const favicon_base::FaviconUsageDataList& favicon_usage);
+
+ // Set the favicon for |page_url| for |icon_type| in the thumbnail database.
+ // Unlike SetFavicons(), this method will not delete preexisting bitmap data
+ // which is associated to |page_url| if at all possible. Use this method if
+ // the favicon bitmaps for any of ui::GetSupportedScaleFactors() are not
+ // known.
+ void 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);
+
+ // Set the favicon for |page_url| for |icon_type| in the thumbnail database.
+ // |icon_url| is the single favicon to map to |page_url|. Mappings from
+ // |page_url| to favicons at different icon URLs will be deleted.
+ // A favicon bitmap is added for each image rep in |image|. Any preexisting
+ // bitmap data for |icon_url| is deleted. It is important that |image|
+ // contains image reps for all of ui::GetSupportedScaleFactors(). Use
+ // MergeFavicon() if it does not.
+ // TODO(pkotwicz): Save unresized favicon bitmaps to the database.
+ // TODO(pkotwicz): Support adding favicons for multiple icon URLs to the
+ // thumbnail database.
+ void SetFavicons(const GURL& page_url,
+ const GURL& icon_url,
+ favicon_base::IconType icon_type,
+ const gfx::Image& image);
+
+ // Avoid repeated requests to download missing favicon.
+ void UnableToDownloadFavicon(const GURL& icon_url);
+ bool WasUnableToDownloadFavicon(const GURL& icon_url) const;
+ void ClearUnableToDownloadFavicons();
+
+ private:
+ typedef uint32 MissingFaviconURLHash;
+
+ // Helper function for GetFaviconImageForPageURL(), GetRawFaviconForPageURL()
+ // and GetFaviconForPageURL().
+ base::CancelableTaskTracker::TaskId GetFaviconForPageURLImpl(
+ const GURL& page_url,
+ int icon_types,
+ const std::vector<int>& desired_sizes_in_pixel,
+ const favicon_base::FaviconResultsCallback& callback,
+ base::CancelableTaskTracker* tracker);
+
+ // Intermediate callback for GetFaviconImage() and GetFaviconImageForPageURL()
+ // so that history service can deal solely with FaviconResultsCallback.
+ // Builds favicon_base::FaviconImageResult from |favicon_bitmap_results| and
+ // runs |callback|.
+ void RunFaviconImageCallbackWithBitmapResults(
+ const favicon_base::FaviconImageCallback& callback,
+ int desired_size_in_dip,
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results);
+
+ // Intermediate callback for GetRawFavicon() and GetRawFaviconForPageURL()
+ // so that history service can deal solely with FaviconResultsCallback.
+ // Resizes favicon_base::FaviconRawBitmapResult if necessary and runs
+ // |callback|.
+ void RunFaviconRawBitmapCallbackWithBitmapResults(
+ const favicon_base::FaviconRawBitmapCallback& callback,
+ int desired_size_in_pixel,
+ const std::vector<favicon_base::FaviconRawBitmapResult>&
+ favicon_bitmap_results);
+
+ base::hash_set<MissingFaviconURLHash> missing_favicon_urls_;
+ history::HistoryService* history_service_;
+ FaviconClient* favicon_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconService);
+};
+
+#endif // COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_SERVICE_H_
diff --git a/components/favicon/core/browser/favicon_tab_helper_observer.h b/components/favicon/core/browser/favicon_tab_helper_observer.h
new file mode 100644
index 0000000..bc109ff
--- /dev/null
+++ b/components/favicon/core/browser/favicon_tab_helper_observer.h
@@ -0,0 +1,24 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_TAB_HELPER_OBSERVER_H_
+#define COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_TAB_HELPER_OBSERVER_H_
+
+namespace gfx {
+class Image;
+}
+
+// An observer implemented by classes which are interested in envent in
+// FaviconTabHelper.
+class FaviconTabHelperObserver {
+ public:
+ // Called when favicon |image| is retrieved from either web site or history
+ // backend.
+ virtual void OnFaviconAvailable(const gfx::Image& image) = 0;
+
+ protected:
+ virtual ~FaviconTabHelperObserver() {}
+};
+
+#endif // COMPONENTS_FAVICON_CORE_BROWSER_FAVICON_TAB_HELPER_OBSERVER_H_