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

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

Issue 2739173002: Always select best favicon bitmap (Closed)
Patch Set: Updated. 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 // Size (along each axis) of a touch icon.
27 // the apple touch icon for iPad. 27 #if defined(OS_IOS)
28 const int kTouchIconSize = 144; 28 // This currently corresponds to the apple touch icon for iPad.
29 const int kLargestIconSizeInPixels = 144;
30 #else
31 const int kLargestIconSizeInPixels = 192;
32 #endif
29 33
30 bool DoUrlAndIconMatch(const FaviconURL& favicon_url, 34 bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
31 const GURL& url, 35 const GURL& url,
32 favicon_base::IconType icon_type) { 36 favicon_base::IconType icon_type) {
33 return favicon_url.icon_url == url && favicon_url.icon_type == icon_type; 37 return favicon_url.icon_url == url && favicon_url.icon_type == icon_type;
34 } 38 }
35 39
36 // Returns true if all of the icon URLs and icon types in |bitmap_results| are 40 // 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|. 41 // identical and if they match the icon URL and icon type in |favicon_url|.
38 // Returns false if |bitmap_results| is empty. 42 // Returns false if |bitmap_results| is empty.
(...skipping 17 matching lines...) Expand all
56 // Return true if |bitmap_result| is expired. 60 // Return true if |bitmap_result| is expired.
57 bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) { 61 bool IsExpired(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
58 return bitmap_result.expired; 62 return bitmap_result.expired;
59 } 63 }
60 64
61 // Return true if |bitmap_result| is valid. 65 // Return true if |bitmap_result| is valid.
62 bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) { 66 bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
63 return bitmap_result.is_valid(); 67 return bitmap_result.is_valid();
64 } 68 }
65 69
66 // Returns true if |bitmap_results| is non-empty and: 70 // Returns true at least one of the bitmaps in |bitmap_results| is expired.
67 // - At least one of the bitmaps in |bitmap_results| is expired 71 bool HasExpiredResult(
68 // OR
69 // - |bitmap_results| is missing favicons for |desired_size_in_dip| and one of
70 // the scale factors in favicon_base::GetFaviconScales().
71 bool HasExpiredOrIncompleteResult(
72 int desired_size_in_dip,
73 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) { 72 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
74 if (bitmap_results.empty()) 73 return std::find_if(bitmap_results.begin(), bitmap_results.end(),
75 return false; 74 IsExpired) != bitmap_results.end();
76
77 // Check if at least one of the bitmaps is expired.
78 std::vector<favicon_base::FaviconRawBitmapResult>::const_iterator it =
79 std::find_if(bitmap_results.begin(), bitmap_results.end(), IsExpired);
80 if (it != bitmap_results.end())
81 return true;
82
83 // Any favicon size is good if the desired size is 0.
84 if (desired_size_in_dip == 0)
85 return false;
86
87 // Check if the favicon for at least one of the scale factors is missing.
88 // |bitmap_results| should always be complete for data inserted by
89 // FaviconHandler as the FaviconHandler stores favicons resized to all
90 // of favicon_base::GetFaviconScales() into the history backend.
91 // Examples of when |bitmap_results| can be incomplete:
92 // - Favicons inserted into the history backend by sync.
93 // - Favicons for imported bookmarks.
94 std::vector<gfx::Size> favicon_sizes;
95 for (const auto& bitmap_result : bitmap_results)
96 favicon_sizes.push_back(bitmap_result.pixel_size);
97
98 std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
99 for (float favicon_scale : favicon_scales) {
100 int edge_size_in_pixel = std::ceil(desired_size_in_dip * favicon_scale);
101 auto it = std::find(favicon_sizes.begin(), favicon_sizes.end(),
102 gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
103 if (it == favicon_sizes.end())
104 return true;
105 }
106 return false;
107 } 75 }
108 76
109 // Returns true if at least one of |bitmap_results| is valid. 77 // Returns true if at least one of |bitmap_results| is valid.
110 bool HasValidResult( 78 bool HasValidResult(
111 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) { 79 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
112 return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) != 80 return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
113 bitmap_results.end(); 81 bitmap_results.end();
114 } 82 }
115 83
116 // Returns the index of the entry with the largest area. 84 // Returns the index of the entry with the best size match.
117 int GetLargestSizeIndex(const std::vector<gfx::Size>& sizes) { 85 int GetBestMatchSizeIndex(const FaviconHandler::TargetSpec& target_size,
86 const std::vector<gfx::Size>& sizes) {
118 DCHECK(!sizes.empty()); 87 DCHECK(!sizes.empty());
119 size_t ret = 0; 88 size_t ret = 0;
120 for (size_t i = 1; i < sizes.size(); ++i) { 89 for (size_t i = 1; i < sizes.size(); ++i) {
121 if (sizes[ret].GetArea() < sizes[i].GetArea()) 90 if (target_size.IsBetterMatch(sizes[i], sizes[ret]))
122 ret = i; 91 ret = i;
123 } 92 }
124 return static_cast<int>(ret); 93 return static_cast<int>(ret);
125 } 94 }
126 95
127 // Return the index of a size which is same as the given |size|, -1 returned if 96 // Compare function used for std::stable_sort to sort as descend.
128 // there is no such bitmap. 97 bool CompareScore(const std::pair<float, FaviconURL>& b1,
129 int GetIndexBySize(const std::vector<gfx::Size>& sizes, 98 const std::pair<float, FaviconURL>& b2) {
130 const gfx::Size& size) { 99 return b1.first > b2.first;
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 } 100 }
139 101
140 // Compare function used for std::stable_sort to sort as descend. 102 // Sorts the entries in |image_urls|, best icon size matches first for
141 bool CompareIconSize(const FaviconURL& b1, const FaviconURL& b2) { 103 // |target_size|.
142 int area1 = 0; 104 void SortImageUrls(const FaviconHandler::TargetSpec& target_size,
143 if (!b1.icon_sizes.empty()) 105 std::vector<FaviconURL>* image_urls) {
144 area1 = b1.icon_sizes.front().GetArea(); 106 std::vector<std::pair<float, FaviconURL>> scored_candidates;
145 107 for (const FaviconURL& image_url : *image_urls) {
146 int area2 = 0; 108 float max_score = 0;
147 if (!b2.icon_sizes.empty()) 109 for (const gfx::Size& size : image_url.icon_sizes) {
148 area2 = b2.icon_sizes.front().GetArea(); 110 max_score = std::max(
149 111 max_score,
150 return area1 > area2; 112 GetFaviconCandidateScore(size, target_size.GetMaxPixelSize()));
pkotwicz 2017/03/15 03:49:39 You should use SelectFaviconFrameIndices() to comp
mastiz 2017/03/15 16:34:33 I believe this is a moot point now, because of the
151 } 113 }
152 114 scored_candidates.emplace_back(max_score, std::move(image_url));
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 } 115 }
166 std::stable_sort(image_urls->begin(), image_urls->end(), CompareIconSize); 116 std::stable_sort(scored_candidates.begin(), scored_candidates.end(),
117 CompareScore);
118 image_urls->clear();
119 for (auto& scored_candidate : scored_candidates)
120 image_urls->push_back(std::move(scored_candidate.second));
167 } 121 }
168 122
169 // Checks whether two FaviconURLs are equal ignoring the icon sizes. 123 // Checks whether two FaviconURLs are equal ignoring the icon sizes.
170 bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) { 124 bool FaviconURLsEqualIgnoringSizes(const FaviconURL& u1, const FaviconURL& u2) {
171 return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url; 125 return u1.icon_type == u2.icon_type && u1.icon_url == u2.icon_url;
172 } 126 }
173 127
128 FaviconHandler::TargetSpec GetTargetSpec(
129 FaviconDriverObserver::NotificationIconType handler_type) {
130 switch (handler_type) {
131 case FaviconDriverObserver::NON_TOUCH_16_DIP:
132 return FaviconHandler::TargetSpec::For16x16Dips();
133 case FaviconDriverObserver::NON_TOUCH_LARGEST:
134 case FaviconDriverObserver::TOUCH_LARGEST:
135 return FaviconHandler::TargetSpec::ForLargest();
136 }
137 NOTREACHED();
138 }
139
174 } // namespace 140 } // namespace
175 141
176 //////////////////////////////////////////////////////////////////////////////// 142 ////////////////////////////////////////////////////////////////////////////////
177 143
144 // static
145 FaviconHandler::TargetSpec FaviconHandler::TargetSpec::ForLargest() {
146 FaviconHandler::TargetSpec target_size;
147 target_size.pixel_sizes_.insert({kLargestIconSizeInPixels, 1.0f});
148 target_size.ensure_exact_size_ = false;
149 return target_size;
150 }
151
152 // static
153 FaviconHandler::TargetSpec FaviconHandler::TargetSpec::For16x16Dips() {
154 FaviconHandler::TargetSpec target_size;
155 for (float scale : favicon_base::GetFaviconScales()) {
156 target_size.pixel_sizes_.insert(
157 {std::ceil(scale * gfx::kFaviconSize), scale});
158 }
159 target_size.ensure_exact_size_ = true;
160 return target_size;
161 }
162
163 FaviconHandler::TargetSpec::TargetSpec(const TargetSpec&) = default;
164
165 FaviconHandler::TargetSpec::~TargetSpec() = default;
166
167 std::vector<int> FaviconHandler::TargetSpec::GetPixelSizes() const {
168 std::vector<int> result;
169 for (const auto& pixel_size : pixel_sizes_)
170 result.push_back(pixel_size.first);
171 return result;
172 }
173
174 int FaviconHandler::TargetSpec::GetMaxPixelSize() const {
175 return pixel_sizes_.rbegin()->first;
176 }
177
178 bool FaviconHandler::TargetSpec::WantsBestBitmapOnly() const {
179 return !ensure_exact_size_;
180 }
181
182 bool FaviconHandler::TargetSpec::HasCompleteResult(
183 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results)
184 const {
185 if (WantsBestBitmapOnly())
186 return HasValidResult(bitmap_results);
187
188 // Check if the favicon for at least one of the scale factors is missing.
189 // |bitmap_results| should always be complete for data inserted by
190 // FaviconHandler as the FaviconHandler stores favicons resized to all
191 // of |favicon_scales| into the history backend.
192 // Examples of when |bitmap_results| can be incomplete:
193 // - Favicons inserted into the history backend by sync.
194 // - Favicons for imported bookmarks.
195 std::vector<gfx::Size> favicon_sizes;
196 for (const auto& bitmap_result : bitmap_results) {
197 if (IsValid(bitmap_result))
198 favicon_sizes.push_back(bitmap_result.pixel_size);
199 }
200
201 for (const auto& pixel_size : pixel_sizes_) {
202 const int edge_size_in_pixel = pixel_size.first;
203 auto it = std::find(favicon_sizes.begin(), favicon_sizes.end(),
204 gfx::Size(edge_size_in_pixel, edge_size_in_pixel));
205 if (it == favicon_sizes.end())
206 return false;
207 }
208 return true;
209 }
210
211 bool FaviconHandler::TargetSpec::IsBetterMatch(const gfx::Size& size1,
212 const gfx::Size& size2) const {
213 return GetFaviconCandidateScore(size1, GetMaxPixelSize()) >
214 GetFaviconCandidateScore(size2, GetMaxPixelSize());
215 }
216
217 gfx::ImageSkia FaviconHandler::TargetSpec::CreateImageSkia(
218 const std::vector<SkBitmap>& bitmaps,
219 const std::vector<gfx::Size>& original_bitmap_sizes) const {
220 if (WantsBestBitmapOnly()) {
221 return gfx::ImageSkia(gfx::ImageSkiaRep(
222 bitmaps[GetBestMatchSizeIndex(*this, original_bitmap_sizes)], 1));
223 } else {
224 return CreateFaviconImageSkia(bitmaps, original_bitmap_sizes,
225 gfx::kFaviconSize, /*score=*/nullptr);
226 }
227 }
228
229 gfx::Image FaviconHandler::TargetSpec::CreateImageFromCache(
230 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results)
231 const {
232 return favicon_base::SelectFaviconFramesForPixelSizesFromPNGs(bitmap_results,
233 pixel_sizes_);
234 }
235
236 FaviconHandler::TargetSpec::TargetSpec() = default;
237
238 ////////////////////////////////////////////////////////////////////////////////
239
178 FaviconHandler::DownloadRequest::DownloadRequest() 240 FaviconHandler::DownloadRequest::DownloadRequest()
179 : icon_type(favicon_base::INVALID_ICON) { 241 : icon_type(favicon_base::INVALID_ICON) {
180 } 242 }
181 243
182 FaviconHandler::DownloadRequest::~DownloadRequest() { 244 FaviconHandler::DownloadRequest::~DownloadRequest() {
183 } 245 }
184 246
185 FaviconHandler::DownloadRequest::DownloadRequest( 247 FaviconHandler::DownloadRequest::DownloadRequest(
186 const GURL& image_url, 248 const GURL& image_url,
187 favicon_base::IconType icon_type) 249 favicon_base::IconType icon_type)
188 : image_url(image_url), icon_type(icon_type) { 250 : image_url(image_url), icon_type(icon_type) {
189 } 251 }
190 252
191 //////////////////////////////////////////////////////////////////////////////// 253 ////////////////////////////////////////////////////////////////////////////////
192 254
193 FaviconHandler::FaviconCandidate::FaviconCandidate() 255 FaviconHandler::FaviconCandidate::FaviconCandidate()
194 : score(0), icon_type(favicon_base::INVALID_ICON) { 256 : icon_type(favicon_base::INVALID_ICON) {}
195 }
196 257
197 FaviconHandler::FaviconCandidate::~FaviconCandidate() { 258 FaviconHandler::FaviconCandidate::~FaviconCandidate() {
198 } 259 }
199 260
200 FaviconHandler::FaviconCandidate::FaviconCandidate( 261 FaviconHandler::FaviconCandidate::FaviconCandidate(
201 const GURL& image_url, 262 const GURL& image_url,
202 const gfx::Image& image, 263 const gfx::Image& image,
203 float score,
204 favicon_base::IconType icon_type) 264 favicon_base::IconType icon_type)
205 : image_url(image_url), 265 : image_url(image_url),
206 image(image), 266 image(image),
207 score(score),
208 icon_type(icon_type) {} 267 icon_type(icon_type) {}
209 268
210 //////////////////////////////////////////////////////////////////////////////// 269 ////////////////////////////////////////////////////////////////////////////////
211 270
212 FaviconHandler::FaviconHandler( 271 FaviconHandler::FaviconHandler(
213 FaviconService* service, 272 FaviconService* service,
214 Delegate* delegate, 273 Delegate* delegate,
215 FaviconDriverObserver::NotificationIconType handler_type) 274 FaviconDriverObserver::NotificationIconType handler_type)
216 : handler_type_(handler_type), 275 : handler_type_(handler_type),
217 got_favicon_from_history_(false), 276 got_favicon_from_history_(false),
218 initial_history_result_expired_or_incomplete_(false), 277 initial_history_result_expired_or_incomplete_(false),
219 redownload_icons_(false), 278 redownload_icons_(false),
220 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)), 279 icon_types_(FaviconHandler::GetIconTypesFromHandlerType(handler_type)),
221 download_largest_icon_( 280 target_spec_(GetTargetSpec(handler_type)),
222 handler_type == FaviconDriverObserver::NON_TOUCH_LARGEST ||
223 handler_type == FaviconDriverObserver::TOUCH_LARGEST),
224 notification_icon_type_(favicon_base::INVALID_ICON), 281 notification_icon_type_(favicon_base::INVALID_ICON),
225 service_(service), 282 service_(service),
226 delegate_(delegate), 283 delegate_(delegate),
227 current_candidate_index_(0u), 284 current_candidate_index_(0u),
228 weak_ptr_factory_(this) { 285 weak_ptr_factory_(this) {
229 DCHECK(delegate_); 286 DCHECK(delegate_);
230 } 287 }
231 288
232 FaviconHandler::~FaviconHandler() { 289 FaviconHandler::~FaviconHandler() {
233 } 290 }
(...skipping 24 matching lines...) Expand all
258 notification_icon_url_ = GURL(); 315 notification_icon_url_ = GURL();
259 notification_icon_type_ = favicon_base::INVALID_ICON; 316 notification_icon_type_ = favicon_base::INVALID_ICON;
260 current_candidate_index_ = 0u; 317 current_candidate_index_ = 0u;
261 best_favicon_candidate_ = FaviconCandidate(); 318 best_favicon_candidate_ = FaviconCandidate();
262 319
263 // Request the favicon from the history service. In parallel to this the 320 // 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 321 // renderer is going to notify us (well WebContents) when the favicon url is
265 // available. 322 // available.
266 if (service_) { 323 if (service_) {
267 service_->GetFaviconForPageURL( 324 service_->GetFaviconForPageURL(
268 url_, icon_types_, preferred_icon_size(), 325 url_, icon_types_, target_spec_.GetPixelSizes(),
269 base::Bind( 326 base::Bind(
270 &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService, 327 &FaviconHandler::OnFaviconDataForInitialURLFromFaviconService,
271 base::Unretained(this)), 328 base::Unretained(this)),
272 &cancelable_task_tracker_); 329 &cancelable_task_tracker_);
273 } 330 }
274 } 331 }
275 332
276 bool FaviconHandler::UpdateFaviconCandidate(const GURL& image_url, 333 bool FaviconHandler::UpdateFaviconCandidate(const GURL& image_url,
277 const gfx::Image& image, 334 const gfx::Image& image,
278 float score,
279 favicon_base::IconType icon_type) { 335 favicon_base::IconType icon_type) {
280 bool replace_best_favicon_candidate = false; 336 // The size of the downloaded icon may not match the declared size so compare
281 bool exact_match = false; 337 // before overriding |best_favicon_candidate_|.
282 if (download_largest_icon_) { 338 if (target_spec_.IsBetterMatch(image.Size(),
283 replace_best_favicon_candidate = 339 best_favicon_candidate_.image.Size())) {
284 image.Size().GetArea() > 340 best_favicon_candidate_ = FaviconCandidate(image_url, image, icon_type);
285 best_favicon_candidate_.image.Size().GetArea(); 341 }
286 342
287 gfx::Size largest = best_favicon_candidate_.image.Size(); 343 // Stop downloading if current candidate is only candidate.
288 if (replace_best_favicon_candidate) 344 if (current_candidate_index_ + 1 >= image_urls_.size()) {
289 largest = image.Size(); 345 return true;
346 }
347 const FaviconURL& next_image_url = image_urls_[current_candidate_index_ + 1];
290 348
291 // The size of the downloaded icon may not match the declared size. Stop 349 // For exact sizes (i.e. not best only), we download all candidates until an
292 // downloading if: 350 // exact match is found.
293 // - current candidate is only candidate. 351 if (!target_spec_.WantsBestBitmapOnly()) {
294 // - next candidate doesn't have sizes attributes, in this case, the rest 352 const int desired_max_size = target_spec_.GetMaxPixelSize();
295 // candidates don't have sizes attribute either, stop downloading now, 353 return best_favicon_candidate_.image.Size() ==
296 // otherwise, all favicon without sizes attribute are downloaded. 354 gfx::Size(desired_max_size, desired_max_size);
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 } 355 }
316 if (replace_best_favicon_candidate) { 356
317 best_favicon_candidate_ = 357 // The size of the downloaded icon may not match the declared size. Stop
318 FaviconCandidate(image_url, image, score, icon_type); 358 // downloading if:
319 } 359 // - next candidate doesn't have sizes attributes, in this case, the rest
320 return exact_match; 360 // candidates don't have sizes attribute either, stop downloading now,
361 // otherwise, all favicon without sizes attribute are downloaded.
362 // - next candidate has sizes attribute and it is not better than best,
363 if (next_image_url.icon_sizes.empty())
364 return true;
365
366 const gfx::Size& best_next_size =
367 next_image_url.icon_sizes[
368 GetBestMatchSizeIndex(target_spec_, next_image_url.icon_sizes)];
369 return !target_spec_.IsBetterMatch(best_next_size,
370 best_favicon_candidate_.image.Size());
321 } 371 }
322 372
323 void FaviconHandler::SetFavicon(const GURL& icon_url, 373 void FaviconHandler::SetFavicon(const GURL& icon_url,
324 const gfx::Image& image, 374 const gfx::Image& image,
325 favicon_base::IconType icon_type) { 375 favicon_base::IconType icon_type) {
pkotwicz 2017/03/15 03:49:39 In order to future proof, we should make FaviconHa
326 if (service_ && ShouldSaveFavicon()) 376 if (service_ && ShouldSaveFavicon())
327 service_->SetFavicons(url_, icon_url, icon_type, image); 377 service_->SetFavicons(url_, icon_url, icon_type, image);
328 378
329 NotifyFaviconUpdated(icon_url, icon_type, image); 379 NotifyFaviconUpdated(icon_url, icon_type, image);
330 } 380 }
331 381
332 void FaviconHandler::NotifyFaviconUpdated( 382 void FaviconHandler::NotifyFaviconUpdated(
333 const std::vector<favicon_base::FaviconRawBitmapResult>& 383 const std::vector<favicon_base::FaviconRawBitmapResult>&
334 favicon_bitmap_results) { 384 favicon_bitmap_results) {
335 if (favicon_bitmap_results.empty()) 385 if (favicon_bitmap_results.empty())
336 return; 386 return;
337 387
338 gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs( 388 gfx::Image resized_image =
339 favicon_bitmap_results, 389 target_spec_.CreateImageFromCache(favicon_bitmap_results);
340 favicon_base::GetFaviconScales(), 390
341 preferred_icon_size());
342 // The history service sends back results for a single icon URL and icon 391 // The history service sends back results for a single icon URL and icon
343 // type, so it does not matter which result we get |icon_url| and |icon_type| 392 // type, so it does not matter which result we get |icon_url| and |icon_type|
344 // from. 393 // from.
345 const GURL icon_url = favicon_bitmap_results[0].icon_url; 394 const GURL icon_url = favicon_bitmap_results[0].icon_url;
346 favicon_base::IconType icon_type = favicon_bitmap_results[0].icon_type; 395 favicon_base::IconType icon_type = favicon_bitmap_results[0].icon_type;
347 NotifyFaviconUpdated(icon_url, icon_type, resized_image); 396 NotifyFaviconUpdated(icon_url, icon_type, resized_image);
348 } 397 }
349 398
350 void FaviconHandler::NotifyFaviconUpdated(const GURL& icon_url, 399 void FaviconHandler::NotifyFaviconUpdated(const GURL& icon_url,
351 favicon_base::IconType icon_type, 400 favicon_base::IconType icon_type,
(...skipping 17 matching lines...) Expand all
369 const std::vector<FaviconURL>& candidates) { 418 const std::vector<FaviconURL>& candidates) {
370 if (page_url != url_) 419 if (page_url != url_)
371 return; 420 return;
372 421
373 std::vector<FaviconURL> pruned_candidates; 422 std::vector<FaviconURL> pruned_candidates;
374 for (const FaviconURL& candidate : candidates) { 423 for (const FaviconURL& candidate : candidates) {
375 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_)) 424 if (!candidate.icon_url.is_empty() && (candidate.icon_type & icon_types_))
376 pruned_candidates.push_back(candidate); 425 pruned_candidates.push_back(candidate);
377 } 426 }
378 427
379 if (download_largest_icon_) 428 SortImageUrls(target_spec_, &pruned_candidates);
380 SortAndPruneImageUrls(&pruned_candidates);
381 429
382 // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored 430 // Ignore FaviconURL::icon_sizes because FaviconURL::icon_sizes is not stored
383 // in the history database. 431 // in the history database.
384 if (image_urls_.size() == pruned_candidates.size() && 432 if (image_urls_.size() == pruned_candidates.size() &&
385 std::equal(pruned_candidates.begin(), pruned_candidates.end(), 433 std::equal(pruned_candidates.begin(), pruned_candidates.end(),
386 image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) { 434 image_urls_.begin(), FaviconURLsEqualIgnoringSizes)) {
387 return; 435 return;
388 } 436 }
389 437
390 download_requests_.clear(); 438 download_requests_.clear();
391 image_urls_ = pruned_candidates; 439 image_urls_ = pruned_candidates;
392 current_candidate_index_ = 0u; 440 current_candidate_index_ = 0u;
393 best_favicon_candidate_ = FaviconCandidate(); 441 best_favicon_candidate_ = FaviconCandidate();
394 442
395 // TODO(davemoore) Should clear on empty url. Currently we ignore it. 443 // TODO(davemoore) Should clear on empty url. Currently we ignore it.
396 // This appears to be what FF does as well. 444 // This appears to be what FF does as well.
397 if (current_candidate() && got_favicon_from_history_) 445 if (current_candidate() && got_favicon_from_history_)
398 OnGotInitialHistoryDataAndIconURLCandidates(); 446 OnGotInitialHistoryDataAndIconURLCandidates();
399 } 447 }
400 448
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() { 449 void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() {
420 if (!initial_history_result_expired_or_incomplete_ && 450 if (!initial_history_result_expired_or_incomplete_ &&
421 DoUrlAndIconMatch(*current_candidate(), notification_icon_url_, 451 DoUrlAndIconMatch(*current_candidate(), notification_icon_url_,
422 notification_icon_type_)) { 452 notification_icon_type_)) {
423 // - The data from history is valid and not expired. 453 // - 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. 454 // - 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 455 // - The icon URL of the history data matches the icon URL of the last
426 // OnFaviconAvailable() notification. 456 // OnFaviconAvailable() notification.
427 // We are done. No additional downloads or history requests are needed. 457 // 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 458 // TODO: Store all of the icon URLs associated with a page in history so
(...skipping 29 matching lines...) Expand all
458 488
459 if (!current_candidate() || 489 if (!current_candidate() ||
460 !DoUrlAndIconMatch(*current_candidate(), 490 !DoUrlAndIconMatch(*current_candidate(),
461 image_url, 491 image_url,
462 download_request.icon_type)) { 492 download_request.icon_type)) {
463 return; 493 return;
464 } 494 }
465 495
466 bool request_next_icon = true; 496 bool request_next_icon = true;
467 if (!bitmaps.empty()) { 497 if (!bitmaps.empty()) {
468 float score = 0.0f; 498 gfx::ImageSkia image_skia =
469 gfx::ImageSkia image_skia; 499 target_spec_.CreateImageSkia(bitmaps, original_bitmap_sizes);
470 if (download_largest_icon_) {
471 int index = -1;
472 // Use the largest bitmap if FaviconURL doesn't have sizes attribute.
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 {
484 image_skia = CreateFaviconImageSkia(bitmaps,
485 original_bitmap_sizes,
486 preferred_icon_size(),
487 &score);
488 }
489 500
490 if (!image_skia.isNull()) { 501 if (!image_skia.isNull()) {
491 gfx::Image image(image_skia); 502 gfx::Image image(image_skia);
492 // The downloaded icon is still valid when there is no FaviconURL update 503 // The downloaded icon is still valid when there is no FaviconURL update
493 // during the downloading. 504 // during the downloading.
494 request_next_icon = !UpdateFaviconCandidate(image_url, image, score, 505 request_next_icon =
495 download_request.icon_type); 506 !UpdateFaviconCandidate(image_url, image, download_request.icon_type);
pkotwicz 2017/03/15 03:49:39 UpdateFaviconCandidate() should be fed |bitmaps| a
496 } 507 }
497 } 508 }
498 509
499 if (request_next_icon && current_candidate_index_ + 1 < image_urls_.size()) { 510 if (request_next_icon && current_candidate_index_ + 1 < image_urls_.size()) {
500 // Process the next candidate. 511 // Process the next candidate.
501 ++current_candidate_index_; 512 ++current_candidate_index_;
502 DownloadCurrentCandidateOrAskFaviconService(); 513 DownloadCurrentCandidateOrAskFaviconService();
503 } else { 514 } else {
504 // We have either found the ideal candidate or run out of candidates. 515 // We have either found the ideal candidate or run out of candidates.
505 if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) { 516 if (best_favicon_candidate_.icon_type != favicon_base::INVALID_ICON) {
(...skipping 21 matching lines...) Expand all
527 // Always save favicon if the page is bookmarked. 538 // Always save favicon if the page is bookmarked.
528 return delegate_->IsBookmarked(url_); 539 return delegate_->IsBookmarked(url_);
529 } 540 }
530 541
531 void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService( 542 void FaviconHandler::OnFaviconDataForInitialURLFromFaviconService(
532 const std::vector<favicon_base::FaviconRawBitmapResult>& 543 const std::vector<favicon_base::FaviconRawBitmapResult>&
533 favicon_bitmap_results) { 544 favicon_bitmap_results) {
534 got_favicon_from_history_ = true; 545 got_favicon_from_history_ = true;
535 bool has_valid_result = HasValidResult(favicon_bitmap_results); 546 bool has_valid_result = HasValidResult(favicon_bitmap_results);
536 initial_history_result_expired_or_incomplete_ = 547 initial_history_result_expired_or_incomplete_ =
537 !has_valid_result || 548 !has_valid_result || HasExpiredResult(favicon_bitmap_results) ||
538 HasExpiredOrIncompleteResult(preferred_icon_size(), 549 !target_spec_.HasCompleteResult(favicon_bitmap_results);
539 favicon_bitmap_results);
540 redownload_icons_ = initial_history_result_expired_or_incomplete_ && 550 redownload_icons_ = initial_history_result_expired_or_incomplete_ &&
541 !favicon_bitmap_results.empty(); 551 !favicon_bitmap_results.empty();
542 552
543 if (has_valid_result && 553 if (has_valid_result &&
544 (!current_candidate() || 554 (!current_candidate() ||
545 DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) { 555 DoUrlsAndIconsMatch(*current_candidate(), favicon_bitmap_results))) {
546 // The db knows the favicon (although it may be out of date) and the entry 556 // 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 557 // 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 558 // 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. 559 // user doesn't see a flash of the default favicon.
(...skipping 10 matching lines...) Expand all
560 570
561 if (redownload_icons_) { 571 if (redownload_icons_) {
562 // We have the mapping, but the favicon is out of date. Download it now. 572 // We have the mapping, but the favicon is out of date. Download it now.
563 ScheduleDownload(icon_url, icon_type); 573 ScheduleDownload(icon_url, icon_type);
564 } else if (service_) { 574 } else if (service_) {
565 // We don't know the favicon, but we may have previously downloaded the 575 // 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 576 // favicon for another page that shares the same favicon. Ask for the
567 // favicon given the favicon URL. 577 // favicon given the favicon URL.
568 if (delegate_->IsOffTheRecord()) { 578 if (delegate_->IsOffTheRecord()) {
569 service_->GetFavicon( 579 service_->GetFavicon(
570 icon_url, icon_type, preferred_icon_size(), 580 icon_url, icon_type,
581 target_spec_.GetPixelSizes(),
571 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)), 582 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
572 &cancelable_task_tracker_); 583 &cancelable_task_tracker_);
573 } else { 584 } else {
574 // Ask the history service for the icon. This does two things: 585 // Ask the history service for the icon. This does two things:
575 // 1. Attempts to fetch the favicon data from the database. 586 // 1. Attempts to fetch the favicon data from the database.
576 // 2. If the favicon exists in the database, this updates the database to 587 // 2. If the favicon exists in the database, this updates the database to
577 // include the mapping between the page url and the favicon url. 588 // include the mapping between the page url and the favicon url.
578 // This is asynchronous. The history service will call back when done. 589 // This is asynchronous. The history service will call back when done.
579 // TODO(pkotwicz): pass in all of |image_urls_| to 590 // TODO(pkotwicz): pass in all of |image_urls_| to
580 // UpdateFaviconMappingsAndFetch(). 591 // UpdateFaviconMappingsAndFetch().
581 service_->UpdateFaviconMappingsAndFetch( 592 service_->UpdateFaviconMappingsAndFetch(
582 url_, {icon_url}, icon_type, preferred_icon_size(), 593 url_, {icon_url}, icon_type, target_spec_.GetPixelSizes(),
583 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)), 594 base::Bind(&FaviconHandler::OnFaviconData, base::Unretained(this)),
584 &cancelable_task_tracker_); 595 &cancelable_task_tracker_);
585 } 596 }
586 } 597 }
587 } 598 }
588 599
589 void FaviconHandler::OnFaviconData(const std::vector< 600 void FaviconHandler::OnFaviconData(const std::vector<
590 favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) { 601 favicon_base::FaviconRawBitmapResult>& favicon_bitmap_results) {
591 bool has_results = !favicon_bitmap_results.empty(); 602 bool has_results = !favicon_bitmap_results.empty();
592 bool has_valid_result = HasValidResult(favicon_bitmap_results); 603 bool has_valid_result = HasValidResult(favicon_bitmap_results);
593 bool has_expired_or_incomplete_result = 604 bool has_expired_or_incomplete_result =
594 !has_valid_result || HasExpiredOrIncompleteResult(preferred_icon_size(), 605 !has_valid_result || HasExpiredResult(favicon_bitmap_results) ||
595 favicon_bitmap_results); 606 !target_spec_.HasCompleteResult(favicon_bitmap_results);
596 607
597 if (has_valid_result) { 608 if (has_valid_result) {
598 // There is a valid favicon. Notify any observers. It is useful to notify 609 // 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 610 // the observers even if the favicon is expired or incomplete (incorrect
600 // size) because temporarily showing the user an expired favicon or 611 // size) because temporarily showing the user an expired favicon or
601 // streched favicon is preferable to showing the user the default favicon. 612 // streched favicon is preferable to showing the user the default favicon.
602 NotifyFaviconUpdated(favicon_bitmap_results); 613 NotifyFaviconUpdated(favicon_bitmap_results);
603 } 614 }
604 615
605 if (!current_candidate() || 616 if (!current_candidate() ||
(...skipping 18 matching lines...) Expand all
624 // OnDidDownloadFavicon() from returning early. 635 // OnDidDownloadFavicon() from returning early.
625 download_requests_[0] = DownloadRequest(image_url, icon_type); 636 download_requests_[0] = DownloadRequest(image_url, icon_type);
626 OnDidDownloadFavicon(0, 0, image_url, std::vector<SkBitmap>(), 637 OnDidDownloadFavicon(0, 0, image_url, std::vector<SkBitmap>(),
627 std::vector<gfx::Size>()); 638 std::vector<gfx::Size>());
628 return; 639 return;
629 } 640 }
630 // A max bitmap size is specified to avoid receiving huge bitmaps in 641 // A max bitmap size is specified to avoid receiving huge bitmaps in
631 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload() 642 // OnDidDownloadFavicon(). See FaviconDriver::StartDownload()
632 // for more details about the max bitmap size. 643 // for more details about the max bitmap size.
633 const int download_id = 644 const int download_id =
634 delegate_->DownloadImage(image_url, GetMaximalIconSize(icon_type), 645 delegate_->DownloadImage(image_url, target_spec_.GetMaxPixelSize(),
635 base::Bind(&FaviconHandler::OnDidDownloadFavicon, 646 base::Bind(&FaviconHandler::OnDidDownloadFavicon,
636 weak_ptr_factory_.GetWeakPtr())); 647 weak_ptr_factory_.GetWeakPtr()));
637 DCHECK_NE(download_id, 0); 648 DCHECK_NE(download_id, 0);
638 649
639 // Download ids should be unique. 650 // Download ids should be unique.
640 DCHECK(download_requests_.find(download_id) == download_requests_.end()); 651 DCHECK(download_requests_.find(download_id) == download_requests_.end());
641 download_requests_[download_id] = DownloadRequest(image_url, icon_type); 652 download_requests_[download_id] = DownloadRequest(image_url, icon_type);
642 } 653 }
643 654
644 } // namespace favicon 655 } // namespace favicon
OLDNEW
« no previous file with comments | « components/favicon/core/favicon_handler.h ('k') | components/favicon/core/favicon_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698