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

Side by Side Diff: components/favicon/core/favicon_selector.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
(Empty)
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/favicon/core/favicon_selector.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <utility>
10
11 #include "components/favicon_base/favicon_util.h"
12 #include "components/favicon_base/select_favicon_frames.h"
13 #include "ui/gfx/favicon_size.h"
14
15 namespace favicon {
16 namespace {
17
18 // Size (along each axis) of a touch icon.
19 #if defined(OS_IOS)
20 // This currently corresponds to the apple touch icon for iPad.
21 const int kLargestIconSizeInPixels = 144;
22 #else
23 const int kLargestIconSizeInPixels = 192;
24 #endif
25
26 // Compare function used for std::stable_sort to sort as descend.
27 bool CompareScore(const FaviconSelector::Candidate& lhs,
28 const FaviconSelector::Candidate& rhs) {
29 return lhs.score > rhs.score;
30 }
31
32 bool ComparePixelSize(const FaviconSelector::TargetSizeSpec& lhs,
33 const FaviconSelector::TargetSizeSpec& rhs) {
34 return lhs.pixel_size() > rhs.pixel_size();
35 }
36
37 // Return true if |bitmap_result| is valid.
38 bool IsValid(const favicon_base::FaviconRawBitmapResult& bitmap_result) {
39 return bitmap_result.is_valid();
40 }
41
42 // Returns true if at least one of |bitmap_results| is valid.
43 bool HasValidResult(
44 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results) {
45 return std::find_if(bitmap_results.begin(), bitmap_results.end(), IsValid) !=
46 bitmap_results.end();
47 }
48
49 } // namespace
50
51 // static
52 FaviconSelector::TargetSizeSpec FaviconSelector::TargetSizeSpec::ForLargest() {
53 FaviconSelector::TargetSizeSpec target_size_spec;
54 target_size_spec.pixel_size_ = kLargestIconSizeInPixels;
55 // 0 is special-cased in CreateFaviconImageSkiaWithScaleFactors().
56 target_size_spec.scale_factor_ = 0;
57 target_size_spec.ensure_exact_size_ = false;
58 return target_size_spec;
59 }
60
61 // static
62 std::vector<FaviconSelector::TargetSizeSpec>
63 FaviconSelector::TargetSizeSpec::For16x16Dips() {
64 std::vector<FaviconSelector::TargetSizeSpec> target_size_specs;
65 std::vector<float> scale_factors = favicon_base::GetFaviconScales();
66 std::sort(scale_factors.begin(), scale_factors.end(), std::greater<float>());
67 for (float scale : scale_factors) {
68 FaviconSelector::TargetSizeSpec target_size_spec;
69 target_size_spec.pixel_size_ = std::ceil(scale * gfx::kFaviconSize);
70 target_size_spec.scale_factor_ = scale;
71 target_size_spec.ensure_exact_size_ = true;
72 target_size_specs.push_back(target_size_spec);
73 }
74 return target_size_specs;
75 }
76
77 FaviconSelector::TargetSizeSpec::TargetSizeSpec(const TargetSizeSpec&) =
78 default;
79
80 FaviconSelector::TargetSizeSpec::~TargetSizeSpec() = default;
81
82 FaviconSelector::TargetSizeSpec::TargetSizeSpec(TargetSizeSpec&&) = default;
83
84 FaviconSelector::TargetSizeSpec& FaviconSelector::TargetSizeSpec::operator=(
85 FaviconSelector::TargetSizeSpec&&) = default;
86
87 bool FaviconSelector::TargetSizeSpec::WantsBestBitmapOnly() const {
88 return !ensure_exact_size_;
89 }
90
91 bool FaviconSelector::TargetSizeSpec::HasSatisfyingResult(
92 const std::vector<favicon_base::FaviconRawBitmapResult>& bitmap_results)
93 const {
94 if (WantsBestBitmapOnly())
95 return HasValidResult(bitmap_results);
96
97 const gfx::Size desired_size(pixel_size_, pixel_size_);
98 for (const auto& bitmap_result : bitmap_results) {
99 if (IsValid(bitmap_result) && bitmap_result.pixel_size == desired_size)
100 return true;
101 }
102 return false;
103 }
104
105 std::list<FaviconSelector::Candidate>
106 FaviconSelector::TargetSizeSpec::SortAndPruneCandidates(
107 const std::vector<favicon::FaviconURL>& favicon_urls) const {
108 std::vector<Candidate> candidates;
109 for (const favicon::FaviconURL& favicon_url : favicon_urls)
110 candidates.push_back(Candidate::FromFaviconURL(favicon_url, pixel_size_));
111
112 std::stable_sort(candidates.begin(), candidates.end(), CompareScore);
113 std::list<Candidate> result;
114 std::move(candidates.begin(), candidates.end(), std::back_inserter(result));
115 return result;
116 }
117
118 FaviconSelector::TargetSizeSpec::TargetSizeSpec() = default;
119
120 ////////////////////////////////////////////////////////////////////////////////
121
122 // static
123 FaviconSelector::Candidate FaviconSelector::Candidate::FromFaviconURL(
124 const favicon::FaviconURL& favicon_url,
125 int target_pixel_size) {
126 FaviconSelector::Candidate candidate;
127 candidate.icon_url = favicon_url.icon_url;
128 candidate.icon_type = favicon_url.icon_type;
129 candidate.score = 0;
130 for (const gfx::Size& favicon_size : favicon_url.icon_sizes) {
pkotwicz 2017/03/20 03:25:16 If you passed in a vector of target sizes (std::ve
mastiz 2017/03/20 08:07:28 This deserves some discussion, because my proposal
131 candidate.score =
132 std::max(candidate.score,
133 GetFaviconCandidateScore(favicon_size, target_pixel_size));
134 }
135 return candidate;
136 }
137
138 ////////////////////////////////////////////////////////////////////////////////
139
140 // static
141 std::vector<FaviconSelector> FaviconSelector::BuildMultiple(
142 const std::vector<TargetSizeSpec>& target_size_specs,
143 const std::vector<favicon::FaviconURL>& candidates) {
144 DCHECK(std::is_sorted(target_size_specs.begin(), target_size_specs.end(),
145 &ComparePixelSize));
146 std::vector<FaviconSelector> selectors;
147 for (const TargetSizeSpec& target_size_spec : target_size_specs)
148 selectors.emplace_back(target_size_spec, candidates);
149 return selectors;
150 }
151
152 FaviconSelector::FaviconSelector(
153 const FaviconSelector::TargetSizeSpec& target_size_spec,
154 const std::vector<favicon::FaviconURL>& candidates)
155 : target_size_spec_(target_size_spec),
156 pending_candidates_(target_size_spec.SortAndPruneCandidates(candidates)) {
157 DCHECK(!pending_candidates_.empty());
158 }
159
160 FaviconSelector::~FaviconSelector() = default;
161
162 FaviconSelector::FaviconSelector(FaviconSelector&&) = default;
163
164 FaviconSelector& FaviconSelector::operator=(FaviconSelector&&) = default;
165
166 bool FaviconSelector::IsSatisfied() const {
167 if (!best_candidate_)
168 return false;
169
170 if (target_size_spec_.WantsBestBitmapOnly()) {
171 // The next candidate must have size attributes that are more promising than
172 // the best candidate so far. Otherwise, all favicon without sizes attribute
173 // are downloaded.
174 // TODO(mastiz): This seems useful for sites that have reported the wrong
175 // size. Consider simplifying and returning true here.
176 return pending_candidates_.empty() || pending_candidates_.front().score <=
177 best_candidate_->candidate.score;
178 } else {
179 // For exact sizes (i.e. not best only), we download all candidates until an
180 // exact match is found.
181 return best_candidate_->original_size.width() ==
182 target_size_spec_.pixel_size() &&
183 best_candidate_->original_size.height() ==
184 target_size_spec_.pixel_size();
185 }
186 }
187
188 // Returns the next candidate to be processed by populating |*candidate|.
189 // Returns false if the queue is empty.
190 base::Optional<FaviconSelector::Candidate> FaviconSelector::DequeueCandidate() {
191 if (pending_candidates_.empty() || IsSatisfied())
192 return base::Optional<Candidate>();
193
194 base::Optional<Candidate> result = std::move(pending_candidates_.front());
195 pending_candidates_.pop_front();
196 return result;
197 }
198
199 const FaviconSelector::Candidate* FaviconSelector::CurrentCandidate() const {
200 if (pending_candidates_.empty() || IsSatisfied())
201 return nullptr;
202
203 return &pending_candidates_.front();
204 }
205
206 bool FaviconSelector::ProcessDownloadedImage(
207 const GURL& icon_url,
208 favicon_base::IconType icon_type,
209 const std::vector<SkBitmap>& bitmaps,
210 const std::vector<gfx::Size>& original_sizes) {
211 // Remove potentially queued candidates for |icon_url| (this happens if the
212 // candidate was dequeued from another queue).
213 pending_candidates_.remove_if([&icon_url](const Candidate& candidate) {
214 return candidate.icon_url == icon_url;
215 });
216
217 // Select the best bitmap, which to be relevant needs to be better than the
218 // best known bitmap until now.
219 float best_score = best_candidate_ ? best_candidate_->candidate.score : -1;
220 size_t best_bitmap_index = bitmaps.size();
221 for (size_t i = 0; i < bitmaps.size(); ++i) {
222 const SkBitmap& bitmap = bitmaps[i];
223 const float bitmap_score =
224 GetFaviconCandidateScore(gfx::Size(bitmap.width(), bitmap.height()),
225 target_size_spec_.pixel_size());
226 if (bitmap_score > best_score) {
227 best_bitmap_index = i;
228 best_score = bitmap_score;
229 }
230 }
231
232 // No interesting bitmap, nothing to be done (|icon_url| has already been
233 // removed from the queue).
234 if (best_bitmap_index == bitmaps.size())
235 return false;
236
237 Candidate candidate{icon_url, icon_type, best_score};
238 best_candidate_.emplace(BestCandidate{std::move(candidate),
239 original_sizes[best_bitmap_index],
240 bitmaps[best_bitmap_index]});
241 return true;
242 }
243
244 } // namespace favicon
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698