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

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

Issue 2739173002: Always select best favicon bitmap (Closed)
Patch Set: Rebased. 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/favicon_handler.h" 5 #include "components/favicon/core/favicon_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/memory/ref_counted_memory.h" 13 #include "base/memory/ref_counted_memory.h"
14 #include "build/build_config.h" 14 #include "build/build_config.h"
15 #include "components/favicon/core/favicon_service.h" 15 #include "components/favicon/core/favicon_service.h"
16 #include "components/favicon_base/favicon_util.h" 16 #include "components/favicon_base/favicon_util.h"
17 #include "components/favicon_base/select_favicon_frames.h" 17 #include "components/favicon_base/select_favicon_frames.h"
18 #include "skia/ext/image_operations.h" 18 #include "skia/ext/image_operations.h"
19 #include "ui/gfx/codec/png_codec.h" 19 #include "ui/gfx/codec/png_codec.h"
20 #include "ui/gfx/image/image_skia.h" 20 #include "ui/gfx/image/image_skia.h"
21 #include "ui/gfx/image/image_util.h" 21 #include "ui/gfx/image/image_util.h"
22 22
23 namespace favicon { 23 namespace favicon {
24 namespace { 24 namespace {
25 25
26 // Size (along each axis) of a touch icon. This currently corresponds to 26 bool DoUrlAndIconMatch(const FaviconSelector::Candidate& candidate,
27 // the apple touch icon for iPad.
28 const int kTouchIconSize = 144;
29
30 bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
31 const GURL& url, 27 const GURL& url,
32 favicon_base::IconType icon_type) { 28 favicon_base::IconType icon_type) {
33 return favicon_url.icon_url == url && favicon_url.icon_type == icon_type; 29 return candidate.icon_url == url && candidate.icon_type == icon_type;
34 } 30 }
35 31
36 // Returns true if all of the icon URLs and icon types in |bitmap_results| are 32 // Returns true if all of the icon URLs and icon types in |bitmap_results| are
37 // identical and if they match the icon URL and icon type in |favicon_url|. 33 // identical and if they match the icon URL and icon type in |candidate|.
38 // Returns false if |bitmap_results| is empty. 34 // Returns false if |bitmap_results| is empty.
39 bool DoUrlsAndIconsMatch( 35 bool DoUrlsAndIconsMatch(
40 const FaviconURL& favicon_url, 36 const FaviconSelector::Candidate& candidate,
41 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) { 37 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
42 if (bitmap_results.empty()) 38 if (bitmap_results.empty())
43 return false; 39 return false;
44 40
45 const favicon_base::IconType icon_type = favicon_url.icon_type;
46
47 for (const auto& bitmap_result : bitmap_results) { 41 for (const auto& bitmap_result : bitmap_results) {
48 if (favicon_url.icon_url != bitmap_result.icon_url || 42 if (!DoUrlAndIconMatch(candidate, bitmap_result.icon_url,
49 icon_type != bitmap_result.icon_type) { 43 bitmap_result.icon_type)) {
50 return false; 44 return false;
51 } 45 }
52 } 46 }
53 return true; 47 return true;
54 } 48 }
55 49
56 // Return true if |bitmap_result| is expired. 50 // Return true if |bitmap_result| is expired.
57 bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) { 51 bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
58 return bitmap_result.expired; 52 return bitmap_result.expired;
59 } 53 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 return false; 100 return false;
107 } 101 }
108 102
109 // Returns true if at least one of |bitmap_results| is valid. 103 // Returns true if at least one of |bitmap_results| is valid.
110 bool HasValidResult( 104 bool HasValidResult(
111 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) { 105 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
112 return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) != 106 return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
113 bitmap_results.end(); 107 bitmap_results.end();
114 } 108 }
115 109
116 // Returns the index of the entry with the largest area.
117 int GetLargestSizeIndex(const std::vector<gfx::Size>& sizes) {
118 DCHECK(!sizes.empty());
119 size_t ret = 0;
120 for (size_t i = 1; i < sizes.size(); ++i) {
121 if (sizes[ret].GetArea() < sizes[i].GetArea())
122 ret = i;
123 }
124 return static_cast<int>(ret);
125 }
126
127 // Return the index of a size which is same as the given |size|, -1 returned if
128 // there is no such bitmap.
129 int GetIndexBySize(const std::vector<gfx::Size>& sizes,
130 const gfx::Size& size) {
131 DCHECK(!sizes.empty());
132 std::vector<gfx::Size>::const_iterator i =
133 std::find(sizes.begin(), sizes.end(), size);
134 if (i == sizes.end())
135 return -1;
136
137 return static_cast<int>(i - sizes.begin());
138 }
139
140 // Compare function used for std::stable_sort to sort as descend.
141 bool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) {
142 int area1 = 0;
143 if (!b1.icon_sizes.empty())
144 area1 = b1.icon_sizes.front().GetArea();
145
146 int area2 = 0;
147 if (!b2.icon_sizes.empty())
148 area2 = b2.icon_sizes.front().GetArea();
149
150 return area1 > area2;
151 }
152
153 // Sorts the entries in |image_urls| by icon size in descending order.
154 // Discards all but the largest size for each FaviconURL.
155 void SortAndPruneImageUrls(std::vector<FaviconURL>* image_urls) {
156 // Not using const-reference since the loop mutates FaviconURL::icon_sizes.
157 for (FaviconURL& image_url : *image_urls) {
158 if (image_url.icon_sizes.empty())
159 continue;
160
161 gfx::Size largest =
162 image_url.icon_sizes[GetLargestSizeIndex(image_url.icon_sizes)];
163 image_url.icon_sizes.clear();
164 image_url.icon_sizes.push_back(largest);
165 }
166 std::stable_sort(image_urls->begin(), image_urls->end(), CompareIconSize);
167 }
168
169 // Checks whether two FaviconURLs are equal ignoring the icon sizes. 110 // Checks whether two FaviconURLs are equal ignoring the icon sizes.
170 bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) { 111 bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) {
171 return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url; 112 return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url;
172 } 113 }
173 114
115 std::vector<FaviconSelector::TargetSizeSpec> GetTargetSizeSpecs(
116 FaviconDriverObserver::NotificationIconType handler_type) {
117 switch (handler_type) {
118 case FaviconDriverObserver::NON_TOUCH_16_DIP:
119 return FaviconSelector::TargetSizeSpec::For16x16Dips();
120 case FaviconDriverObserver::NON_TOUCH_LARGEST:
121 case FaviconDriverObserver::TOUCH_LARGEST:
122 return {FaviconSelector::TargetSizeSpec::ForLargest()};
123 }
124 NOTREACHED();
125 }
126
174 } // namespace 127 } // namespace
175 128
176 //////////////////////////////////////////////////////////////////////////////// 129 ////////////////////////////////////////////////////////////////////////////////
177 130
178 FaviconHandler::DownloadRequest::DownloadRequest() 131 FaviconHandler::DownloadRequest::DownloadRequest()
179 : icon_type(favicon_base::INVALID_ICON) { 132 : icon_type(favicon_base::INVALID_ICON) {
180 } 133 }
181 134
182 FaviconHandler::DownloadRequest::~DownloadRequest() { 135 FaviconHandler::DownloadRequest::~DownloadRequest() {
183 } 136 }
184 137
185 FaviconHandler::DownloadRequest::DownloadRequest( 138 FaviconHandler::DownloadRequest::DownloadRequest(
186 const GURL& image_url, 139 const GURL& image_url,
187 favicon_base::IconType icon_type) 140 favicon_base::IconType icon_type)
188 : image_url(image_url), icon_type(icon_type) { 141 : image_url(image_url), icon_type(icon_type) {}
189 }
190 142
191 //////////////////////////////////////////////////////////////////////////////// 143 ////////////////////////////////////////////////////////////////////////////////
192 144
193 FaviconHandler::FaviconCandidate::FaviconCandidate()
194 : score(0), icon_type(favicon_base::INVALID_ICON) {
195 }
196
197 FaviconHandler::FaviconCandidate::~FaviconCandidate() {
198 }
199
200 FaviconHandler::FaviconCandidate::FaviconCandidate(
201 const GURL& image_url,
202 const gfx::Image& image,
203 float score,
204 favicon_base::IconType icon_type)
205 : image_url(image_url),
206 image(image),
207 score(score),
208 icon_type(icon_type) {}
209
210 ////////////////////////////////////////////////////////////////////////////////
211
212 FaviconHandler::FaviconHandler( 145 FaviconHandler::FaviconHandler(
213 FaviconService* service, 146 FaviconService* service,
214 Delegate* delegate, 147 Delegate* delegate,
215 FaviconDriverObserver::NotificationIconType handler_type) 148 FaviconDriverObserver::NotificationIconType handler_type)
216 : handler_type_(handler_type), 149 : handler_type_(handler_type),
217 got_favicon_from_history_(false), 150 got_favicon_from_history_(false),
218 initial_history_result_expired_or_incomplete_(false), 151 initial_history_result_expired_or_incomplete_(false),
219 redownload_icons_(false), 152 redownload_icons_(false),
220 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), 153 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)),
221 download_largest_icon_( 154 target_size_spec_(GetTargetSizeSpecs(handler_type).front()),
pkotwicz 2017/03/20 03:25:16 Won't this regress the current behavior?
mastiz 2017/03/20 08:07:27 As I mentioned in my earlier message, there's the
222 handler_type == FaviconDriverObserver::NON_TOUCH_LARGEST ||
223 handler_type == FaviconDriverObserver::TOUCH_LARGEST),
224 notification_icon_type_(favicon_base::INVALID_ICON), 155 notification_icon_type_(favicon_base::INVALID_ICON),
225 service_(service), 156 service_(service),
226 delegate_(delegate), 157 delegate_(delegate),
227 current_candidate_index_(0u),
228 weak_ptr_factory_(this) { 158 weak_ptr_factory_(this) {
229 DCHECK(delegate_); 159 DCHECK(delegate_);
230 } 160 }
231 161
232 FaviconHandler::~FaviconHandler() { 162 FaviconHandler::~FaviconHandler() {
233 } 163 }
234 164
235 // static 165 // static
236 int FaviconHandler::GetIconTypesFromHandlerType( 166 int FaviconHandler::GetIconTypesFromHandlerType(
237 FaviconDriverObserver::NotificationIconType handler_type) { 167 FaviconDriverObserver::NotificationIconType handler_type) {
(...skipping 12 matching lines...) Expand all
250 180
251 url_ = url; 181 url_ = url;
252 182
253 initial_history_result_expired_or_incomplete_ = false; 183 initial_history_result_expired_or_incomplete_ = false;
254 redownload_icons_ = false; 184 redownload_icons_ = false;
255 got_favicon_from_history_ = false; 185 got_favicon_from_history_ = false;
256 download_requests_.clear(); 186 download_requests_.clear();
257 image_urls_.clear(); 187 image_urls_.clear();
258 notification_icon_url_ = GURL(); 188 notification_icon_url_ = GURL();
259 notification_icon_type_ = favicon_base::INVALID_ICON; 189 notification_icon_type_ = favicon_base::INVALID_ICON;
260 current_candidate_index_ = 0u; 190 current_candidate_.reset();
261 best_favicon_candidate_ = FaviconCandidate(); 191 selector_.reset();
192 best_favicon_image_ = gfx::Image();
262 193
263 // Request the favicon from the history service. In parallel to this the 194 // Request the favicon from the history service. In parallel to this the
264 // renderer is going to notify us (well WebContents) when the favicon url is 195 // renderer is going to notify us (well WebContents) when the favicon url is
265 // available. 196 // available.
266 if (service_) { 197 if (service_) {
267 service_->GetFaviconForPageURL( 198 service_->GetFaviconForPageURL(
268 url_, icon_types_, preferred_icon_size(), 199 url_, icon_types_, preferred_icon_size(),
269 base::Bind( 200 base::Bind(
270 &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, 201 &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
271 base::Unretained(this)), 202 base::Unretained(this)),
272 &cancelable_task_tracker_); 203 &cancelable_task_tracker_);
273 } 204 }
274 } 205 }
275 206
276 bool FaviconHandler::UpdateFaviconCandidate(const GURL& image_url,
277 const gfx::Image& image,
278 float score,
279 favicon_base::IconType icon_type) {
280 bool replace_best_favicon_candidate = false;
281 bool exact_match = false;
282 if (download_largest_icon_) {
283 replace_best_favicon_candidate =
284 image.Size().GetArea() >
285 best_favicon_candidate_.image.Size().GetArea();
286
287 gfx::Size largest = best_favicon_candidate_.image.Size();
288 if (replace_best_favicon_candidate)
289 largest = image.Size();
290
291 // The size of the downloaded icon may not match the declared size. Stop
292 // downloading if:
293 // - current candidate is only candidate.
294 // - next candidate doesn't have sizes attributes, in this case, the rest
295 // candidates don't have sizes attribute either, stop downloading now,
296 // otherwise, all favicon without sizes attribute are downloaded.
297 // - next candidate has sizes attribute and it is not larger than largest,
298 // - current candidate is maximal one we want.
299 const int maximal_size = GetMaximalIconSize(icon_type);
300 if (current_candidate_index_ + 1 >= image_urls_.size()) {
301 exact_match = true;
302 } else {
303 FaviconURL next_image_url = image_urls_[current_candidate_index_ + 1];
304 exact_match = next_image_url.icon_sizes.empty() ||
305 next_image_url.icon_sizes[0].GetArea() <= largest.GetArea() ||
306 (image.Size().width() == maximal_size &&
307 image.Size().height() == maximal_size);
308 }
309 } else {
310 exact_match = score == 1 || preferred_icon_size() == 0;
311 replace_best_favicon_candidate =
312 exact_match ||
313 best_favicon_candidate_.icon_type == favicon_base::INVALID_ICON ||
314 score > best_favicon_candidate_.score;
315 }
316 if (replace_best_favicon_candidate) {
317 best_favicon_candidate_ =
318 FaviconCandidate(image_url, image, score, icon_type);
319 }
320 return exact_match;
321 }
322
323 void FaviconHandler::SetFavicon(const GURL& icon_url, 207 void FaviconHandler::SetFavicon(const GURL& icon_url,
324 const gfx::Image& image, 208 const gfx::Image& image,
325 favicon_base::IconType icon_type) { 209 favicon_base::IconType icon_type) {
326 if (service_ && ShouldSaveFavicon()) 210 if (service_ && ShouldSaveFavicon())
327 service_->SetFavicons(url_, icon_url, icon_type, image); 211 service_->SetFavicons(url_, icon_url, icon_type, image);
328 212
329 NotifyFaviconUpdated(icon_url, icon_type, image); 213 NotifyFaviconUpdated(icon_url, icon_type, image);
330 } 214 }
331 215
332 void FaviconHandler::NotifyFaviconUpdated( 216 void FaviconHandler::NotifyFaviconUpdated(
(...skipping 30 matching lines...) Expand all
363 notification_icon_url_ = icon_url; 247 notification_icon_url_ = icon_url;
364 notification_icon_type_ = icon_type; 248 notification_icon_type_ = icon_type;
365 } 249 }
366 250
367 void FaviconHandler::OnUpdateFaviconURL( 251 void FaviconHandler::OnUpdateFaviconURL(
368 const GURL& page_url, 252 const GURL& page_url,
369 const std::vector<FaviconURL>& candidates) { 253 const std::vector<FaviconURL>& candidates) {
370 if (page_url != url_) 254 if (page_url != url_)
371 return; 255 return;
372 256
373 std::vector<FaviconURL> pruned_candidates; 257 std::vector<FaviconURL> filtered_candidates;
258 std::set<GURL> urls_to_filter;
259 urls_to_filter.insert(GURL());
260
374 for (const FaviconURL& candidate : candidates) { 261 for (const FaviconURL& candidate : candidates) {
375 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) 262 if (urls_to_filter.count(candidate.icon_url) == 0 &&
376 pruned_candidates.push_back(candidate); 263 (candidate.icon_type & icon_types_)) {
264 filtered_candidates.push_back(candidate);
265 urls_to_filter.insert(candidate.icon_url);
266 }
377 } 267 }
378 268
379 if (download_largest_icon_)
380 SortAndPruneImageUrls(&pruned_candidates);
381
382 // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored 269 // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored
383 // in the history database. 270 // in the history database.
384 if (image_urls_.size() == pruned_candidates.size() && 271 if (image_urls_.size() == filtered_candidates.size() &&
385 std::equal(pruned_candidates.begin(), pruned_candidates.end(), 272 std::equal(filtered_candidates.begin(), filtered_candidates.end(),
386 image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) { 273 image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) {
387 return; 274 return;
388 } 275 }
389 276
277 image_urls_ = filtered_candidates;
278 selector_.reset();
279 current_candidate_.reset();
280 best_favicon_image_ = gfx::Image();
390 download_requests_.clear(); 281 download_requests_.clear();
391 image_urls_ = pruned_candidates; 282
392 current_candidate_index_ = 0u; 283 if (image_urls_.empty())
393 best_favicon_candidate_ = FaviconCandidate(); 284 return;
285
286 // Reset the state of all candidate queues.
287 selector_.reset(new FaviconSelector(target_size_spec_, image_urls_));
394 288
395 // TODO(davemoore) Should clear on empty url. Currently we ignore it. 289 // TODO(davemoore) Should clear on empty url. Currently we ignore it.
396 // This appears to be what FF does as well. 290 // This appears to be what FF does as well.
397 if (current_candidate() && got_favicon_from_history_) 291 if (got_favicon_from_history_)
398 OnGotInitialHistoryDataAndIconURLCandidates(); 292 OnGotInitialHistoryDataAndIconURLCandidates();
399 } 293 }
400 294
401 int FaviconHandler::GetMaximalIconSize(favicon_base::IconType icon_type) {
402 switch (icon_type) {
403 case favicon_base::FAVICON:
404 #if defined(OS_ANDROID)
405 return 192;
406 #else
407 return gfx::ImageSkia::GetMaxSupportedScale() * gfx::kFaviconSize;
408 #endif
409 case favicon_base::TOUCH_ICON:
410 case favicon_base::TOUCH_PRECOMPOSED_ICON:
411 return kTouchIconSize;
412 case favicon_base::INVALID_ICON:
413 return 0;
414 }
415 NOTREACHED();
416 return 0;
417 }
418
419 void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() { 295 void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() {
420 if (!initial_history_result_expired_or_incomplete_ && 296 if (!initial_history_result_expired_or_incomplete_ &&
421 DoUrlAndIconMatch(*current_candidate(), notification_icon_url_, 297 DoUrlAndIconMatch(*selector_->CurrentCandidate(), notification_icon_url_,
422 notification_icon_type_)) { 298 notification_icon_type_)) {
423 // - The data from history is valid and not expired. 299 // - The data from history is valid and not expired.
424 // - The icon URL of the history data matches one of the page's icon URLs. 300 // - The icon URL of the history data matches one of the page's icon URLs.
425 // - The icon URL of the history data matches the icon URL of the last 301 // - The icon URL of the history data matches the icon URL of the last
426 // OnFaviconAvailable() notification. 302 // OnFaviconAvailable() notification.
427 // We are done. No additional downloads or history requests are needed. 303 // We are done. No additional downloads or history requests are needed.
428 // TODO: Store all of the icon URLs associated with a page in history so 304 // TODO: Store all of the icon URLs associated with a page in history so
429 // that we can check whether the page's icon URLs match the page's icon URLs 305 // that we can check whether the page's icon URLs match the page's icon URLs
430 // at the time that the favicon data was stored to the history database. 306 // at the time that the favicon data was stored to the history database.
431 return; 307 return;
432 } 308 }
433 309
434 DownloadCurrentCandidateOrAskFaviconService(); 310 DownloadNextCandidateOrAskFaviconService();
435 } 311 }
436 312
437 void FaviconHandler::OnDidDownloadFavicon( 313 void FaviconHandler::OnDidDownloadFavicon(
438 int id, 314 int id,
439 int http_status_code, 315 int http_status_code,
440 const GURL& image_url, 316 const GURL& image_url,
441 const std::vector<SkBitmap>& bitmaps, 317 const std::vector<SkBitmap>& bitmaps,
442 const std::vector<gfx::Size>& original_bitmap_sizes) { 318 const std::vector<gfx::Size>& original_bitmap_sizes) {
319 DCHECK(current_candidate_);
320
443 if (bitmaps.empty() && http_status_code == 404) { 321 if (bitmaps.empty() && http_status_code == 404) {
444 DVLOG(1) << "Failed to Download Favicon:" << image_url; 322 DVLOG(1) << "Failed to Download Favicon:" << image_url;
445 if (service_) 323 if (service_)
446 service_->UnableToDownloadFavicon(image_url); 324 service_->UnableToDownloadFavicon(image_url);
447 } 325 }
448 326
449 DownloadRequests::iterator i = download_requests_.find(id); 327 DownloadRequests::iterator i = download_requests_.find(id);
450 if (i == download_requests_.end()) { 328 if (i == download_requests_.end()) {
451 // Currently WebContents notifies us of ANY downloads so that it is 329 // Currently WebContents notifies us of ANY downloads so that it is
452 // possible to get here. 330 // possible to get here.
453 return; 331 return;
454 } 332 }
455 333
456 DownloadRequest download_request = i->second; 334 DownloadRequest download_request = i->second;
457 download_requests_.erase(i); 335 download_requests_.erase(i);
458 336
459 if (!current_candidate() || 337 if (!current_candidate_ || !DoUrlAndIconMatch(*current_candidate_, image_url,
460 !DoUrlAndIconMatch(*current_candidate(), 338 download_request.icon_type)) {
461 image_url,
462 download_request.icon_type)) {
463 return; 339 return;
464 } 340 }
465 341
466 bool request_next_icon = true; 342 if (!bitmaps.empty() &&
467 if (!bitmaps.empty()) { 343 selector_->ProcessDownloadedImage(current_candidate_->icon_url,
468 float score = 0.0f; 344 current_candidate_->icon_type, bitmaps,
345 original_bitmap_sizes)) {
346 // The bitmap has been chosen as the best so far so let's build the
347 // corresponding gfx::Image() and save it in |best_favicon_image_|.
469 gfx::ImageSkia image_skia; 348 gfx::ImageSkia image_skia;
470 if (download_largest_icon_) { 349 if (target_size_spec_.WantsBestBitmapOnly()) {
471 int index = -1; 350 image_skia =
472 // Use the largest bitmap if FaviconURL doesn't have sizes attribute. 351 gfx::ImageSkia(gfx::ImageSkiaRep(selector_->BestBitmap()->bitmap, 1));
473 if (current_candidate()->icon_sizes.empty()) {
474 index = GetLargestSizeIndex(original_bitmap_sizes);
475 } else {
476 index = GetIndexBySize(original_bitmap_sizes,
477 current_candidate()->icon_sizes[0]);
478 // Find largest bitmap if there is no one exactly matched.
479 if (index == -1)
480 index = GetLargestSizeIndex(original_bitmap_sizes);
481 }
482 image_skia = gfx::ImageSkia(gfx::ImageSkiaRep(bitmaps[index], 1));
483 } else { 352 } else {
484 image_skia = CreateFaviconImageSkia(bitmaps, 353 image_skia = CreateFaviconImageSkia(bitmaps, original_bitmap_sizes,
485 original_bitmap_sizes,
486 preferred_icon_size(), 354 preferred_icon_size(),
487 &score); 355 /*score=*/nullptr);
488 } 356 }
489 357
490 if (!image_skia.isNull()) { 358 if (!image_skia.isNull())
491 gfx::Image image(image_skia); 359 best_favicon_image_ = gfx::Image(image_skia);
492 // The downloaded icon is still valid when there is no FaviconURL update
493 // during the downloading.
494 request_next_icon = !UpdateFaviconCandidate(image_url, image, score,
495 download_request.icon_type);
496 }
497 } 360 }
498 361
499 if (request_next_icon && current_candidate_index_ + 1 < image_urls_.size()) { 362 DownloadNextCandidateOrAskFaviconService();
500 // Process the next candidate.
501 ++current_candidate_index_;
502 DownloadCurrentCandidateOrAskFaviconService();
503 } else {
504 // We have either found the ideal candidate or run out of candidates.
505 if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) {
506 // No more icons to request, set the favicon from the candidate.
507 SetFavicon(best_favicon_candidate_.image_url,
508 best_favicon_candidate_.image,
509 best_favicon_candidate_.icon_type);
510 }
511 // Clear download related state.
512 download_requests_.clear();
513 current_candidate_index_ = image_urls_.size();
514 best_favicon_candidate_ = FaviconCandidate();
515 }
516 } 363 }
517 364
518 bool FaviconHandler::HasPendingTasksForTest() { 365 bool FaviconHandler::HasPendingTasksForTest() {
519 return !download_requests_.empty() || 366 return !download_requests_.empty() ||
520 cancelable_task_tracker_.HasTrackedTasks(); 367 cancelable_task_tracker_.HasTrackedTasks();
521 } 368 }
522 369
523 bool FaviconHandler::ShouldSaveFavicon() { 370 bool FaviconHandler::ShouldSaveFavicon() {
524 if (!delegate_->IsOffTheRecord()) 371 if (!delegate_->IsOffTheRecord())
525 return true; 372 return true;
526 373
527 // Always save favicon if the page is bookmarked. 374 // Always save favicon if the page is bookmarked.
528 return delegate_->IsBookmarked(url_); 375 return delegate_->IsBookmarked(url_);
529 } 376 }
530 377
531 void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService( 378 void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
532 const std::vector<favicon_base::FaviconRawBitmapResult>& 379 const std::vector<favicon_base::FaviconRawBitmapResult>&
533 favicon_bitmap_results) { 380 favicon_bitmap_results) {
534 got_favicon_from_history_ = true; 381 got_favicon_from_history_ = true;
535 bool has_valid_result = HasValidResult(favicon_bitmap_results); 382 bool has_valid_result = HasValidResult(favicon_bitmap_results);
536 initial_history_result_expired_or_incomplete_ = 383 initial_history_result_expired_or_incomplete_ =
537 !has_valid_result || 384 !has_valid_result ||
538 HasExpiredOrIncompleteResult(preferred_icon_size(), 385 HasExpiredOrIncompleteResult(preferred_icon_size(),
539 favicon_bitmap_results); 386 favicon_bitmap_results);
540 redownload_icons_ = initial_history_result_expired_or_incomplete_ && 387 redownload_icons_ = initial_history_result_expired_or_incomplete_ &&
541 !favicon_bitmap_results.empty(); 388 !favicon_bitmap_results.empty();
542 389
543 if (has_valid_result && 390 if (has_valid_result &&
544 (!current_candidate() || 391 (!current_candidate_ ||
545 DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { 392 DoUrlsAndIconsMatch(*current_candidate_, favicon_bitmap_results))) {
pkotwicz 2017/03/20 03:25:16 This if() statement will now always return true be
mastiz 2017/03/20 08:07:27 You're right, thanks. I couldn't decide whether it
546 // The db knows the favicon (although it may be out of date) and the entry 393 // The db knows the favicon (although it may be out of date) and the entry
547 // doesn't have an icon. Set the favicon now, and if the favicon turns out 394 // doesn't have an icon. Set the favicon now, and if the favicon turns out
548 // to be expired (or the wrong url) we'll fetch later on. This way the 395 // to be expired (or the wrong url) we'll fetch later on. This way the
549 // user doesn't see a flash of the default favicon. 396 // user doesn't see a flash of the default favicon.
550 NotifyFaviconUpdated(favicon_bitmap_results); 397 NotifyFaviconUpdated(favicon_bitmap_results);
551 } 398 }
552 399
553 if (current_candidate()) 400 if (selector_)
554 OnGotInitialHistoryDataAndIconURLCandidates(); 401 OnGotInitialHistoryDataAndIconURLCandidates();
555 } 402 }
556 403
557 void FaviconHandler::DownloadCurrentCandidateOrAskFaviconService() { 404 void FaviconHandler::DownloadNextCandidateOrAskFaviconService() {
558 GURL icon_url = current_candidate()->icon_url; 405 current_candidate_ = selector_->DequeueCandidate();
559 favicon_base::IconType icon_type = current_candidate()->icon_type; 406
407 if (!current_candidate_) {
408 // We have either found the ideal candidate or run out of candidates.
409 const base::Optional<FaviconSelector::BestCandidate>& best =
410 selector_->BestBitmap();
411 if (best) {
412 // No more icons to request, set the favicon from the candidate.
413 SetFavicon(best->candidate.icon_url, best_favicon_image_,
414 best->candidate.icon_type);
415 }
416 // Clear download related state.
417 download_requests_.clear();
418 current_candidate_.reset();
419 best_favicon_image_ = gfx::Image();
420 selector_.reset();
421 return;
422 }
423
424 GURL icon_url = current_candidate_->icon_url;
425 favicon_base::IconType icon_type = current_candidate_->icon_type;
560 426
561 if (redownload_icons_) { 427 if (redownload_icons_) {
562 // We have the mapping, but the favicon is out of date. Download it now. 428 // We have the mapping, but the favicon is out of date. Download it now.
563 ScheduleDownload(icon_url, icon_type); 429 ScheduleDownload(icon_url, icon_type);
564 } else if (service_) { 430 } else if (service_) {
565 // We don't know the favicon, but we may have previously downloaded the 431 // We don't know the favicon, but we may have previously downloaded the
566 // favicon for another page that shares the same favicon. Ask for the 432 // favicon for another page that shares the same favicon. Ask for the
567 // favicon given the favicon URL. 433 // favicon given the favicon URL.
568 if (delegate_->IsOffTheRecord()) { 434 if (delegate_->IsOffTheRecord()) {
569 service_->GetFavicon( 435 service_->GetFavicon(
(...skipping 25 matching lines...) Expand all
595 favicon_bitmap_results); 461 favicon_bitmap_results);
596 462
597 if (has_valid_result) { 463 if (has_valid_result) {
598 // There is a valid favicon. Notify any observers. It is useful to notify 464 // There is a valid favicon. Notify any observers. It is useful to notify
599 // the observers even if the favicon is expired or incomplete (incorrect 465 // the observers even if the favicon is expired or incomplete (incorrect
600 // size) because temporarily showing the user an expired favicon or 466 // size) because temporarily showing the user an expired favicon or
601 // streched favicon is preferable to showing the user the default favicon. 467 // streched favicon is preferable to showing the user the default favicon.
602 NotifyFaviconUpdated(favicon_bitmap_results); 468 NotifyFaviconUpdated(favicon_bitmap_results);
603 } 469 }
604 470
605 if (!current_candidate() || 471 if (!current_candidate_ ||
606 (has_results && 472 (has_results &&
607 !DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { 473 !DoUrlsAndIconsMatch(*current_candidate_, favicon_bitmap_results))) {
608 // The icon URLs have been updated since the favicon data was requested. 474 // The icon URLs have been updated since the favicon data was requested.
609 return; 475 return;
610 } 476 }
611 477
612 if (has_expired_or_incomplete_result) { 478 if (has_expired_or_incomplete_result) {
613 ScheduleDownload(current_candidate()->icon_url, 479 ScheduleDownload(current_candidate_->icon_url,
614 current_candidate()->icon_type); 480 current_candidate_->icon_type);
615 } 481 }
616 } 482 }
617 483
618 void FaviconHandler::ScheduleDownload(const GURL& image_url, 484 void FaviconHandler::ScheduleDownload(const GURL& image_url,
619 favicon_base::IconType icon_type) { 485 favicon_base::IconType icon_type) {
620 DCHECK(image_url.is_valid()); 486 DCHECK(image_url.is_valid());
621 if (service_ && service_->WasUnableToDownloadFavicon(image_url)) { 487 if (service_ && service_->WasUnableToDownloadFavicon(image_url)) {
622 DVLOG(1) << "Skip Failed FavIcon: " << image_url; 488 DVLOG(1) << "Skip Failed FavIcon: " << image_url;
623 // Registration in download_requests_ is needed to prevent 489 // Registration in download_requests_ is needed to prevent
624 // OnDidDownloadFavicon() from returning early. 490 // OnDidDownloadFavicon() from returning early.
625 download_requests_[0] = DownloadRequest(image_url, icon_type); 491 download_requests_[0] = DownloadRequest(image_url, icon_type);
626 OnDidDownloadFavicon(0, 0, image_url, std::vector<SkBitmap>(), 492 OnDidDownloadFavicon(0, 0, image_url, std::vector<SkBitmap>(),
627 std::vector<gfx::Size>()); 493 std::vector<gfx::Size>());
628 return; 494 return;
629 } 495 }
630 // A max bitmap size is specified to avoid receiving huge bitmaps in 496 // A max bitmap size is specified to avoid receiving huge bitmaps in
631 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() 497 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
632 // for more details about the max bitmap size. 498 // for more details about the max bitmap size.
499 const int max_pixel_size = target_size_spec_.pixel_size();
633 const int download_id = 500 const int download_id =
634 delegate_->DownloadImage(image_url, GetMaximalIconSize(icon_type), 501 delegate_->DownloadImage(image_url, max_pixel_size,
635 base::Bind(&FaviconHandler::OnDidDownloadFavicon, 502 base::Bind(&FaviconHandler::OnDidDownloadFavicon,
636 weak_ptr_factory_.GetWeakPtr())); 503 weak_ptr_factory_.GetWeakPtr()));
637 DCHECK_NE(download_id, 0); 504 DCHECK_NE(download_id, 0);
638 505
639 // Download ids should be unique. 506 // Download ids should be unique.
640 DCHECK(download_requests_.find(download_id) == download_requests_.end()); 507 DCHECK(download_requests_.find(download_id) == download_requests_.end());
641 download_requests_[download_id] = DownloadRequest(image_url, icon_type); 508 download_requests_[download_id] = DownloadRequest(image_url, icon_type);
642 } 509 }
643 510
644 } // namespace favicon 511 } // namespace favicon
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698