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

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

Issue 2784233003: [LargeIconService] Allow decoding of images in the service (Closed)
Patch Set: Peter's comments Created 3 years, 8 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 <memory> 7 #include <memory>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 } 49 }
50 50
51 GURL GetIconUrlForGoogleServerV2(const GURL& page_url, 51 GURL GetIconUrlForGoogleServerV2(const GURL& page_url,
52 int min_source_size_in_pixel) { 52 int min_source_size_in_pixel) {
53 return GURL(base::StringPrintf( 53 return GURL(base::StringPrintf(
54 kGoogleServerV2RequestFormat, kGoogleServerV2DesiredSizeInPixel, 54 kGoogleServerV2RequestFormat, kGoogleServerV2DesiredSizeInPixel,
55 min_source_size_in_pixel, kGoogleServerV2MaxSizeInPixel, 55 min_source_size_in_pixel, kGoogleServerV2MaxSizeInPixel,
56 page_url.spec().c_str())); 56 page_url.spec().c_str()));
57 } 57 }
58 58
59 bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
60 int min_source_size) {
61 return db_result.is_valid() &&
62 db_result.pixel_size.width() == db_result.pixel_size.height() &&
63 db_result.pixel_size.width() >= min_source_size;
64 }
65
pkotwicz 2017/04/04 02:34:40 Nit: Please add a comment to this function
jkrcal 2017/04/04 09:34:16 Done.
66 gfx::Image ResizeLargeIconOnBackgroundThread(
67 const favicon_base::FaviconRawBitmapResult& db_result,
68 int desired_size) {
69 gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
70 db_result.bitmap_data->front(), db_result.bitmap_data->size());
71
72 if (desired_size == 0 || db_result.pixel_size.width() == desired_size) {
73 return image;
74 }
75
76 SkBitmap resized = skia::ImageOperations::Resize(
77 image.AsBitmap(), skia::ImageOperations::RESIZE_LANCZOS3, desired_size,
78 desired_size);
79 return gfx::Image::CreateFrom1xBitmap(resized);
80 }
81
82 void ProcessIconOnBackgroundThread(
83 const favicon_base::FaviconRawBitmapResult& db_result,
84 int min_source_size,
85 int desired_size,
86 favicon_base::FaviconRawBitmapResult* raw_result,
87 SkBitmap* bitmap,
88 favicon_base::FallbackIconStyle* fallback_icon_style) {
89 gfx::Image image;
90 if (IsDbResultAdequate(db_result, min_source_size)) {
91 image = ResizeLargeIconOnBackgroundThread(db_result, desired_size);
92 }
93
94 if (!image.IsEmpty()) {
pkotwicz 2017/04/04 02:34:40 Nit: You can nest this if() inside of the if(IsDbR
jkrcal 2017/04/04 09:34:16 Done.
95 if (raw_result) {
96 *raw_result = db_result;
97 if (desired_size != 0)
98 raw_result->pixel_size = gfx::Size(desired_size, desired_size);
99 raw_result->bitmap_data = image.As1xPNGBytes();
100 }
101 if (bitmap) {
102 *bitmap = image.AsBitmap();
103 }
104 return;
105 }
106
107 if (!fallback_icon_style)
108 return;
109
110 *fallback_icon_style = favicon_base::FallbackIconStyle();
111 if (db_result.is_valid()) {
112 favicon_base::SetDominantColorAsBackground(db_result.bitmap_data,
113 fallback_icon_style);
114 }
115 }
116
59 // Processes the bitmap data returned from the FaviconService as part of a 117 // Processes the bitmap data returned from the FaviconService as part of a
60 // LargeIconService request. 118 // LargeIconService request.
61 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> { 119 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
62 public: 120 public:
121 // Exactly one of the callbacks is expected to be non-null.
63 LargeIconWorker(int min_source_size_in_pixel, 122 LargeIconWorker(int min_source_size_in_pixel,
64 int desired_size_in_pixel, 123 int desired_size_in_pixel,
65 favicon_base::LargeIconCallback callback, 124 favicon_base::LargeIconCallback raw_bitmap_callback,
125 favicon_base::LargeIconImageCallback image_callback,
66 scoped_refptr<base::TaskRunner> background_task_runner, 126 scoped_refptr<base::TaskRunner> background_task_runner,
67 base::CancelableTaskTracker* tracker); 127 base::CancelableTaskTracker* tracker);
68 128
69 // Must run on the owner (UI) thread in production. 129 // Must run on the owner (UI) thread in production.
70 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes 130 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes
71 // ProcessIconOnBackgroundThread() so we do not perform complex image 131 // ProcessIconOnBackgroundThread() so we do not perform complex image
72 // operations on the UI thread. 132 // operations on the UI thread.
73 void OnIconLookupComplete( 133 void OnIconLookupComplete(
74 const favicon_base::FaviconRawBitmapResult& bitmap_result); 134 const favicon_base::FaviconRawBitmapResult& raw_bitmap_result);
75 135
76 private: 136 private:
77 friend class base::RefCountedThreadSafe<LargeIconWorker>; 137 friend class base::RefCountedThreadSafe<LargeIconWorker>;
78 138
79 ~LargeIconWorker(); 139 ~LargeIconWorker();
80 140
81 // Must run on a background thread in production.
82 // Tries to resize |bitmap_result_| and pass the output to |callback_|. If
83 // that does not work, computes the icon fallback style and uses it to
84 // invoke |callback_|. This must be run on a background thread because image
85 // resizing and dominant color extraction can be expensive.
86 void ProcessIconOnBackgroundThread();
87
88 // Must run on a background thread in production.
89 // If |bitmap_result_| is square and large enough (>= |min_source_in_pixel_|),
90 // resizes it to |desired_size_in_pixel_| (but if |desired_size_in_pixel_| is
91 // 0 then don't resize). If successful, stores the resulting bitmap data
92 // into |resized_bitmap_result| and returns true.
93 bool ResizeLargeIconOnBackgroundThreadIfValid(
94 favicon_base::FaviconRawBitmapResult* resized_bitmap_result);
95
96 // Must run on the owner (UI) thread in production. 141 // Must run on the owner (UI) thread in production.
97 // Invoked when ProcessIconOnBackgroundThread() is done. 142 // Invoked when ProcessIconOnBackgroundThread() is done.
98 void OnIconProcessingComplete(); 143 void OnIconProcessingComplete();
99 144
100 int min_source_size_in_pixel_; 145 int min_source_size_in_pixel_;
101 int desired_size_in_pixel_; 146 int desired_size_in_pixel_;
102 favicon_base::LargeIconCallback callback_; 147 favicon_base::LargeIconCallback raw_bitmap_callback_;
148 favicon_base::LargeIconImageCallback image_callback_;
103 scoped_refptr<base::TaskRunner> background_task_runner_; 149 scoped_refptr<base::TaskRunner> background_task_runner_;
104 base::CancelableTaskTracker* tracker_; 150 base::CancelableTaskTracker* tracker_;
105 favicon_base::FaviconRawBitmapResult bitmap_result_; 151
106 std::unique_ptr<favicon_base::LargeIconResult> result_; 152 favicon_base::FaviconRawBitmapResult raw_bitmap_result_;
153 SkBitmap image_result_;
pkotwicz 2017/04/04 02:34:41 Nit: Rename this to |bitmap_result_|
jkrcal 2017/04/04 09:34:16 I'd like to keep this as there is an analogy with
pkotwicz 2017/04/04 12:43:42 It is confusing to have a variable which stores an
jkrcal 2017/04/04 14:44:40 Ok, done.
154 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style_;
pkotwicz 2017/04/04 02:34:40 Nit: You might as well make this: favicon_base::F
jkrcal 2017/04/04 09:34:16 If I drop the unique_ptr, I would have to have a "
pkotwicz 2017/04/04 12:43:42 I understand now
107 155
108 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker); 156 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker);
109 }; 157 };
110 158
111 LargeIconWorker::LargeIconWorker( 159 LargeIconWorker::LargeIconWorker(
112 int min_source_size_in_pixel, 160 int min_source_size_in_pixel,
113 int desired_size_in_pixel, 161 int desired_size_in_pixel,
114 favicon_base::LargeIconCallback callback, 162 favicon_base::LargeIconCallback raw_bitmap_callback,
163 favicon_base::LargeIconImageCallback image_callback,
115 scoped_refptr<base::TaskRunner> background_task_runner, 164 scoped_refptr<base::TaskRunner> background_task_runner,
116 base::CancelableTaskTracker* tracker) 165 base::CancelableTaskTracker* tracker)
117 : min_source_size_in_pixel_(min_source_size_in_pixel), 166 : min_source_size_in_pixel_(min_source_size_in_pixel),
118 desired_size_in_pixel_(desired_size_in_pixel), 167 desired_size_in_pixel_(desired_size_in_pixel),
119 callback_(callback), 168 raw_bitmap_callback_(raw_bitmap_callback),
169 image_callback_(image_callback),
120 background_task_runner_(background_task_runner), 170 background_task_runner_(background_task_runner),
121 tracker_(tracker) { 171 tracker_(tracker),
122 } 172 fallback_icon_style_(
173 base::MakeUnique<favicon_base::FallbackIconStyle>()) {}
123 174
124 LargeIconWorker::~LargeIconWorker() { 175 LargeIconWorker::~LargeIconWorker() {
125 } 176 }
126 177
127 void LargeIconWorker::OnIconLookupComplete( 178 void LargeIconWorker::OnIconLookupComplete(
128 const favicon_base::FaviconRawBitmapResult& bitmap_result) { 179 const favicon_base::FaviconRawBitmapResult& raw_bitmap_result) {
pkotwicz 2017/04/04 02:34:41 Can you please rename |raw_bitmap_result| to |db_r
jkrcal 2017/04/04 09:34:16 Makes sense! Done.
129 bitmap_result_ = bitmap_result;
130 tracker_->PostTaskAndReply( 180 tracker_->PostTaskAndReply(
131 background_task_runner_.get(), FROM_HERE, 181 background_task_runner_.get(), FROM_HERE,
132 base::Bind(&LargeIconWorker::ProcessIconOnBackgroundThread, this), 182 base::Bind(&ProcessIconOnBackgroundThread, raw_bitmap_result,
183 min_source_size_in_pixel_, desired_size_in_pixel_,
184 raw_bitmap_callback_ ? &raw_bitmap_result_ : nullptr,
185 image_callback_ ? &image_result_ : nullptr,
186 fallback_icon_style_.get()),
133 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this)); 187 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this));
134 } 188 }
135 189
136 void LargeIconWorker::ProcessIconOnBackgroundThread() { 190 void LargeIconWorker::OnIconProcessingComplete() {
137 favicon_base::FaviconRawBitmapResult resized_bitmap_result; 191 // Return the large icon, if we have the image.
138 if (ResizeLargeIconOnBackgroundThreadIfValid(&resized_bitmap_result)) { 192 if (raw_bitmap_callback_ && raw_bitmap_result_.is_valid()) {
139 result_.reset( 193 raw_bitmap_callback_.Run(favicon_base::LargeIconResult(raw_bitmap_result_));
140 new favicon_base::LargeIconResult(resized_bitmap_result)); 194 return;
195 }
pkotwicz 2017/04/04 02:34:41 For the sake of simplicity, perhaps do if (raw_bi
jkrcal 2017/04/04 09:34:16 Ok, done.
196 if (image_callback_ && !image_result_.isNull()) {
197 image_callback_.Run(favicon_base::LargeIconImageResult(
198 gfx::Image::CreateFrom1xBitmap(image_result_)));
199 return;
200 }
201
202 // Return fallback style, otherwise
203 if (raw_bitmap_callback_) {
204 raw_bitmap_callback_.Run(
205 favicon_base::LargeIconResult(fallback_icon_style_.release()));
141 } else { 206 } else {
142 // Failed to resize |bitmap_result_|, so compute fallback icon style. 207 image_callback_.Run(
143 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style( 208 favicon_base::LargeIconImageResult(fallback_icon_style_.release()));
144 new favicon_base::FallbackIconStyle());
145 if (bitmap_result_.is_valid()) {
146 favicon_base::SetDominantColorAsBackground(
147 bitmap_result_.bitmap_data, fallback_icon_style.get());
148 }
149 result_.reset(
150 new favicon_base::LargeIconResult(fallback_icon_style.release()));
151 } 209 }
152 } 210 }
153 211
154 bool LargeIconWorker::ResizeLargeIconOnBackgroundThreadIfValid(
155 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) {
156 // Require bitmap to be valid and square.
157 if (!bitmap_result_.is_valid() ||
158 bitmap_result_.pixel_size.width() != bitmap_result_.pixel_size.height())
159 return false;
160
161 // Require bitmap to be large enough. It's square, so just check width.
162 if (bitmap_result_.pixel_size.width() < min_source_size_in_pixel_)
163 return false;
164
165 *resized_bitmap_result = bitmap_result_;
166
167 // Special case: Can use |bitmap_result_| as is.
168 if (desired_size_in_pixel_ == 0 ||
169 bitmap_result_.pixel_size.width() == desired_size_in_pixel_)
170 return true;
171
172 // Resize bitmap: decode PNG, resize, and re-encode PNG.
173 SkBitmap decoded_bitmap;
174 if (!gfx::PNGCodec::Decode(bitmap_result_.bitmap_data->front(),
175 bitmap_result_.bitmap_data->size(), &decoded_bitmap))
176 return false;
177
178 SkBitmap resized_bitmap = skia::ImageOperations::Resize(
179 decoded_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
180 desired_size_in_pixel_, desired_size_in_pixel_);
181
182 std::vector<unsigned char> bitmap_data;
183 if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_bitmap, false, &bitmap_data))
184 return false;
185
186 resized_bitmap_result->pixel_size =
187 gfx::Size(desired_size_in_pixel_, desired_size_in_pixel_);
188 resized_bitmap_result->bitmap_data =
189 base::RefCountedBytes::TakeVector(&bitmap_data);
190 return true;
191 }
192
193 void LargeIconWorker::OnIconProcessingComplete() {
194 callback_.Run(*result_);
195 }
196
197 void OnFetchIconFromGoogleServerComplete( 212 void OnFetchIconFromGoogleServerComplete(
198 FaviconService* favicon_service, 213 FaviconService* favicon_service,
199 const GURL& page_url, 214 const GURL& page_url,
200 const base::Callback<void(bool success)>& callback, 215 const base::Callback<void(bool success)>& callback,
201 const std::string& icon_url, 216 const std::string& icon_url,
202 const gfx::Image& image, 217 const gfx::Image& image,
203 const image_fetcher::RequestMetadata& metadata) { 218 const image_fetcher::RequestMetadata& metadata) {
204 if (image.IsEmpty()) { 219 if (image.IsEmpty()) {
205 DLOG(WARNING) << "large icon server fetch empty " << icon_url; 220 DLOG(WARNING) << "large icon server fetch empty " << icon_url;
206 favicon_service->UnableToDownloadFavicon(GURL(icon_url)); 221 favicon_service->UnableToDownloadFavicon(GURL(icon_url));
(...skipping 28 matching lines...) Expand all
235 image_fetcher_(std::move(image_fetcher)) { 250 image_fetcher_(std::move(image_fetcher)) {
236 large_icon_types_.push_back(favicon_base::IconType::FAVICON); 251 large_icon_types_.push_back(favicon_base::IconType::FAVICON);
237 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON); 252 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON);
238 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON); 253 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON);
239 } 254 }
240 255
241 LargeIconService::~LargeIconService() { 256 LargeIconService::~LargeIconService() {
242 } 257 }
243 258
244 base::CancelableTaskTracker::TaskId 259 base::CancelableTaskTracker::TaskId
245 LargeIconService::GetLargeIconOrFallbackStyle( 260 LargeIconService::GetLargeIconOrFallbackStyle(
246 const GURL& page_url, 261 const GURL& page_url,
247 int min_source_size_in_pixel, 262 int min_source_size_in_pixel,
248 int desired_size_in_pixel, 263 int desired_size_in_pixel,
249 const favicon_base::LargeIconCallback& callback, 264 const favicon_base::LargeIconCallback& raw_bitmap_callback,
250 base::CancelableTaskTracker* tracker) { 265 base::CancelableTaskTracker* tracker) {
266 DCHECK_LE(1, min_source_size_in_pixel);
267 DCHECK_LE(0, desired_size_in_pixel);
268
269 scoped_refptr<LargeIconWorker> worker = new LargeIconWorker(
270 min_source_size_in_pixel, desired_size_in_pixel, raw_bitmap_callback,
271 favicon_base::LargeIconImageCallback(), background_task_runner_, tracker);
272
273 // TODO(beaudoin): For now this is just a wrapper around
274 // GetLargestRawFaviconForPageURL. Add the logic required to select the best
275 // possible large icon. Also add logic to fetch-on-demand when the URL of
276 // a large icon is known but its bitmap is not available.
277 return favicon_service_->GetLargestRawFaviconForPageURL(
278 page_url, large_icon_types_, min_source_size_in_pixel,
279 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
280 }
281
282 base::CancelableTaskTracker::TaskId
283 LargeIconService::GetLargeIconImageOrFallbackStyle(
284 const GURL& page_url,
285 int min_source_size_in_pixel,
286 int desired_size_in_pixel,
287 const favicon_base::LargeIconImageCallback& image_callback,
288 base::CancelableTaskTracker* tracker) {
251 DCHECK_LE(1, min_source_size_in_pixel); 289 DCHECK_LE(1, min_source_size_in_pixel);
252 DCHECK_LE(0, desired_size_in_pixel); 290 DCHECK_LE(0, desired_size_in_pixel);
253 291
254 scoped_refptr<LargeIconWorker> worker = 292 scoped_refptr<LargeIconWorker> worker =
255 new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel, 293 new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel,
256 callback, background_task_runner_, tracker); 294 favicon_base::LargeIconCallback(), image_callback,
295 background_task_runner_, tracker);
257 296
258 // TODO(beaudoin): For now this is just a wrapper around 297 // TODO(beaudoin): For now this is just a wrapper around
259 // GetLargestRawFaviconForPageURL. Add the logic required to select the best 298 // GetLargestRawFaviconForPageURL. Add the logic required to select the best
260 // possible large icon. Also add logic to fetch-on-demand when the URL of 299 // possible large icon. Also add logic to fetch-on-demand when the URL of
261 // a large icon is known but its bitmap is not available. 300 // a large icon is known but its bitmap is not available.
262 return favicon_service_->GetLargestRawFaviconForPageURL( 301 return favicon_service_->GetLargestRawFaviconForPageURL(
263 page_url, large_icon_types_, min_source_size_in_pixel, 302 page_url, large_icon_types_, min_source_size_in_pixel,
264 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker), 303 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker),
265 tracker); 304 tracker);
266 } 305 }
pkotwicz 2017/04/04 02:34:40 Please add a new function GetLargeIconImageOrFallb
jkrcal 2017/04/04 09:34:16 Done. (Named GetLargeIcon**OrFallbackStyleImpl to
267 306
268 void LargeIconService:: 307 void LargeIconService::
269 GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache( 308 GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
270 const GURL& page_url, 309 const GURL& page_url,
271 int min_source_size_in_pixel, 310 int min_source_size_in_pixel,
272 const base::Callback<void(bool success)>& callback) { 311 const base::Callback<void(bool success)>& callback) {
273 DCHECK_LE(0, min_source_size_in_pixel); 312 DCHECK_LE(0, min_source_size_in_pixel);
274 313
275 const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url); 314 const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url);
276 const GURL icon_url = 315 const GURL icon_url =
(...skipping 10 matching lines...) Expand all
287 326
288 image_fetcher_->SetDataUseServiceName( 327 image_fetcher_->SetDataUseServiceName(
289 data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE); 328 data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE);
290 image_fetcher_->StartOrQueueNetworkRequest( 329 image_fetcher_->StartOrQueueNetworkRequest(
291 icon_url.spec(), icon_url, 330 icon_url.spec(), icon_url,
292 base::Bind(&OnFetchIconFromGoogleServerComplete, favicon_service_, 331 base::Bind(&OnFetchIconFromGoogleServerComplete, favicon_service_,
293 page_url, callback)); 332 page_url, callback));
294 } 333 }
295 334
296 } // namespace favicon 335 } // namespace favicon
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698