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

Side by Side Diff: components/favicon_base/select_favicon_frames.cc

Issue 336423006: Pass in a set of requested favicon pixel sizes to the HistoryService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « components/favicon_base/select_favicon_frames.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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_base/select_favicon_frames.h" 5 #include "components/favicon_base/select_favicon_frames.h"
6 6
7 #include <algorithm>
8 #include <cmath>
7 #include <limits> 9 #include <limits>
10 #include <map>
8 #include <set> 11 #include <set>
9 12
10 #include "skia/ext/image_operations.h" 13 #include "skia/ext/image_operations.h"
11 #include "third_party/skia/include/core/SkCanvas.h" 14 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "ui/gfx/image/image.h" 15 #include "ui/gfx/image/image.h"
13 #include "ui/gfx/image/image_skia.h" 16 #include "ui/gfx/image/image_skia.h"
14 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
15 18
16 namespace { 19 namespace {
17 20
(...skipping 22 matching lines...) Expand all
40 SkRect dest(SkRect::MakeWH(desired_size, desired_size)); 43 SkRect dest(SkRect::MakeWH(desired_size, desired_size));
41 canvas.drawBitmapRect(contents, NULL, dest); 44 canvas.drawBitmapRect(contents, NULL, dest);
42 } 45 }
43 46
44 return bitmap; 47 return bitmap;
45 } 48 }
46 49
47 enum ResizeMethod { NONE, SAMPLE_NEAREST_NEIGHBOUR, LANCZOS }; 50 enum ResizeMethod { NONE, SAMPLE_NEAREST_NEIGHBOUR, LANCZOS };
48 51
49 size_t GetCandidateIndexWithBestScore( 52 size_t GetCandidateIndexWithBestScore(
50 const std::vector<gfx::Size>& candidate_sizes_in_pixel, 53 const std::vector<gfx::Size>& candidate_sizes,
51 ui::ScaleFactor scale_factor, 54 int desired_size,
52 int desired_size_in_dip,
53 float* score, 55 float* score,
54 ResizeMethod* resize_method) { 56 ResizeMethod* resize_method) {
55 DCHECK_NE(desired_size_in_dip, 0); 57 DCHECK_NE(desired_size, 0);
56
57 float scale = ui::GetScaleForScaleFactor(scale_factor);
58 int desired_size_in_pixel =
59 static_cast<int>(desired_size_in_dip * scale + 0.5f);
60 58
61 // Try to find an exact match. 59 // Try to find an exact match.
62 for (size_t i = 0; i < candidate_sizes_in_pixel.size(); ++i) { 60 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
63 if (candidate_sizes_in_pixel[i].width() == desired_size_in_pixel && 61 if (candidate_sizes[i].width() == desired_size &&
64 candidate_sizes_in_pixel[i].height() == desired_size_in_pixel) { 62 candidate_sizes[i].height() == desired_size) {
65 *score = 1; 63 *score = 1;
66 *resize_method = NONE; 64 *resize_method = NONE;
67 return i; 65 return i;
68 } 66 }
69 } 67 }
70 68
71 // Huge favicon bitmaps often have a completely different visual style from 69 // Huge favicon bitmaps often have a completely different visual style from
72 // smaller favicon bitmaps. Avoid these favicon bitmaps when a favicon of 70 // smaller favicon bitmaps. Avoid them.
73 // gfx::kFaviconSize DIP is requested. 71 const int kHugeEdgeSize = desired_size * 8;
74 const int kHugeEdgeSizeInPixel = desired_size_in_pixel * 8;
75 72
76 // Order of preference: 73 // Order of preference:
77 // 1) Bitmaps with width and height smaller than |kHugeEdgeSizeInPixel|. 74 // 1) Bitmaps with width and height smaller than |kHugeEdgeSize|.
78 // 2) Bitmaps which need to be scaled down instead of up. 75 // 2) Bitmaps which need to be scaled down instead of up.
79 // 3) Bitmaps which do not need to be scaled as much. 76 // 3) Bitmaps which do not need to be scaled as much.
80 size_t candidate_index = std::numeric_limits<size_t>::max(); 77 size_t candidate_index = std::numeric_limits<size_t>::max();
81 float candidate_score = 0; 78 float candidate_score = 0;
82 for (size_t i = 0; i < candidate_sizes_in_pixel.size(); ++i) { 79 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
83 float average_edge_in_pixel = (candidate_sizes_in_pixel[i].width() + 80 float average_edge =
84 candidate_sizes_in_pixel[i].height()) / 81 (candidate_sizes[i].width() + candidate_sizes[i].height()) / 2.0f;
85 2.0f;
86 82
87 float score = 0; 83 float score = 0;
88 if (candidate_sizes_in_pixel[i].width() >= kHugeEdgeSizeInPixel || 84 if (candidate_sizes[i].width() >= kHugeEdgeSize ||
89 candidate_sizes_in_pixel[i].height() >= kHugeEdgeSizeInPixel) { 85 candidate_sizes[i].height() >= kHugeEdgeSize) {
90 score = 86 score = std::min(1.0f, desired_size / average_edge) * 0.01f;
91 std::min(1.0f, desired_size_in_pixel / average_edge_in_pixel) * 0.01f; 87 } else if (candidate_sizes[i].width() >= desired_size &&
92 } else if (candidate_sizes_in_pixel[i].width() >= desired_size_in_pixel && 88 candidate_sizes[i].height() >= desired_size) {
93 candidate_sizes_in_pixel[i].height() >= desired_size_in_pixel) { 89 score = desired_size / average_edge * 0.01f + 0.15f;
94 score = desired_size_in_pixel / average_edge_in_pixel * 0.01f + 0.15f;
95 } else { 90 } else {
96 score = std::min(1.0f, average_edge_in_pixel / desired_size_in_pixel) * 91 score = std::min(1.0f, average_edge / desired_size) *
97 0.01f + 92 0.01f +
98 0.1f; 93 0.1f;
99 } 94 }
100 95
101 if (candidate_index == std::numeric_limits<size_t>::max() || 96 if (candidate_index == std::numeric_limits<size_t>::max() ||
102 score > candidate_score) { 97 score > candidate_score) {
103 candidate_index = i; 98 candidate_index = i;
104 candidate_score = score; 99 candidate_score = score;
105 } 100 }
106 } 101 }
107 *score = candidate_score; 102 *score = candidate_score;
108 103
109 // Integer multiples are built using nearest neighbor sampling. Otherwise, 104 // Integer multiples are built using nearest neighbor sampling. Otherwise,
110 // Lanczos scaling is used. 105 // Lanczos scaling is used.
111 const gfx::Size& candidate_size_in_pixel = 106 const gfx::Size& candidate_size = candidate_sizes[candidate_index];
112 candidate_sizes_in_pixel[candidate_index]; 107 if (candidate_size.IsEmpty()) {
113 if (candidate_size_in_pixel.IsEmpty()) {
114 *resize_method = NONE; 108 *resize_method = NONE;
115 } else if (desired_size_in_pixel % candidate_size_in_pixel.width() == 0 && 109 } else if (desired_size % candidate_size.width() == 0 &&
116 desired_size_in_pixel % candidate_size_in_pixel.height() == 0) { 110 desired_size % candidate_size.height() == 0) {
117 *resize_method = SAMPLE_NEAREST_NEIGHBOUR; 111 *resize_method = SAMPLE_NEAREST_NEIGHBOUR;
118 } else { 112 } else {
119 *resize_method = LANCZOS; 113 *resize_method = LANCZOS;
120 } 114 }
121 return candidate_index; 115 return candidate_index;
122 } 116 }
123 117
124 // Represents the index of the best candidate for a |scale_factor| from the 118 // Represents the index of the best candidate for |desired_size| from the
125 // |candidate_sizes| passed into GetCandidateIndicesWithBestScores(). 119 // |candidate_sizes| passed into GetCandidateIndicesWithBestScores().
126 struct SelectionResult { 120 struct SelectionResult {
127 // index in |candidate_sizes| of the best candidate. 121 // index in |candidate_sizes| of the best candidate.
128 size_t index; 122 size_t index;
129 123
130 // The ScaleFactor for which |index| is the best candidate. 124 // The desired size for which |index| is the best candidate.
131 ui::ScaleFactor scale_factor; 125 int desired_size;
132 126
133 // How the bitmap data that the bitmap with |candidate_sizes[index]| should 127 // How the bitmap data that the bitmap with |candidate_sizes[index]| should
134 // be resized for displaying in the UI. 128 // be resized for displaying in the UI.
135 ResizeMethod resize_method; 129 ResizeMethod resize_method;
136 }; 130 };
137 131
138 void GetCandidateIndicesWithBestScores( 132 void GetCandidateIndicesWithBestScores(
139 const std::vector<gfx::Size>& candidate_sizes, 133 const std::vector<gfx::Size>& candidate_sizes,
140 const std::vector<ui::ScaleFactor>& scale_factors, 134 const std::vector<int>& desired_sizes,
141 int desired_size,
142 float* match_score, 135 float* match_score,
143 std::vector<SelectionResult>* results) { 136 std::vector<SelectionResult>* results) {
144 if (candidate_sizes.empty()) { 137 if (candidate_sizes.empty() || desired_sizes.empty()) {
145 if (match_score) 138 if (match_score)
146 *match_score = 0.0f; 139 *match_score = 0.0f;
147 return; 140 return;
148 } 141 }
149 142
150 if (desired_size == 0) { 143 std::vector<int>::const_iterator zero_size_it = std::find(
144 desired_sizes.begin(), desired_sizes.end(), 0);
145 if (zero_size_it != desired_sizes.end()) {
151 // Just return the biggest image available. 146 // Just return the biggest image available.
152 SelectionResult result; 147 SelectionResult result;
153 result.index = BiggestCandidate(candidate_sizes); 148 result.index = BiggestCandidate(candidate_sizes);
154 result.scale_factor = ui::SCALE_FACTOR_100P; 149 result.desired_size = 0;
155 result.resize_method = NONE; 150 result.resize_method = NONE;
156 results->push_back(result); 151 results->push_back(result);
157 if (match_score) 152 if (match_score)
158 *match_score = 1.0f; 153 *match_score = 1.0f;
159 return; 154 return;
160 } 155 }
161 156
162 float total_score = 0; 157 float total_score = 0;
163 for (size_t i = 0; i < scale_factors.size(); ++i) { 158 for (size_t i = 0; i < desired_sizes.size(); ++i) {
164 float score; 159 float score;
165 SelectionResult result; 160 SelectionResult result;
166 result.scale_factor = scale_factors[i]; 161 result.desired_size = desired_sizes[i];
167 result.index = GetCandidateIndexWithBestScore(candidate_sizes, 162 result.index = GetCandidateIndexWithBestScore(candidate_sizes,
168 result.scale_factor, 163 result.desired_size,
169 desired_size,
170 &score, 164 &score,
171 &result.resize_method); 165 &result.resize_method);
172 results->push_back(result); 166 results->push_back(result);
173 total_score += score; 167 total_score += score;
174 } 168 }
175 169
176 if (match_score) 170 if (match_score)
177 *match_score = total_score / scale_factors.size(); 171 *match_score = total_score / desired_sizes.size();
178 } 172 }
179 173
180 // Resize |source_bitmap| using |resize_method|. 174 // Resize |source_bitmap| using |resize_method|.
181 SkBitmap GetResizedBitmap(const SkBitmap& source_bitmap, 175 SkBitmap GetResizedBitmap(const SkBitmap& source_bitmap,
182 int desired_size_in_dip, 176 int desired_size,
183 ui::ScaleFactor scale_factor,
184 ResizeMethod resize_method) { 177 ResizeMethod resize_method) {
185 float scale = ui::GetScaleForScaleFactor(scale_factor);
186 int desired_size_in_pixel =
187 static_cast<int>(desired_size_in_dip * scale + 0.5f);
188
189 switch (resize_method) { 178 switch (resize_method) {
190 case NONE: 179 case NONE:
191 return source_bitmap; 180 return source_bitmap;
192 case SAMPLE_NEAREST_NEIGHBOUR: 181 case SAMPLE_NEAREST_NEIGHBOUR:
193 return SampleNearestNeighbor(source_bitmap, desired_size_in_pixel); 182 return SampleNearestNeighbor(source_bitmap, desired_size);
194 case LANCZOS: 183 case LANCZOS:
195 return skia::ImageOperations::Resize( 184 return skia::ImageOperations::Resize(
196 source_bitmap, 185 source_bitmap,
197 skia::ImageOperations::RESIZE_LANCZOS3, 186 skia::ImageOperations::RESIZE_LANCZOS3,
198 desired_size_in_pixel, 187 desired_size,
199 desired_size_in_pixel); 188 desired_size);
200 } 189 }
201 return source_bitmap; 190 return source_bitmap;
202 } 191 }
203 192
204 } // namespace 193 } // namespace
205 194
206 const float kSelectFaviconFramesInvalidScore = -1.0f; 195 const float kSelectFaviconFramesInvalidScore = -1.0f;
207 196
208 gfx::ImageSkia SelectFaviconFrames( 197 gfx::ImageSkia SelectFaviconFrames(
209 const std::vector<SkBitmap>& bitmaps, 198 const std::vector<SkBitmap>& bitmaps,
210 const std::vector<gfx::Size>& original_sizes, 199 const std::vector<gfx::Size>& original_sizes,
211 const std::vector<ui::ScaleFactor>& scale_factors, 200 const std::vector<ui::ScaleFactor>& scale_factors,
212 int desired_size, 201 int desired_size_in_dip,
213 float* match_score) { 202 float* match_score) {
203 std::vector<int> desired_sizes;
204 std::map<int, float> scale_map;
205 if (desired_size_in_dip == 0) {
206 desired_sizes.push_back(0);
207 scale_map[0] = 1.0f;
208 } else {
209 for (size_t i = 0; i < scale_factors.size(); ++i) {
210 float scale = ui::GetScaleForScaleFactor(scale_factors[i]);
211 int desired_size = ceil(desired_size_in_dip * scale);
212 desired_sizes.push_back(desired_size);
213 scale_map[desired_size] = scale;
214 }
215 }
216
214 std::vector<SelectionResult> results; 217 std::vector<SelectionResult> results;
215 GetCandidateIndicesWithBestScores( 218 GetCandidateIndicesWithBestScores(
216 original_sizes, scale_factors, desired_size, match_score, &results); 219 original_sizes, desired_sizes, match_score, &results);
217 220
218 gfx::ImageSkia multi_image; 221 gfx::ImageSkia multi_image;
219 for (size_t i = 0; i < results.size(); ++i) { 222 for (size_t i = 0; i < results.size(); ++i) {
220 const SelectionResult& result = results[i]; 223 const SelectionResult& result = results[i];
221 SkBitmap resized_bitmap = GetResizedBitmap(bitmaps[result.index], 224 SkBitmap resized_bitmap = GetResizedBitmap(bitmaps[result.index],
222 desired_size, 225 result.desired_size,
223 result.scale_factor,
224 result.resize_method); 226 result.resize_method);
225 multi_image.AddRepresentation(gfx::ImageSkiaRep( 227
226 resized_bitmap, ui::GetScaleForScaleFactor(result.scale_factor))); 228 std::map<int, float>::const_iterator it = scale_map.find(
229 result.desired_size);
230 DCHECK(it != scale_map.end());
231 float scale = it->second;
232 multi_image.AddRepresentation(gfx::ImageSkiaRep(resized_bitmap, scale));
227 } 233 }
228 return multi_image; 234 return multi_image;
229 } 235 }
230 236
231 void SelectFaviconFrameIndices( 237 void SelectFaviconFrameIndices(
232 const std::vector<gfx::Size>& frame_pixel_sizes, 238 const std::vector<gfx::Size>& frame_pixel_sizes,
233 const std::vector<ui::ScaleFactor>& scale_factors, 239 const std::vector<int>& desired_sizes,
234 int desired_size,
235 std::vector<size_t>* best_indices, 240 std::vector<size_t>* best_indices,
236 float* match_score) { 241 float* match_score) {
237 std::vector<SelectionResult> results; 242 std::vector<SelectionResult> results;
238 GetCandidateIndicesWithBestScores( 243 GetCandidateIndicesWithBestScores(
239 frame_pixel_sizes, scale_factors, desired_size, match_score, &results); 244 frame_pixel_sizes, desired_sizes, match_score, &results);
240 245
241 std::set<size_t> already_added; 246 std::set<size_t> already_added;
242 for (size_t i = 0; i < results.size(); ++i) { 247 for (size_t i = 0; i < results.size(); ++i) {
243 size_t index = results[i].index; 248 size_t index = results[i].index;
244 // GetCandidateIndicesWithBestScores() will return duplicate indices if the 249 // GetCandidateIndicesWithBestScores() will return duplicate indices if the
245 // bitmap data with |frame_pixel_sizes[index]| should be used for multiple 250 // bitmap data with |frame_pixel_sizes[index]| should be used for multiple
246 // scale factors. Remove duplicates here such that |best_indices| contains 251 // scale factors. Remove duplicates here such that |best_indices| contains
247 // no duplicates. 252 // no duplicates.
248 if (already_added.find(index) == already_added.end()) { 253 if (already_added.find(index) == already_added.end()) {
249 already_added.insert(index); 254 already_added.insert(index);
250 best_indices->push_back(index); 255 best_indices->push_back(index);
251 } 256 }
252 } 257 }
253 } 258 }
OLDNEW
« no previous file with comments | « components/favicon_base/select_favicon_frames.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698