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

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

Issue 1122103003: [Large Icon Service] Move icon resizing into worker thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment cleanup; making ResizeLargeIconOnBackgroundThreadIfValid() a member function. Created 5 years, 7 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
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 "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/task_runner.h"
12 #include "base/threading/sequenced_worker_pool.h"
7 #include "components/favicon/core/favicon_service.h" 13 #include "components/favicon/core/favicon_service.h"
8 #include "components/favicon_base/fallback_icon_style.h" 14 #include "components/favicon_base/fallback_icon_style.h"
9 #include "components/favicon_base/favicon_types.h" 15 #include "components/favicon_base/favicon_types.h"
16 #include "content/public/browser/browser_thread.h"
10 #include "skia/ext/image_operations.h" 17 #include "skia/ext/image_operations.h"
11 #include "ui/gfx/codec/png_codec.h" 18 #include "ui/gfx/codec/png_codec.h"
12 #include "ui/gfx/geometry/size.h" 19 #include "ui/gfx/geometry/size.h"
13 20
21 namespace {
22
23 // Processes the bitmap data returned from the FaviconService as part of a
24 // LargeIconService request.
25 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
26 public:
27 LargeIconWorker(int min_source_size_in_pixel,
28 int desired_size_in_pixel,
29 favicon_base::LargeIconCallback callback,
30 scoped_refptr<base::TaskRunner> background_task_runner,
31 base::CancelableTaskTracker* tracker);
32
33 // Must run on the owner (UI) thread in production.
34 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes
35 // ProcessIconOnBackgroundThread() so we do not perform complex image
36 // operations on the UI thread.
37 void OnIconLookupComplete(
38 const favicon_base::FaviconRawBitmapResult& bitmap_result);
39
40 private:
41 friend class base::RefCountedThreadSafe<LargeIconWorker>;
42
43 ~LargeIconWorker();
44
45 // Must run on a background thread in production.
46 // Tries to resize |bitmap_result_| and pass the output to |callback_|. If
47 // that does not work, computes the icon fallback style and uses it to
48 // invoke |callback_|. This must be run on a background thread because image
49 // resizing and dominant color extraction can be expensive.
50 void ProcessIconOnBackgroundThread();
51
52 // Must run on a background thread in production.
53 // If |bitmap_result_| is square and large enough (>= |min_source_in_pixel_|),
54 // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is
55 // 0 then don't resize). If successful, stores the resulting bitmap data
56 // into |resized_bitmap_result| and returns true.
57 bool ResizeLargeIconOnBackgroundThreadIfValid(
58 favicon_base::FaviconRawBitmapResult* resized_bitmap_result);
59
60 // Must run on the owner (UI) thread in production.
61 // Invoked when ProcessIconOnBackgroundThread() is done.
62 void OnIconProcessingComplete();
63
64 int min_source_size_in_pixel_;
65 int desired_size_in_pixel_;
66 favicon_base::LargeIconCallback callback_;
67 scoped_refptr<base::TaskRunner> background_task_runner_;
68 base::CancelableTaskTracker* tracker_;
69 favicon_base::FaviconRawBitmapResult bitmap_result_;
70 scoped_ptr<favicon_base::LargeIconResult> result_;
71
72 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker);
73 };
74
75 LargeIconWorker::LargeIconWorker(
76 int min_source_size_in_pixel,
77 int desired_size_in_pixel,
78 favicon_base::LargeIconCallback callback,
79 scoped_refptr<base::TaskRunner> background_task_runner,
80 base::CancelableTaskTracker* tracker)
81 : min_source_size_in_pixel_(min_source_size_in_pixel),
82 desired_size_in_pixel_(desired_size_in_pixel),
83 callback_(callback),
84 background_task_runner_(background_task_runner),
85 tracker_(tracker) {
86 }
87
88 LargeIconWorker::~LargeIconWorker() {
89 }
90
91 void LargeIconWorker::OnIconLookupComplete(
92 const favicon_base::FaviconRawBitmapResult& bitmap_result) {
93 bitmap_result_ = bitmap_result;
94 tracker_->PostTaskAndReply(
95 background_task_runner_.get(), FROM_HERE,
96 base::Bind(&LargeIconWorker::ProcessIconOnBackgroundThread, this),
97 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this));
98 }
99
100 void LargeIconWorker::ProcessIconOnBackgroundThread() {
101 favicon_base::FaviconRawBitmapResult resized_bitmap_result;
102 if (ResizeLargeIconOnBackgroundThreadIfValid(&resized_bitmap_result)) {
103 result_.reset(
104 new favicon_base::LargeIconResult(resized_bitmap_result));
105 } else {
106 // Failed to resize |bitmap_result_|, so compute fallback icon style.
107 scoped_ptr<favicon_base::FallbackIconStyle> fallback_icon_style(
108 new favicon_base::FallbackIconStyle());
109 if (bitmap_result_.is_valid()) {
110 favicon_base::SetDominantColorAsBackground(
111 bitmap_result_.bitmap_data, fallback_icon_style.get());
112 }
113 result_.reset(
114 new favicon_base::LargeIconResult(fallback_icon_style.release()));
115 }
116 }
117
118 bool LargeIconWorker::ResizeLargeIconOnBackgroundThreadIfValid(
119 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) {
120 // Require bitmap to be valid and square.
121 if (!bitmap_result_.is_valid() ||
122 bitmap_result_.pixel_size.width() != bitmap_result_.pixel_size.height())
123 return false;
124
125 // Require bitmap to be large enough. It's square, so just check width.
126 if (bitmap_result_.pixel_size.width() < min_source_size_in_pixel_)
127 return false;
128
129 *resized_bitmap_result = bitmap_result_;
130
131 // Special case: Can use |bitmap_result_| as is.
132 if (desired_size_in_pixel_ == 0 ||
133 bitmap_result_.pixel_size.width() == desired_size_in_pixel_)
134 return true;
135
136 // Resize bitmap: decode PNG, resize, and re-encode PNG.
137 SkBitmap decoded_bitmap;
138 if (!gfx::PNGCodec::Decode(bitmap_result_.bitmap_data->front(),
139 bitmap_result_.bitmap_data->size(), &decoded_bitmap))
140 return false;
141
142 SkBitmap resized_bitmap = skia::ImageOperations::Resize(
143 decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
144 desired_size_in_pixel_, desired_size_in_pixel_);
145
146 std::vector<unsigned char> bitmap_data;
147 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_bitmap, false, &bitmap_data))
148 return false;
149
150 resized_bitmap_result->pixel_size =
151 gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_);
152 resized_bitmap_result->bitmap_data =
153 base::RefCountedBytes::TakeVector(&bitmap_data);
154 return true;
155 }
156
157 void LargeIconWorker::OnIconProcessingComplete() {
158 callback_.Run(*result_);
159 }
160
161 } // namespace
162
14 namespace favicon { 163 namespace favicon {
15 164
16 LargeIconService::LargeIconService(FaviconService* favicon_service) 165 LargeIconService::LargeIconService(FaviconService* favicon_service)
17 : favicon_service_(favicon_service) { 166 : favicon_service_(favicon_service) {
18 large_icon_types_.push_back(favicon_base::IconType::FAVICON); 167 large_icon_types_.push_back(favicon_base::IconType::FAVICON);
19 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON); 168 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON);
20 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON); 169 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON);
21 } 170 }
22 171
23 LargeIconService::~LargeIconService() { 172 LargeIconService::~LargeIconService() {
24 } 173 }
25 174
26 base::CancelableTaskTracker::TaskId 175 base::CancelableTaskTracker::TaskId
27 LargeIconService::GetLargeIconOrFallbackStyle( 176 LargeIconService::GetLargeIconOrFallbackStyle(
28 const GURL& page_url, 177 const GURL& page_url,
29 int min_source_size_in_pixel, 178 int min_source_size_in_pixel,
30 int desired_size_in_pixel, 179 int desired_size_in_pixel,
31 const favicon_base::LargeIconCallback& callback, 180 const favicon_base::LargeIconCallback& callback,
32 base::CancelableTaskTracker* tracker) { 181 base::CancelableTaskTracker* tracker) {
33 DCHECK_LE(1, min_source_size_in_pixel); 182 DCHECK_LE(1, min_source_size_in_pixel);
34 DCHECK_LE(0, desired_size_in_pixel); 183 DCHECK_LE(0, desired_size_in_pixel);
35 184
185 scoped_refptr<LargeIconWorker> worker =
186 new LargeIconWorker(min_source_size_in_pixel,
187 desired_size_in_pixel, callback, GetBackgroundTaskRunner(), tracker);
188
36 // TODO(beaudoin): For now this is just a wrapper around 189 // TODO(beaudoin): For now this is just a wrapper around
37 // GetLargestRawFaviconForPageURL. Add the logic required to select the best 190 // GetLargestRawFaviconForPageURL. Add the logic required to select the best
38 // possible large icon. Also add logic to fetch-on-demand when the URL of 191 // possible large icon. Also add logic to fetch-on-demand when the URL of
39 // a large icon is known but its bitmap is not available. 192 // a large icon is known but its bitmap is not available.
40 return favicon_service_->GetLargestRawFaviconForPageURL( 193 return favicon_service_->GetLargestRawFaviconForPageURL(
41 page_url, 194 page_url, large_icon_types_, desired_size_in_pixel,
42 large_icon_types_, 195 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker),
43 std::max(min_source_size_in_pixel, desired_size_in_pixel),
44 base::Bind(&LargeIconService::RunLargeIconCallback,
45 base::Unretained(this), callback, min_source_size_in_pixel,
46 desired_size_in_pixel),
47 tracker); 196 tracker);
48 } 197 }
49 198
50 bool LargeIconService::ResizeLargeIconIfValid( 199 // Returns TaskRunner used to execute background task.
51 int min_source_size_in_pixel, 200 scoped_refptr<base::TaskRunner> LargeIconService::GetBackgroundTaskRunner() {
52 int desired_size_in_pixel, 201 return content::BrowserThread::GetBlockingPool()
53 const favicon_base::FaviconRawBitmapResult& bitmap_result, 202 ->GetTaskRunnerWithShutdownBehavior(
54 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) { 203 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
55 // Require bitmap to be valid and square.
56 if (!bitmap_result.is_valid() ||
57 bitmap_result.pixel_size.width() != bitmap_result.pixel_size.height())
58 return false;
59
60 // Require bitmap to be large enough. It's square, so just check width.
61 if (bitmap_result.pixel_size.width() < min_source_size_in_pixel)
62 return false;
63
64 *resized_bitmap_result = bitmap_result;
65
66 // Special case: Can use |bitmap_result| as is.
67 if (desired_size_in_pixel == 0 ||
68 bitmap_result.pixel_size.width() == desired_size_in_pixel)
69 return true;
70
71 // Resize bitmap: decode PNG, resize, and re-encode PNG.
72 SkBitmap decoded_bitmap;
73 if (!gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
74 bitmap_result.bitmap_data->size(), &decoded_bitmap))
75 return false;
76
77 SkBitmap resized_bitmap = skia::ImageOperations::Resize(
78 decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
79 desired_size_in_pixel, desired_size_in_pixel);
80
81 std::vector<unsigned char> bitmap_data;
82 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_bitmap, false, &bitmap_data))
83 return false;
84
85 resized_bitmap_result->pixel_size =
86 gfx::Size(desired_size_in_pixel, desired_size_in_pixel);
87 resized_bitmap_result->bitmap_data =
88 base::RefCountedBytes::TakeVector(&bitmap_data);
89 return true;
90 }
91
92 void LargeIconService::RunLargeIconCallback(
93 const favicon_base::LargeIconCallback& callback,
94 int min_source_size_in_pixel,
95 int desired_size_in_pixel,
96 const favicon_base::FaviconRawBitmapResult& bitmap_result) {
97 favicon_base::FaviconRawBitmapResult resized_bitmap_result;
98 if (ResizeLargeIconIfValid(min_source_size_in_pixel, desired_size_in_pixel,
99 bitmap_result, &resized_bitmap_result)) {
100 callback.Run(favicon_base::LargeIconResult(resized_bitmap_result));
101 return;
102 }
103
104 // Failed to resize |bitmap_result|, so compute fallback icon style.
105 favicon_base::LargeIconResult result(new favicon_base::FallbackIconStyle());
106 if (bitmap_result.is_valid()) {
107 favicon_base::SetDominantColorAsBackground(
108 bitmap_result.bitmap_data, result.fallback_icon_style.get());
109 }
110 callback.Run(result);
111 } 204 }
112 205
113 } // namespace favicon 206 } // namespace favicon
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698