Chromium Code Reviews| Index: components/favicon/core/favicon_service.cc |
| diff --git a/components/favicon/core/favicon_service.cc b/components/favicon/core/favicon_service.cc |
| index 57a29deaf5fe69c7250a85ef799d064bab7ffe7a..9cac40343bb501ec99f5eae4d2264c2498195f15 100644 |
| --- a/components/favicon/core/favicon_service.cc |
| +++ b/components/favicon/core/favicon_service.cc |
| @@ -5,17 +5,20 @@ |
| #include "components/favicon/core/favicon_service.h" |
| #include <stddef.h> |
| +#include <algorithm> |
| #include <cmath> |
| #include <utility> |
| #include "base/hash.h" |
| #include "base/single_thread_task_runner.h" |
| +#include "base/strings/stringprintf.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/trace_event/trace_event.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 "components/image_fetcher/image_fetcher.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "ui/gfx/favicon_size.h" |
| @@ -25,6 +28,32 @@ |
| namespace favicon { |
| namespace { |
| +const char kGoogleFaviconServiceRequestFormat[] = |
| + "https://s2.googleusercontent.com/s2/" |
| + "favicons?domain=%s&src=%s&sz=%d&alt=404"; |
| + |
| +const int kGoogleFaviconServiceSupportedSizes[] = {16, 24, 32, 48, 64}; |
| + |
| +int GetClosestGoogleFaviconServerSupportedSize(int arbitrary_size) { |
| + // Take the smallest size larger than |arbitrary_size|. |
| + for (int size : kGoogleFaviconServiceSupportedSizes) { |
| + if (size >= arbitrary_size) |
| + return size; |
| + } |
| + // Or at least the largest available size. |
| + return kGoogleFaviconServiceSupportedSizes |
| + [arraysize(kGoogleFaviconServiceSupportedSizes) - 1]; |
| +} |
| + |
| +GURL GetGoogleFaviconServerURLForPageURL(GURL page_url, |
| + const std::string& client_id, |
| + int supported_size) { |
| + return GURL(base::StringPrintf(kGoogleFaviconServiceRequestFormat, |
| + page_url.spec().c_str(), |
| + client_id.c_str(), |
| + supported_size)); |
| +} |
| + |
| // Helper to run callback with empty results if we cannot get the history |
| // service. |
| base::CancelableTaskTracker::TaskId RunWithEmptyResultAsync( |
| @@ -51,10 +80,13 @@ std::vector<int> GetPixelSizesForFaviconScales(int size_in_dip) { |
| } // namespace |
| -FaviconService::FaviconService(std::unique_ptr<FaviconClient> favicon_client, |
| - history::HistoryService* history_service) |
| +FaviconService::FaviconService( |
| + std::unique_ptr<FaviconClient> favicon_client, |
| + history::HistoryService* history_service, |
| + std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher) |
| : favicon_client_(std::move(favicon_client)), |
| - history_service_(history_service) {} |
| + history_service_(history_service), |
| + image_fetcher_(std::move(image_fetcher)) {} |
| FaviconService::~FaviconService() { |
| } |
| @@ -199,6 +231,30 @@ base::CancelableTaskTracker::TaskId FaviconService::GetFaviconForPageURL( |
| } |
| base::CancelableTaskTracker::TaskId |
| +FaviconService::Get1xFaviconForPageURLDownloadFromGoogleServerIfMissing( |
| + const GURL& page_url, |
| + int minimum_size_in_pixel, |
| + int desired_size_in_pixel, |
| + std::string client_id, |
| + data_use_measurement::DataUseUserData::ServiceName data_use_service_name, |
| + const favicon_base::FaviconImageCallback& callback, |
| + base::CancelableTaskTracker* tracker) { |
| + TRACE_EVENT0("browser", |
| + "FaviconService::" |
| + "Get1xFaviconForPageURLDownloadFromGoogleServerIfMissing"); |
| + std::vector<int> desired_sizes_in_pixel; |
| + desired_sizes_in_pixel.push_back(desired_size_in_pixel); |
| + return GetFaviconForPageURLImpl( |
| + page_url, favicon_base::IconType::FAVICON, desired_sizes_in_pixel, |
| + base::Bind(&FaviconService:: |
| + RunFaviconImageCallbackOrDownloadFromGoogleFaviconServer, |
| + base::Unretained(this), page_url, minimum_size_in_pixel, |
| + desired_size_in_pixel, client_id, data_use_service_name, |
| + callback), |
| + tracker); |
| +} |
| + |
| +base::CancelableTaskTracker::TaskId |
| FaviconService::UpdateFaviconMappingsAndFetch( |
| const GURL& page_url, |
| const std::vector<GURL>& icon_urls, |
| @@ -348,4 +404,100 @@ void FaviconService::RunFaviconRawBitmapCallbackWithBitmapResults( |
| ResizeFaviconBitmapResult(favicon_bitmap_results, desired_size_in_pixel)); |
| } |
| +void FaviconService::RunFaviconImageCallbackOrDownloadFromGoogleFaviconServer( |
| + const GURL& page_url, |
| + int minimum_size_in_pixel, |
| + int desired_size_in_pixel, |
| + std::string client_id, |
| + data_use_measurement::DataUseUserData::ServiceName data_use_service_name, |
| + const favicon_base::FaviconImageCallback& callback, |
| + const std::vector<favicon_base::FaviconRawBitmapResult>& |
| + favicon_bitmap_results) { |
| + TRACE_EVENT0("browser", |
| + "FaviconService::" |
| + "RunFaviconImageCallbackOrDownloadFromGoogleFaviconServer"); |
| + |
| + // Ensure we do not get an icon upscaled from a smaller png than |
| + // |minimum_size_in_pixel|. |
| + bool large_enough = false; |
| + for (const auto& bitmap : favicon_bitmap_results) { |
| + if (minimum_size_in_pixel <= std::max(bitmap.pixel_size_in_db.width(), |
| + bitmap.pixel_size_in_db.height())) { |
| + large_enough = true; |
| + break; |
|
jkrcal
2017/02/06 19:01:22
This was obviously wrong :)
|
| + } |
| + } |
| + |
| + // If there are some cached bitmaps but none is large enough, we cannot return |
|
pkotwicz
2017/02/07 04:55:55
Nit: 'is' -> 'are'
|
| + // any of them as the result and we also do not want to overwrite them by an |
| + // icon from the Google server. Thus, return an empty result. |
| + if (favicon_bitmap_results.size() > 0 && !large_enough) { |
|
pkotwicz
2017/02/07 04:55:55
Nit: !favicon_bitmap_results.empty()
|
| + callback.Run(favicon_base::FaviconImageResult()); |
| + return; |
| + } |
| + |
| + gfx::Image image; |
| + image = favicon_base::SelectFaviconFramesFromPNGs( |
| + favicon_bitmap_results, {1.0f}, desired_size_in_pixel); |
| + |
| + if (!image.IsEmpty()) { |
| + // If a large enough cached bitmap is successfully rescaled, serve it! |
| + favicon_base::FaviconImageResult image_result; |
| + image_result.image = image; |
| + favicon_base::SetFaviconColorSpace(&image_result.image); |
| + image_result.icon_url = favicon_bitmap_results[0].icon_url; |
| + callback.Run(image_result); |
| + return; |
| + } |
| + |
| + // No good enough favicon in the cache. Download it from the server. |
| + |
| + if (!image_fetcher_.get()) { |
| + // No fetcher available (e.g. in unittests), return an empty result. |
| + callback.Run(favicon_base::FaviconImageResult()); |
| + return; |
| + } |
| + |
| + // TODO(jkrcal): When we use the other server backend, require |
| + // |minimum_size_in_pixel|. |
|
pkotwicz
2017/02/07 04:55:55
I think that it makes sense to enforce |minimum_si
|
| + int supported_size = |
| + GetClosestGoogleFaviconServerSupportedSize(desired_size_in_pixel); |
| + GURL image_url = GetGoogleFaviconServerURLForPageURL(page_url, client_id, |
| + supported_size); |
| + |
| + image_fetcher_->SetDataUseServiceName(data_use_service_name); |
| + image_fetcher_->StartOrQueueNetworkRequest( |
| + image_url.spec(), image_url, |
| + base::Bind(&FaviconService:: |
| + StoreFaviconFromGoogleServerAndRunFaviconImageCallback, |
| + base::Unretained(this), callback, page_url, |
| + desired_size_in_pixel)); |
| +} |
| + |
| +void FaviconService::StoreFaviconFromGoogleServerAndRunFaviconImageCallback( |
| + const favicon_base::FaviconImageCallback& callback, |
| + const GURL& page_url, |
| + int desired_size_in_pixel, |
| + const std::string& icon_url, |
| + const gfx::Image& image) { |
| + if (image.IsEmpty()) |
| + callback.Run(favicon_base::FaviconImageResult()); |
| + |
| + SkBitmap icon = image.AsBitmap(); |
| + SkBitmap icon_resized = favicon_base::ResizeBitmapByDownsamplingIfPossible( |
| + {icon}, desired_size_in_pixel); |
| + |
| + favicon_base::FaviconImageResult image_result; |
| + image_result.icon_url = GURL(icon_url); |
| + image_result.image = gfx::Image::CreateFrom1xBitmap(icon_resized); |
| + favicon_base::SetFaviconColorSpace(&image_result.image); |
| + SetFavicons(page_url, image_result.icon_url, |
| + favicon_base::IconType::FAVICON, image_result.image); |
| + // Mark the icons as out-of-date so that they are refetched when we visit the |
| + // original page any time in the future. |
| + SetFaviconOutOfDateForPage(page_url); |
| + |
| + callback.Run(image_result); |
| +} |
| + |
| } // namespace favicon |