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

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

Powered by Google App Engine
This is Rietveld 408576698