Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1564)

Side by Side Diff: components/favicon/core/large_icon_service.cc

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

Powered by Google App Engine
This is Rietveld 408576698