Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |