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

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 #4 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
66 // Wraps the PNG data in |db_result| in a gfx::Image. If |desired_size| is not
67 // 0, the image gets decoded and resized to |desired_size| (in px). Must run on
68 // a background thread in production.
69 gfx::Image ResizeLargeIconOnBackgroundThread(
70 const favicon_base::FaviconRawBitmapResult& db_result,
71 int desired_size) {
72 gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
73 db_result.bitmap_data->front(), db_result.bitmap_data->size());
74
75 if (desired_size == 0 || db_result.pixel_size.width() == desired_size) {
76 return image;
77 }
78
79 SkBitmap resized = skia::ImageOperations::Resize(
80 image.AsBitmap(), skia::ImageOperations::RESIZE_LANCZOS3, desired_size,
81 desired_size);
82 return gfx::Image::CreateFrom1xBitmap(resized);
83 }
84
85 // Processes the |db_result| and writes the result into |raw_result| if
86 // |raw_result| is not nullptr or to |bitmap|, otherwise. If |db_result| is not
87 // valid or is smaller than |min_source_size|, the resulting fallback style is
88 // written into |fallback_icon_style|.
89 void ProcessIconOnBackgroundThread(
90 const favicon_base::FaviconRawBitmapResult& db_result,
91 int min_source_size,
92 int desired_size,
93 favicon_base::FaviconRawBitmapResult* raw_result,
94 SkBitmap* bitmap,
95 favicon_base::FallbackIconStyle* fallback_icon_style) {
96 if (IsDbResultAdequate(db_result, min_source_size)) {
97 gfx::Image image;
98 image = ResizeLargeIconOnBackgroundThread(db_result, desired_size);
99
100 if (!image.IsEmpty()) {
101 if (raw_result) {
102 *raw_result = db_result;
103 if (desired_size != 0)
104 raw_result->pixel_size = gfx::Size(desired_size, desired_size);
105 raw_result->bitmap_data = image.As1xPNGBytes();
106 }
107 if (bitmap) {
108 *bitmap = image.AsBitmap();
109 }
110 return;
111 }
112 }
113
114 if (!fallback_icon_style)
115 return;
116
117 *fallback_icon_style = favicon_base::FallbackIconStyle();
118 if (db_result.is_valid()) {
119 favicon_base::SetDominantColorAsBackground(db_result.bitmap_data,
120 fallback_icon_style);
121 }
122 }
123
59 // Processes the bitmap data returned from the FaviconService as part of a 124 // Processes the bitmap data returned from the FaviconService as part of a
60 // LargeIconService request. 125 // LargeIconService request.
61 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> { 126 class LargeIconWorker : public base::RefCountedThreadSafe<LargeIconWorker> {
62 public: 127 public:
128 // Exactly one of the callbacks is expected to be non-null.
63 LargeIconWorker(int min_source_size_in_pixel, 129 LargeIconWorker(int min_source_size_in_pixel,
64 int desired_size_in_pixel, 130 int desired_size_in_pixel,
65 favicon_base::LargeIconCallback callback, 131 favicon_base::LargeIconCallback raw_bitmap_callback,
132 favicon_base::LargeIconImageCallback image_callback,
66 scoped_refptr<base::TaskRunner> background_task_runner, 133 scoped_refptr<base::TaskRunner> background_task_runner,
67 base::CancelableTaskTracker* tracker); 134 base::CancelableTaskTracker* tracker);
68 135
69 // Must run on the owner (UI) thread in production. 136 // Must run on the owner (UI) thread in production.
70 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes 137 // Intermediate callback for GetLargeIconOrFallbackStyle(). Invokes
71 // ProcessIconOnBackgroundThread() so we do not perform complex image 138 // ProcessIconOnBackgroundThread() so we do not perform complex image
72 // operations on the UI thread. 139 // operations on the UI thread.
73 void OnIconLookupComplete( 140 void OnIconLookupComplete(
74 const favicon_base::FaviconRawBitmapResult& bitmap_result); 141 const favicon_base::FaviconRawBitmapResult& db_result);
75 142
76 private: 143 private:
77 friend class base::RefCountedThreadSafe<LargeIconWorker>; 144 friend class base::RefCountedThreadSafe<LargeIconWorker>;
78 145
79 ~LargeIconWorker(); 146 ~LargeIconWorker();
80 147
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. 148 // Must run on the owner (UI) thread in production.
97 // Invoked when ProcessIconOnBackgroundThread() is done. 149 // Invoked when ProcessIconOnBackgroundThread() is done.
98 void OnIconProcessingComplete(); 150 void OnIconProcessingComplete();
99 151
100 int min_source_size_in_pixel_; 152 int min_source_size_in_pixel_;
101 int desired_size_in_pixel_; 153 int desired_size_in_pixel_;
102 favicon_base::LargeIconCallback callback_; 154 favicon_base::LargeIconCallback raw_bitmap_callback_;
155 favicon_base::LargeIconImageCallback image_callback_;
103 scoped_refptr<base::TaskRunner> background_task_runner_; 156 scoped_refptr<base::TaskRunner> background_task_runner_;
104 base::CancelableTaskTracker* tracker_; 157 base::CancelableTaskTracker* tracker_;
105 favicon_base::FaviconRawBitmapResult bitmap_result_; 158
106 std::unique_ptr<favicon_base::LargeIconResult> result_; 159 favicon_base::FaviconRawBitmapResult raw_bitmap_result_;
160 SkBitmap bitmap_result_;
161 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style_;
107 162
108 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker); 163 DISALLOW_COPY_AND_ASSIGN(LargeIconWorker);
109 }; 164 };
110 165
111 LargeIconWorker::LargeIconWorker( 166 LargeIconWorker::LargeIconWorker(
112 int min_source_size_in_pixel, 167 int min_source_size_in_pixel,
113 int desired_size_in_pixel, 168 int desired_size_in_pixel,
114 favicon_base::LargeIconCallback callback, 169 favicon_base::LargeIconCallback raw_bitmap_callback,
170 favicon_base::LargeIconImageCallback image_callback,
115 scoped_refptr<base::TaskRunner> background_task_runner, 171 scoped_refptr<base::TaskRunner> background_task_runner,
116 base::CancelableTaskTracker* tracker) 172 base::CancelableTaskTracker* tracker)
117 : min_source_size_in_pixel_(min_source_size_in_pixel), 173 : min_source_size_in_pixel_(min_source_size_in_pixel),
118 desired_size_in_pixel_(desired_size_in_pixel), 174 desired_size_in_pixel_(desired_size_in_pixel),
119 callback_(callback), 175 raw_bitmap_callback_(raw_bitmap_callback),
176 image_callback_(image_callback),
120 background_task_runner_(background_task_runner), 177 background_task_runner_(background_task_runner),
121 tracker_(tracker) { 178 tracker_(tracker),
122 } 179 fallback_icon_style_(
180 base::MakeUnique<favicon_base::FallbackIconStyle>()) {}
123 181
124 LargeIconWorker::~LargeIconWorker() { 182 LargeIconWorker::~LargeIconWorker() {
125 } 183 }
126 184
127 void LargeIconWorker::OnIconLookupComplete( 185 void LargeIconWorker::OnIconLookupComplete(
128 const favicon_base::FaviconRawBitmapResult& bitmap_result) { 186 const favicon_base::FaviconRawBitmapResult& db_result) {
129 bitmap_result_ = bitmap_result;
130 tracker_->PostTaskAndReply( 187 tracker_->PostTaskAndReply(
131 background_task_runner_.get(), FROM_HERE, 188 background_task_runner_.get(), FROM_HERE,
132 base::Bind(&LargeIconWorker::ProcessIconOnBackgroundThread, this), 189 base::Bind(&ProcessIconOnBackgroundThread, db_result,
190 min_source_size_in_pixel_, desired_size_in_pixel_,
191 raw_bitmap_callback_ ? &raw_bitmap_result_ : nullptr,
192 image_callback_ ? &bitmap_result_ : nullptr,
193 fallback_icon_style_.get()),
133 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this)); 194 base::Bind(&LargeIconWorker::OnIconProcessingComplete, this));
134 } 195 }
135 196
136 void LargeIconWorker::ProcessIconOnBackgroundThread() { 197 void LargeIconWorker::OnIconProcessingComplete() {
137 favicon_base::FaviconRawBitmapResult resized_bitmap_result; 198 // If |raw_bitmap_callback_| is provided, return the raw result.
138 if (ResizeLargeIconOnBackgroundThreadIfValid(&resized_bitmap_result)) { 199 if (raw_bitmap_callback_) {
139 result_.reset( 200 if (raw_bitmap_result_.is_valid()) {
140 new favicon_base::LargeIconResult(resized_bitmap_result)); 201 raw_bitmap_callback_.Run(
141 } else { 202 favicon_base::LargeIconResult(raw_bitmap_result_));
142 // Failed to resize |bitmap_result_|, so compute fallback icon style. 203 return;
143 std::unique_ptr<favicon_base::FallbackIconStyle> fallback_icon_style(
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 } 204 }
149 result_.reset( 205 raw_bitmap_callback_.Run(
150 new favicon_base::LargeIconResult(fallback_icon_style.release())); 206 favicon_base::LargeIconResult(fallback_icon_style_.release()));
207 return;
151 } 208 }
152 }
153 209
154 bool LargeIconWorker::ResizeLargeIconOnBackgroundThreadIfValid( 210 if (!bitmap_result_.isNull()) {
155 favicon_base::FaviconRawBitmapResult* resized_bitmap_result) { 211 image_callback_.Run(favicon_base::LargeIconImageResult(
156 // Require bitmap to be valid and square. 212 gfx::Image::CreateFrom1xBitmap(bitmap_result_)));
157 if (!bitmap_result_.is_valid() || 213 return;
158 bitmap_result_.pixel_size.width() != bitmap_result_.pixel_size.height()) 214 }
159 return false; 215 image_callback_.Run(
160 216 favicon_base::LargeIconImageResult(fallback_icon_style_.release()));
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 } 217 }
196 218
197 void OnFetchIconFromGoogleServerComplete( 219 void OnFetchIconFromGoogleServerComplete(
198 FaviconService* favicon_service, 220 FaviconService* favicon_service,
199 const GURL& page_url, 221 const GURL& page_url,
200 const base::Callback<void(bool success)>& callback, 222 const base::Callback<void(bool success)>& callback,
201 const std::string& icon_url, 223 const std::string& icon_url,
202 const gfx::Image& image, 224 const gfx::Image& image,
203 const image_fetcher::RequestMetadata& metadata) { 225 const image_fetcher::RequestMetadata& metadata) {
204 if (image.IsEmpty()) { 226 if (image.IsEmpty()) {
(...skipping 30 matching lines...) Expand all
235 image_fetcher_(std::move(image_fetcher)) { 257 image_fetcher_(std::move(image_fetcher)) {
236 large_icon_types_.push_back(favicon_base::IconType::FAVICON); 258 large_icon_types_.push_back(favicon_base::IconType::FAVICON);
237 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON); 259 large_icon_types_.push_back(favicon_base::IconType::TOUCH_ICON);
238 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON); 260 large_icon_types_.push_back(favicon_base::IconType::TOUCH_PRECOMPOSED_ICON);
239 } 261 }
240 262
241 LargeIconService::~LargeIconService() { 263 LargeIconService::~LargeIconService() {
242 } 264 }
243 265
244 base::CancelableTaskTracker::TaskId 266 base::CancelableTaskTracker::TaskId
245 LargeIconService::GetLargeIconOrFallbackStyle( 267 LargeIconService::GetLargeIconOrFallbackStyle(
246 const GURL& page_url, 268 const GURL& page_url,
247 int min_source_size_in_pixel, 269 int min_source_size_in_pixel,
248 int desired_size_in_pixel, 270 int desired_size_in_pixel,
249 const favicon_base::LargeIconCallback& callback, 271 const favicon_base::LargeIconCallback& raw_bitmap_callback,
250 base::CancelableTaskTracker* tracker) { 272 base::CancelableTaskTracker* tracker) {
251 DCHECK_LE(1, min_source_size_in_pixel); 273 return GetLargeIconOrFallbackStyleImpl(
252 DCHECK_LE(0, desired_size_in_pixel); 274 page_url, min_source_size_in_pixel, desired_size_in_pixel,
275 raw_bitmap_callback, favicon_base::LargeIconImageCallback(), tracker);
276 }
253 277
254 scoped_refptr<LargeIconWorker> worker = 278 base::CancelableTaskTracker::TaskId
255 new LargeIconWorker(min_source_size_in_pixel, desired_size_in_pixel, 279 LargeIconService::GetLargeIconImageOrFallbackStyle(
256 callback, background_task_runner_, tracker); 280 const GURL& page_url,
257 281 int min_source_size_in_pixel,
258 // TODO(beaudoin): For now this is just a wrapper around 282 int desired_size_in_pixel,
259 // GetLargestRawFaviconForPageURL. Add the logic required to select the best 283 const favicon_base::LargeIconImageCallback& image_callback,
260 // possible large icon. Also add logic to fetch-on-demand when the URL of 284 base::CancelableTaskTracker* tracker) {
261 // a large icon is known but its bitmap is not available. 285 return GetLargeIconOrFallbackStyleImpl(
262 return favicon_service_->GetLargestRawFaviconForPageURL( 286 page_url, min_source_size_in_pixel, desired_size_in_pixel,
263 page_url, large_icon_types_, min_source_size_in_pixel, 287 favicon_base::LargeIconCallback(), image_callback, tracker);
264 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker),
265 tracker);
266 } 288 }
267 289
268 void LargeIconService:: 290 void LargeIconService::
269 GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache( 291 GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
270 const GURL& page_url, 292 const GURL& page_url,
271 int min_source_size_in_pixel, 293 int min_source_size_in_pixel,
272 const base::Callback<void(bool success)>& callback) { 294 const base::Callback<void(bool success)>& callback) {
273 DCHECK_LE(0, min_source_size_in_pixel); 295 DCHECK_LE(0, min_source_size_in_pixel);
274 296
275 const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url); 297 const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url);
(...skipping 10 matching lines...) Expand all
286 } 308 }
287 309
288 image_fetcher_->SetDataUseServiceName( 310 image_fetcher_->SetDataUseServiceName(
289 data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE); 311 data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE);
290 image_fetcher_->StartOrQueueNetworkRequest( 312 image_fetcher_->StartOrQueueNetworkRequest(
291 icon_url.spec(), icon_url, 313 icon_url.spec(), icon_url,
292 base::Bind(&OnFetchIconFromGoogleServerComplete, favicon_service_, 314 base::Bind(&OnFetchIconFromGoogleServerComplete, favicon_service_,
293 page_url, callback)); 315 page_url, callback));
294 } 316 }
295 317
318 base::CancelableTaskTracker::TaskId
319 LargeIconService::GetLargeIconOrFallbackStyleImpl(
320 const GURL& page_url,
321 int min_source_size_in_pixel,
322 int desired_size_in_pixel,
323 const favicon_base::LargeIconCallback& raw_bitmap_callback,
324 const favicon_base::LargeIconImageCallback& image_callback,
325 base::CancelableTaskTracker* tracker) {
326 DCHECK_LE(1, min_source_size_in_pixel);
327 DCHECK_LE(0, desired_size_in_pixel);
328
329 scoped_refptr<LargeIconWorker> worker = new LargeIconWorker(
330 min_source_size_in_pixel, desired_size_in_pixel, raw_bitmap_callback,
331 image_callback, background_task_runner_, tracker);
332
333 // TODO(beaudoin): For now this is just a wrapper around
334 // GetLargestRawFaviconForPageURL. Add the logic required to select the best
335 // possible large icon. Also add logic to fetch-on-demand when the URL of
336 // a large icon is known but its bitmap is not available.
337 return favicon_service_->GetLargestRawFaviconForPageURL(
338 page_url, large_icon_types_, min_source_size_in_pixel,
339 base::Bind(&LargeIconWorker::OnIconLookupComplete, worker), tracker);
340 }
341
296 } // namespace favicon 342 } // namespace favicon
OLDNEW
« no previous file with comments | « components/favicon/core/large_icon_service.h ('k') | components/favicon/core/large_icon_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698