Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/favicon/core/large_icon_service.h" | 5 #include "components/favicon/core/large_icon_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include <memory> | 8 #include <memory> |
| 8 | 9 |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/feature_list.h" | |
| 10 #include "base/location.h" | 12 #include "base/location.h" |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/memory/ptr_util.h" | |
| 13 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/strings/stringprintf.h" | |
| 14 #include "base/task_runner.h" | 18 #include "base/task_runner.h" |
| 15 #include "base/threading/sequenced_worker_pool.h" | 19 #include "base/threading/sequenced_worker_pool.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | |
| 21 #include "components/data_use_measurement/core/data_use_user_data.h" | |
| 16 #include "components/favicon/core/favicon_service.h" | 22 #include "components/favicon/core/favicon_service.h" |
| 23 #include "components/favicon/core/features.h" | |
| 17 #include "components/favicon_base/fallback_icon_style.h" | 24 #include "components/favicon_base/fallback_icon_style.h" |
| 18 #include "components/favicon_base/favicon_types.h" | 25 #include "components/favicon_base/favicon_types.h" |
| 26 #include "components/favicon_base/favicon_util.h" | |
| 27 #include "components/image_fetcher/image_fetcher.h" | |
| 19 #include "skia/ext/image_operations.h" | 28 #include "skia/ext/image_operations.h" |
| 20 #include "ui/gfx/codec/png_codec.h" | 29 #include "ui/gfx/codec/png_codec.h" |
| 21 #include "ui/gfx/geometry/size.h" | 30 #include "ui/gfx/geometry/size.h" |
| 22 | 31 |
| 32 using image_fetcher::ImageFetcher; | |
| 33 | |
| 34 namespace favicon { | |
| 35 | |
| 23 namespace { | 36 namespace { |
| 24 | 37 |
| 25 // Processes the bitmap data returned from the FaviconService as part of a | 38 const char kGoogleServer1RequestFormat[] = |
| 26 // LargeIconService request. | 39 "https://s2.googleusercontent.com/s2/" |
| 27 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> { | 40 "favicons?domain=%s&src=chrome_large_icons&sz=%d&alt=404"; |
| 41 const int kGoogleServer1DesiredSizeInPixel = 32; | |
| 42 | |
| 43 // Type APPLE_TOUCH includes TOUCH_ICONs as well as FAVICONs as fallback. | |
| 44 const char kGoogleServer2RequestFormat[] = | |
| 45 "https://t0.gstatic.com/" | |
| 46 "faviconV2?url=%s&type=APPLE_TOUCH&size=%d&min_size=%d&max_size=%d"; | |
| 47 const int kGoogleServer2MinSizeInPixel = 48; | |
| 48 const int kGoogleServer2MaxSizeInPixel = 256; | |
| 49 const int kGoogleServer2DesiredSizeInPixel = 192; | |
| 50 | |
| 51 // Base class for processing one large icon query. | |
| 52 class LargeIconWorkerBase { | |
| 28 public: | 53 public: |
| 29 LargeIconWorker(int min_source_size_in_pixel, | 54 LargeIconWorkerBase(const GURL& page_url, |
| 30 int desired_size_in_pixel, | 55 int min_source_size_in_pixel, |
| 31 favicon_base::LargeIconCallback callback, | 56 int desired_size_in_pixel, |
| 32 scoped_refptr<base::TaskRunner> background_task_runner, | 57 favicon_base::LargeIconCallback callback, |
| 33 base::CancelableTaskTracker* tracker); | 58 scoped_refptr<base::TaskRunner> background_task_runner, |
| 59 base::CancelableTaskTracker* tracker, | |
| 60 FaviconService* favicon_service); | |
| 61 | |
| 62 virtual base::CancelableTaskTracker::TaskId Start() = 0; | |
| 63 | |
| 64 protected: | |
| 65 ~LargeIconWorkerBase() = default; | |
| 66 void PrepareLargeIconResult( | |
| 67 const favicon_base::FaviconRawBitmapResult* bitmap_result, | |
| 68 bool create_bitmap); | |
| 34 | 69 |
| 35 // Must run on the owner (UI) thread in production. | 70 // Must run on the owner (UI) thread in production. |
| 36 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes | 71 void RunCallback(); |
| 37 // ProcessIconOnBackgroundThread() so we do not perform complex image | 72 |
| 38 // operations on the UI thread. | 73 GURL page_url_; |
| 39 void OnIconLookupComplete( | |
| 40 const favicon_base::FaviconRawBitmapResult& bitmap_result); | |
| 41 | |
| 42 private: | |
| 43 friend class base::RefCountedThreadSafe<LargeIconWorker>; | |
| 44 | |
| 45 ~LargeIconWorker(); | |
| 46 | |
| 47 // Must run on a background thread in production. | |
| 48 // Tries to resize |bitmap_result_| and pass the output to |callback_|. If | |
| 49 // that does not work, computes the icon fallback style and uses it to | |
| 50 // invoke |callback_|. This must be run on a background thread because image | |
| 51 // resizing and dominant color extraction can be expensive. | |
| 52 void ProcessIconOnBackgroundThread(); | |
| 53 | |
| 54 // Must run on a background thread in production. | |
| 55 // If |bitmap_result_| is square and large enough (>= |min_source_in_pixel_|), | |
| 56 // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is | |
| 57 // 0 then don't resize). If successful, stores the resulting bitmap data | |
| 58 // into |resized_bitmap_result| and returns true. | |
| 59 bool ResizeLargeIconOnBackgroundThreadIfValid( | |
| 60 favicon_base::FaviconRawBitmapResult* resized_bitmap_result); | |
| 61 | |
| 62 // Must run on the owner (UI) thread in production. | |
| 63 // Invoked when ProcessIconOnBackgroundThread() is done. | |
| 64 void OnIconProcessingComplete(); | |
| 65 | 74 |
| 66 int min_source_size_in_pixel_; | 75 int min_source_size_in_pixel_; |
| 67 int desired_size_in_pixel_; | 76 int desired_size_in_pixel_; |
| 68 favicon_base::LargeIconCallback callback_; | 77 favicon_base::LargeIconCallback callback_; |
| 69 scoped_refptr<base::TaskRunner> background_task_runner_; | 78 scoped_refptr<base::TaskRunner> background_task_runner_; |
| 70 base::CancelableTaskTracker* tracker_; | 79 base::CancelableTaskTracker* tracker_; |
| 71 favicon_base::FaviconRawBitmapResult bitmap_result_; | 80 FaviconService* favicon_service_; |
| 81 | |
| 82 // Data constructed on the background thread. | |
| 72 std::unique_ptr<favicon_base::LargeIconResult> result_; | 83 std::unique_ptr<favicon_base::LargeIconResult> result_; |
| 73 | 84 |
| 74 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker); | 85 private: |
| 86 DISALLOW_COPY_AND_ASSIGN(LargeIconWorkerBase); | |
| 75 }; | 87 }; |
| 76 | 88 |
| 77 LargeIconWorker::LargeIconWorker( | 89 LargeIconWorkerBase::LargeIconWorkerBase( |
| 90 const GURL& page_url, | |
| 78 int min_source_size_in_pixel, | 91 int min_source_size_in_pixel, |
| 79 int desired_size_in_pixel, | 92 int desired_size_in_pixel, |
| 80 favicon_base::LargeIconCallback callback, | 93 favicon_base::LargeIconCallback callback, |
| 81 scoped_refptr<base::TaskRunner> background_task_runner, | 94 scoped_refptr<base::TaskRunner> background_task_runner, |
| 82 base::CancelableTaskTracker* tracker) | 95 base::CancelableTaskTracker* tracker, |
| 83 : min_source_size_in_pixel_(min_source_size_in_pixel), | 96 FaviconService* favicon_service) |
| 97 : page_url_(page_url), | |
| 98 min_source_size_in_pixel_(std::min(min_source_size_in_pixel_, 32)), | |
| 84 desired_size_in_pixel_(desired_size_in_pixel), | 99 desired_size_in_pixel_(desired_size_in_pixel), |
| 85 callback_(callback), | 100 callback_(callback), |
| 86 background_task_runner_(background_task_runner), | 101 background_task_runner_(background_task_runner), |
| 87 tracker_(tracker) { | 102 tracker_(tracker), |
| 88 } | 103 favicon_service_(favicon_service) {} |
| 89 | 104 |
| 90 LargeIconWorker::~LargeIconWorker() { | 105 void LargeIconWorkerBase::PrepareLargeIconResult( |
| 91 } | 106 const favicon_base::FaviconRawBitmapResult* bitmap_result, |
| 92 | 107 bool create_bitmap) { |
| 93 void LargeIconWorker::OnIconLookupComplete( | 108 if (create_bitmap && bitmap_result && bitmap_result->is_valid()) { |
| 109 result_ = base::MakeUnique<favicon_base::LargeIconResult>(*bitmap_result); | |
| 110 } else { | |
| 111 // Compute fallback icon style. | |
| 112 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style = | |
| 113 base::MakeUnique<favicon_base::FallbackIconStyle>(); | |
| 114 if (bitmap_result && bitmap_result->is_valid()) { | |
| 115 favicon_base::SetDominantColorAsBackground(bitmap_result->bitmap_data, | |
| 116 fallback_icon_style.get()); | |
| 117 } | |
| 118 result_ = base::MakeUnique<favicon_base::LargeIconResult>( | |
| 119 std::move(fallback_icon_style)); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 void LargeIconWorkerBase::RunCallback() { | |
| 124 callback_.Run(*result_); | |
| 125 } | |
| 126 | |
| 127 // Processes the bitmap data returned from a Google favicon server as part of a | |
| 128 // LargeIconService request. | |
| 129 class LargeIconCacheWorker | |
| 130 : public LargeIconWorkerBase, | |
| 131 public base::RefCountedThreadSafe<LargeIconCacheWorker> { | |
| 132 public: | |
| 133 LargeIconCacheWorker(const GURL& page_url, | |
| 134 int min_source_size_in_pixel, | |
| 135 int desired_size_in_pixel, | |
| 136 favicon_base::LargeIconCallback callback, | |
| 137 scoped_refptr<base::TaskRunner> background_task_runner, | |
| 138 base::CancelableTaskTracker* tracker, | |
| 139 FaviconService* favicon_service); | |
| 140 | |
| 141 base::CancelableTaskTracker::TaskId Start() override; | |
| 142 | |
| 143 private: | |
| 144 friend class base::RefCountedThreadSafe<LargeIconCacheWorker>; | |
| 145 virtual ~LargeIconCacheWorker(); | |
| 146 | |
| 147 // Must run on the owner (UI) thread in production. | |
| 148 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes | |
| 149 // ProcessIconOnBackgroundThread() so we do not perform complex image | |
| 150 // operations on the UI thread. | |
| 151 void OnCachedIconLookupComplete( | |
| 152 const favicon_base::FaviconRawBitmapResult& bitmap_result); | |
| 153 | |
| 154 // Must run on a background thread in production. | |
| 155 // Tries to resize |bitmap_result| and pass the output to |callback_|. If | |
| 156 // that does not work, computes the icon fallback style and uses it to | |
| 157 // invoke |callback_|. This must be run on a background thread because image | |
| 158 // resizing and dominant color extraction can be expensive. | |
| 159 void ProcessCachedIconOnBackgroundThread( | |
| 160 const favicon_base::FaviconRawBitmapResult& bitmap_result); | |
| 161 | |
| 162 // Must run on a background thread in production. | |
| 163 // If |bitmap_result| is square and large enough (>= |min_source_in_pixel_|), | |
| 164 // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is | |
| 165 // 0 then don't resize). If successful, stores the resulting bitmap data | |
| 166 // into |bitmap_result| and returns true. | |
| 167 bool ResizeCachedIconOnBackgroundThreadIfValid( | |
| 168 const favicon_base::FaviconRawBitmapResult& bitmap_result, | |
| 169 favicon_base::FaviconRawBitmapResult* resized_bitmap_result); | |
| 170 | |
| 171 DISALLOW_COPY_AND_ASSIGN(LargeIconCacheWorker); | |
| 172 }; | |
| 173 | |
| 174 LargeIconCacheWorker::LargeIconCacheWorker( | |
| 175 const GURL& page_url, | |
| 176 int min_source_size_in_pixel, | |
| 177 int desired_size_in_pixel, | |
| 178 favicon_base::LargeIconCallback callback, | |
| 179 scoped_refptr<base::TaskRunner> background_task_runner, | |
| 180 base::CancelableTaskTracker* tracker, | |
| 181 FaviconService* favicon_service) | |
| 182 : LargeIconWorkerBase(page_url, | |
| 183 min_source_size_in_pixel, | |
| 184 desired_size_in_pixel, | |
| 185 callback, | |
| 186 background_task_runner, | |
| 187 tracker, | |
| 188 favicon_service) {} | |
| 189 | |
| 190 LargeIconCacheWorker::~LargeIconCacheWorker() {} | |
| 191 | |
| 192 base::CancelableTaskTracker::TaskId LargeIconCacheWorker::Start() { | |
| 193 return favicon_service_->GetRawFaviconForPageURL( | |
| 194 page_url_, | |
| 195 favicon_base::IconType::FAVICON | favicon_base::IconType::TOUCH_ICON | | |
| 196 favicon_base::IconType::TOUCH_PRECOMPOSED_ICON, | |
| 197 desired_size_in_pixel_, | |
| 198 base::Bind(&LargeIconCacheWorker::OnCachedIconLookupComplete, this), | |
| 199 tracker_); | |
| 200 } | |
| 201 | |
| 202 void LargeIconCacheWorker::OnCachedIconLookupComplete( | |
| 94 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | 203 const favicon_base::FaviconRawBitmapResult& bitmap_result) { |
| 95 bitmap_result_ = bitmap_result; | 204 // Prepare the data for the callback and run it. |
| 96 tracker_->PostTaskAndReply( | 205 tracker_->PostTaskAndReply( |
| 97 background_task_runner_.get(), FROM_HERE, | 206 background_task_runner_.get(), FROM_HERE, |
| 98 base::Bind(&LargeIconWorker::ProcessIconOnBackgroundThread, this), | 207 base::Bind(&LargeIconCacheWorker::ProcessCachedIconOnBackgroundThread, |
| 99 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this)); | 208 this, bitmap_result), |
| 100 } | 209 base::Bind(&LargeIconCacheWorker::RunCallback, this)); |
| 101 | 210 } |
| 102 void LargeIconWorker::ProcessIconOnBackgroundThread() { | 211 |
| 212 void LargeIconCacheWorker::ProcessCachedIconOnBackgroundThread( | |
| 213 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | |
| 103 favicon_base::FaviconRawBitmapResult resized_bitmap_result; | 214 favicon_base::FaviconRawBitmapResult resized_bitmap_result; |
| 104 if (ResizeLargeIconOnBackgroundThreadIfValid(&resized_bitmap_result)) { | 215 bool create_bitmap = ResizeCachedIconOnBackgroundThreadIfValid( |
| 105 result_.reset( | 216 bitmap_result, &resized_bitmap_result); |
| 106 new favicon_base::LargeIconResult(resized_bitmap_result)); | 217 PrepareLargeIconResult(&resized_bitmap_result, create_bitmap); |
| 107 } else { | 218 } |
| 108 // Failed to resize |bitmap_result_|, so compute fallback icon style. | 219 |
| 109 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style( | 220 bool LargeIconCacheWorker::ResizeCachedIconOnBackgroundThreadIfValid( |
| 110 new favicon_base::FallbackIconStyle()); | 221 const favicon_base::FaviconRawBitmapResult& bitmap_result, |
| 111 if (bitmap_result_.is_valid()) { | |
| 112 favicon_base::SetDominantColorAsBackground( | |
| 113 bitmap_result_.bitmap_data, fallback_icon_style.get()); | |
| 114 } | |
| 115 result_.reset( | |
| 116 new favicon_base::LargeIconResult(fallback_icon_style.release())); | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 bool LargeIconWorker::ResizeLargeIconOnBackgroundThreadIfValid( | |
| 121 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) { | 222 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) { |
| 122 // Require bitmap to be valid and square. | 223 // Require bitmap to be valid and square. |
| 123 if (!bitmap_result_.is_valid() || | 224 if (!bitmap_result.is_valid() || |
| 124 bitmap_result_.pixel_size.width() != bitmap_result_.pixel_size.height()) | 225 bitmap_result.pixel_size.width() != bitmap_result.pixel_size.height()) |
| 125 return false; | 226 return false; |
| 126 | 227 |
| 127 // Require bitmap to be large enough. It's square, so just check width. | 228 // Require bitmap to be large enough. It's square, so just check width. |
| 128 if (bitmap_result_.pixel_size.width() < min_source_size_in_pixel_) | 229 if (bitmap_result.pixel_size.width() < min_source_size_in_pixel_) |
| 129 return false; | 230 return false; |
| 130 | 231 |
| 131 *resized_bitmap_result = bitmap_result_; | 232 *resized_bitmap_result = bitmap_result; |
| 132 | 233 |
| 133 // Special case: Can use |bitmap_result_| as is. | 234 // Special case: Can use |bitmap_result| as is. |
| 134 if (desired_size_in_pixel_ == 0 || | 235 if (desired_size_in_pixel_ == 0 || |
| 135 bitmap_result_.pixel_size.width() == desired_size_in_pixel_) | 236 bitmap_result.pixel_size.width() == desired_size_in_pixel_) |
| 136 return true; | 237 return true; |
| 137 | 238 |
| 138 // Resize bitmap: decode PNG, resize, and re-encode PNG. | 239 // Resize bitmap: decode PNG, resize, and re-encode PNG. |
| 139 SkBitmap decoded_bitmap; | 240 SkBitmap decoded_bitmap; |
| 140 if (!gfx::PNGCodec::Decode(bitmap_result_.bitmap_data->front(), | 241 if (!gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), |
| 141 bitmap_result_.bitmap_data->size(), &decoded_bitmap)) | 242 bitmap_result.bitmap_data->size(), |
| 142 return false; | 243 &decoded_bitmap)) |
| 143 | 244 return false; |
| 144 SkBitmap resized_bitmap = skia::ImageOperations::Resize( | 245 |
| 246 SkBitmap bitmap = skia::ImageOperations::Resize( | |
| 145 decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, | 247 decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, |
| 146 desired_size_in_pixel_, desired_size_in_pixel_); | 248 desired_size_in_pixel_, desired_size_in_pixel_); |
| 147 | 249 |
| 148 std::vector<unsigned char> bitmap_data; | 250 std::vector<unsigned char> bitmap_data; |
| 149 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_bitmap, false, &bitmap_data)) | 251 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data)) |
| 150 return false; | 252 return false; |
| 151 | 253 |
| 152 resized_bitmap_result->pixel_size = | 254 resized_bitmap_result->pixel_size = |
| 153 gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_); | 255 gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_); |
| 154 resized_bitmap_result->bitmap_data = | 256 resized_bitmap_result->bitmap_data = |
| 155 base::RefCountedBytes::TakeVector(&bitmap_data); | 257 base::RefCountedBytes::TakeVector(&bitmap_data); |
| 156 return true; | 258 return true; |
| 157 } | 259 } |
| 158 | 260 |
| 159 void LargeIconWorker::OnIconProcessingComplete() { | 261 // Processes the bitmap data returned from the FaviconService as part of a |
| 160 callback_.Run(*result_); | 262 // LargeIconService request. |
| 263 class LargeIconGoogleServerWorker | |
| 264 : public LargeIconWorkerBase, | |
| 265 public base::RefCountedThreadSafe<LargeIconGoogleServerWorker> { | |
| 266 public: | |
| 267 LargeIconGoogleServerWorker( | |
| 268 const GURL& page_url, | |
| 269 int min_source_size_in_pixel, | |
| 270 int desired_size_in_pixel, | |
| 271 favicon_base::LargeIconCallback callback, | |
| 272 scoped_refptr<base::TaskRunner> background_task_runner, | |
| 273 base::CancelableTaskTracker* tracker, | |
| 274 FaviconService* favicon_service, | |
| 275 ImageFetcher* image_fetcher); | |
| 276 | |
| 277 base::CancelableTaskTracker::TaskId Start() override; | |
| 278 | |
| 279 private: | |
| 280 friend class base::RefCountedThreadSafe<LargeIconGoogleServerWorker>; | |
| 281 virtual ~LargeIconGoogleServerWorker(); | |
| 282 | |
| 283 void ProcessIconFromGoogleServerOnBackgroundThread(const GURL& icon_url, | |
| 284 const gfx::Image& image); | |
| 285 | |
| 286 // Must run on a background thread in production. | |
| 287 // If |bitmap_result| is square and large enough (>= |min_source_in_pixel_|), | |
| 288 // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is | |
| 289 // 0 then don't resize). If successful, stores the resulting bitmap data | |
| 290 // into |bitmap_result| and returns true. | |
| 291 bool ResizeIconFromGoogleServerOnBackgroundThreadIfValid( | |
| 292 const GURL& icon_url, | |
| 293 const gfx::Image image, | |
| 294 favicon_base::FaviconRawBitmapResult* resized_bitmap_result); | |
| 295 | |
| 296 // Create the GET URL that requests the desired favicon from a Google favicon | |
| 297 // server (version 1 / version 2). | |
| 298 GURL GetIconUrlForGoogleServer1() const; | |
| 299 GURL GetIconUrlForGoogleServer2() const; | |
| 300 | |
| 301 // Fetches an icon for the given |icon_url| and stores it in the favicon DB. | |
| 302 void FetchIconFromGoogleServer(const GURL& icon_url); | |
| 303 void OnFetchIconFromGoogleServerComplete(const std::string& icon_url, | |
| 304 const gfx::Image& image); | |
| 305 | |
| 306 ImageFetcher* image_fetcher_; | |
| 307 | |
| 308 DISALLOW_COPY_AND_ASSIGN(LargeIconGoogleServerWorker); | |
| 309 }; | |
| 310 | |
| 311 LargeIconGoogleServerWorker::LargeIconGoogleServerWorker( | |
| 312 const GURL& page_url, | |
| 313 int min_source_size_in_pixel, | |
| 314 int desired_size_in_pixel, | |
| 315 favicon_base::LargeIconCallback callback, | |
| 316 scoped_refptr<base::TaskRunner> background_task_runner, | |
| 317 base::CancelableTaskTracker* tracker, | |
| 318 FaviconService* favicon_service, | |
| 319 ImageFetcher* image_fetcher) | |
| 320 : LargeIconWorkerBase(page_url, | |
| 321 min_source_size_in_pixel, | |
| 322 desired_size_in_pixel, | |
| 323 callback, | |
| 324 background_task_runner, | |
| 325 tracker, | |
| 326 favicon_service), | |
| 327 image_fetcher_(image_fetcher) {} | |
| 328 | |
| 329 LargeIconGoogleServerWorker::~LargeIconGoogleServerWorker() {} | |
| 330 | |
| 331 base::CancelableTaskTracker::TaskId LargeIconGoogleServerWorker::Start() { | |
| 332 GURL server_url; | |
| 333 if (base::FeatureList::IsEnabled(kFaviconFetchLargeIconFromGoogleServer2)) { | |
| 334 server_url = GetIconUrlForGoogleServer2(); | |
| 335 } else if (min_source_size_in_pixel_ <= 16 && | |
| 336 base::FeatureList::IsEnabled( | |
| 337 kFaviconFetchLargeIconFromGoogleServer1)) { | |
| 338 // Server 1 cannot guarantee that the served icon has original size >=16px | |
| 339 // as it upscales images to fill in empty spots for missing sizes (32px, | |
| 340 // 64px) when indexing. | |
| 341 server_url = GetIconUrlForGoogleServer1(); | |
| 342 } | |
| 343 | |
| 344 return tracker_->PostTask( | |
| 345 background_task_runner_.get(), FROM_HERE, | |
| 346 base::Bind(&LargeIconGoogleServerWorker::FetchIconFromGoogleServer, this, | |
| 347 server_url)); | |
| 348 } | |
| 349 | |
| 350 GURL LargeIconGoogleServerWorker::GetIconUrlForGoogleServer1() const { | |
| 351 return GURL(base::StringPrintf(kGoogleServer1RequestFormat, | |
| 352 page_url_.spec().c_str(), | |
| 353 kGoogleServer1DesiredSizeInPixel)); | |
| 354 } | |
| 355 | |
| 356 GURL LargeIconGoogleServerWorker::GetIconUrlForGoogleServer2() const { | |
| 357 // TODO(jkrcal): make the desired/min/max sizes depend on the device (its | |
| 358 // scale factor, etc). | |
| 359 return GURL(base::StringPrintf( | |
| 360 kGoogleServer2RequestFormat, page_url_.GetWithEmptyPath().spec().c_str(), | |
| 361 kGoogleServer2DesiredSizeInPixel, kGoogleServer2MinSizeInPixel, | |
| 362 kGoogleServer2MaxSizeInPixel)); | |
| 363 } | |
| 364 | |
| 365 void LargeIconGoogleServerWorker::FetchIconFromGoogleServer( | |
| 366 const GURL& icon_url) { | |
| 367 if (icon_url.is_empty() // Do not fetch if fetching is disabled. | |
| 368 || favicon_service_->WasUnableToDownloadFavicon(icon_url) | |
| 369 // Do not retry if there is a previous cache miss recorded for |icon_url|. | |
| 370 ) { | |
| 371 PrepareLargeIconResult(nullptr, /*create_bitmap=*/false); | |
| 372 RunCallback(); | |
| 373 return; | |
| 374 } | |
| 375 | |
| 376 image_fetcher_->SetDataUseServiceName( | |
| 377 data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE); | |
| 378 image_fetcher_->StartOrQueueNetworkRequest( | |
| 379 icon_url.spec(), icon_url, | |
| 380 base::Bind( | |
| 381 &LargeIconGoogleServerWorker::OnFetchIconFromGoogleServerComplete, | |
| 382 this)); | |
| 383 } | |
| 384 | |
| 385 void LargeIconGoogleServerWorker::OnFetchIconFromGoogleServerComplete( | |
| 386 const std::string& icon_url, | |
| 387 const gfx::Image& image) { | |
| 388 if (image.IsEmpty()) { | |
| 389 favicon_service_->UnableToDownloadFavicon(GURL(icon_url)); | |
| 390 PrepareLargeIconResult(nullptr, /*create_bitmap=*/false); | |
| 391 RunCallback(); | |
| 392 return; | |
| 393 } | |
| 394 | |
| 395 // TODO(jkrcal): Extract the original icon url from the response headers if | |
| 396 // available and use it instead of |icon_url|. | |
| 397 | |
| 398 // TODO(jkrcal): never overwrite favicons. Fix in this CL! | |
|
jkrcal
2017/02/27 17:31:19
This still definitely needs to get addressed in th
| |
| 399 favicon_service_->SetFavicons(page_url_, GURL(icon_url), | |
| 400 favicon_base::IconType::TOUCH_ICON, image); | |
| 401 // Mark the icons as out-of-date so that they are refetched when we visit the | |
| 402 // original page any time in the future. | |
| 403 favicon_service_->SetFaviconOutOfDateForPage(page_url_); | |
| 404 | |
| 405 tracker_->PostTaskAndReply( | |
| 406 background_task_runner_.get(), FROM_HERE, | |
| 407 base::Bind(&LargeIconGoogleServerWorker:: | |
| 408 ProcessIconFromGoogleServerOnBackgroundThread, | |
| 409 this, GURL(icon_url), image), | |
| 410 base::Bind(&LargeIconGoogleServerWorker::RunCallback, this)); | |
| 411 } | |
| 412 | |
| 413 void LargeIconGoogleServerWorker::ProcessIconFromGoogleServerOnBackgroundThread( | |
| 414 const GURL& icon_url, | |
| 415 const gfx::Image& image) { | |
| 416 favicon_base::FaviconRawBitmapResult resized_bitmap_result; | |
| 417 bool create_bitmap = ResizeIconFromGoogleServerOnBackgroundThreadIfValid( | |
| 418 icon_url, image, &resized_bitmap_result); | |
| 419 PrepareLargeIconResult(&resized_bitmap_result, create_bitmap); | |
| 420 } | |
| 421 | |
| 422 bool LargeIconGoogleServerWorker:: | |
| 423 ResizeIconFromGoogleServerOnBackgroundThreadIfValid( | |
| 424 const GURL& icon_url, | |
| 425 const gfx::Image image, | |
| 426 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) { | |
| 427 // Require bitmap to be valid and square. | |
| 428 if (!image.IsEmpty() || image.Width() != image.Height()) | |
| 429 return false; | |
| 430 | |
| 431 // Require bitmap to be large enough. It's square, so just check width. | |
| 432 if (image.Width() < min_source_size_in_pixel_) | |
| 433 return false; | |
| 434 | |
| 435 SkBitmap bitmap = image.AsBitmap(); | |
| 436 | |
| 437 // Resize if necessary. | |
| 438 if (desired_size_in_pixel_ != 0 && image.Width() != desired_size_in_pixel_) { | |
| 439 bitmap = skia::ImageOperations::Resize( | |
| 440 bitmap, skia::ImageOperations::RESIZE_LANCZOS3, desired_size_in_pixel_, | |
| 441 desired_size_in_pixel_); | |
| 442 } | |
| 443 | |
| 444 std::vector<unsigned char> bitmap_data; | |
| 445 if (!gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bitmap_data)) | |
| 446 return false; | |
| 447 | |
| 448 resized_bitmap_result->pixel_size = | |
| 449 gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_); | |
| 450 resized_bitmap_result->bitmap_data = | |
| 451 base::RefCountedBytes::TakeVector(&bitmap_data); | |
| 452 resized_bitmap_result->expired = true; | |
| 453 resized_bitmap_result->icon_url = icon_url; | |
| 454 resized_bitmap_result->icon_type = favicon_base::IconType::TOUCH_ICON; | |
| 455 | |
| 456 return true; | |
| 161 } | 457 } |
| 162 | 458 |
| 163 } // namespace | 459 } // namespace |
| 164 | 460 |
| 165 namespace favicon { | |
| 166 | |
| 167 LargeIconService::LargeIconService( | 461 LargeIconService::LargeIconService( |
| 168 FaviconService* favicon_service, | 462 FaviconService* favicon_service, |
| 169 const scoped_refptr<base::TaskRunner>& background_task_runner) | 463 const scoped_refptr<base::TaskRunner>& background_task_runner, |
| 464 std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher) | |
| 170 : favicon_service_(favicon_service), | 465 : favicon_service_(favicon_service), |
| 171 background_task_runner_(background_task_runner) { | 466 background_task_runner_(background_task_runner), |
| 172 large_icon_types_.push_back(favicon_base::IconType::FAVICON); | 467 image_fetcher_(std::move(image_fetcher)) {} |
| 173 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON); | |
| 174 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON); | |
| 175 } | |
| 176 | 468 |
| 177 LargeIconService::~LargeIconService() { | 469 LargeIconService::~LargeIconService() { |
| 178 } | 470 } |
| 179 | 471 |
| 180 base::CancelableTaskTracker::TaskId | 472 base::CancelableTaskTracker::TaskId |
| 181 LargeIconService::GetLargeIconOrFallbackStyle( | 473 LargeIconService::GetLargeIconOrFallbackStyle( |
| 182 const GURL& page_url, | 474 const GURL& page_url, |
| 183 int min_source_size_in_pixel, | 475 int min_source_size_in_pixel, |
| 184 int desired_size_in_pixel, | 476 int desired_size_in_pixel, |
| 185 const favicon_base::LargeIconCallback& callback, | 477 const favicon_base::LargeIconCallback& callback, |
| 186 base::CancelableTaskTracker* tracker) { | 478 base::CancelableTaskTracker* tracker) { |
| 187 DCHECK_LE(1, min_source_size_in_pixel); | 479 DCHECK_LE(0, min_source_size_in_pixel); |
| 188 DCHECK_LE(0, desired_size_in_pixel); | 480 DCHECK_LE(0, desired_size_in_pixel); |
| 189 | 481 |
| 190 scoped_refptr<LargeIconWorker> worker = | 482 scoped_refptr<LargeIconCacheWorker> worker = new LargeIconCacheWorker( |
| 191 new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel, | 483 page_url, min_source_size_in_pixel, desired_size_in_pixel, callback, |
| 192 callback, background_task_runner_, tracker); | 484 background_task_runner_, tracker, favicon_service_); |
| 193 | 485 return worker->Start(); |
| 194 // TODO(beaudoin): For now this is just a wrapper around | 486 } |
| 195 // GetLargestRawFaviconForPageURL. Add the logic required to select the best | 487 |
| 196 // possible large icon. Also add logic to fetch-on-demand when the URL of | 488 base::CancelableTaskTracker::TaskId |
| 197 // a large icon is known but its bitmap is not available. | 489 LargeIconService::GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache( |
| 198 return favicon_service_->GetLargestRawFaviconForPageURL( | 490 const GURL& page_url, |
| 199 page_url, large_icon_types_, min_source_size_in_pixel, | 491 int min_source_size_in_pixel, |
| 200 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker), | 492 int desired_size_in_pixel, |
| 201 tracker); | 493 const favicon_base::LargeIconCallback& callback, |
| 494 base::CancelableTaskTracker* tracker) { | |
| 495 DCHECK_LE(0, min_source_size_in_pixel); | |
| 496 DCHECK_LE(0, desired_size_in_pixel); | |
| 497 | |
| 498 scoped_refptr<LargeIconGoogleServerWorker> worker = | |
| 499 new LargeIconGoogleServerWorker(page_url, min_source_size_in_pixel, | |
| 500 desired_size_in_pixel, callback, | |
| 501 background_task_runner_, tracker, | |
| 502 favicon_service_, image_fetcher_.get()); | |
| 503 return worker->Start(); | |
| 202 } | 504 } |
| 203 | 505 |
| 204 } // namespace favicon | 506 } // namespace favicon |
| OLD | NEW |