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

Side by Side Diff: chrome/browser/favicon/select_favicon_frames.cc

Issue 10908114: Move SelectFaviconFrames from favicon/ to history/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 8 years, 3 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/favicon/select_favicon_frames.h"
6
7 #include "skia/ext/image_operations.h"
8 #include "third_party/skia/include/core/SkCanvas.h"
9 #include "ui/gfx/image/image.h"
10 #include "ui/gfx/image/image_skia.h"
11 #include "ui/gfx/size.h"
12
13 namespace {
14
15 void SizesFromBitmaps(const std::vector<SkBitmap>& bitmaps,
16 std::vector<gfx::Size>* sizes) {
17 for (size_t i = 0; i < bitmaps.size(); ++i)
18 sizes->push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height()));
19 }
20
21 size_t BiggestCandidate(const std::vector<gfx::Size>& candidate_sizes) {
22 size_t max_index = 0;
23 int max_area = candidate_sizes[0].GetArea();
24 for (size_t i = 1; i < candidate_sizes.size(); ++i) {
25 int area = candidate_sizes[i].GetArea();
26 if (area > max_area) {
27 max_area = area;
28 max_index = i;
29 }
30 }
31 return max_index;
32 }
33
34 SkBitmap PadWithBorder(const SkBitmap& contents,
35 int desired_size,
36 int source_size) {
37 SkBitmap bitmap;
38 bitmap.setConfig(
39 SkBitmap::kARGB_8888_Config, desired_size, desired_size);
40 bitmap.allocPixels();
41 bitmap.eraseARGB(0, 0, 0, 0);
42
43 {
44 SkCanvas canvas(bitmap);
45 int shift = (desired_size - source_size) / 2;
46 SkRect dest(SkRect::MakeXYWH(shift, shift, source_size, source_size));
47 canvas.drawBitmapRect(contents, NULL, dest);
48 }
49
50 return bitmap;
51 }
52
53 SkBitmap SampleNearestNeighbor(const SkBitmap& contents, int desired_size) {
54 SkBitmap bitmap;
55 bitmap.setConfig(
56 SkBitmap::kARGB_8888_Config, desired_size, desired_size);
57 bitmap.allocPixels();
58 if (!contents.isOpaque())
59 bitmap.eraseARGB(0, 0, 0, 0);
60
61 {
62 SkCanvas canvas(bitmap);
63 SkRect dest(SkRect::MakeWH(desired_size, desired_size));
64 canvas.drawBitmapRect(contents, NULL, dest);
65 }
66
67 return bitmap;
68 }
69
70 enum ResizeMethod {
71 NONE,
72 PAD_WITH_BORDER,
73 SAMPLE_NEAREST_NEIGHBOUR,
74 LANCZOS
75 };
76
77 size_t GetCandidateIndexWithBestScore(
78 const std::vector<gfx::Size>& candidate_sizes,
79 ui::ScaleFactor scale_factor,
80 int desired_size,
81 float* score,
82 ResizeMethod* resize_method) {
83 float scale = ui::GetScaleFactorScale(scale_factor);
84 desired_size = static_cast<int>(desired_size * scale + 0.5f);
85
86 // Try to find an exact match.
87 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
88 if (candidate_sizes[i].width() == desired_size &&
89 candidate_sizes[i].height() == desired_size) {
90 *score = 1;
91 *resize_method = NONE;
92 return i;
93 }
94 }
95
96 // If that failed, the following special rules apply:
97 // 1. 17px-24px images are built from 16px images by adding
98 // a transparent border.
99 if (desired_size > 16 * scale && desired_size <= 24 * scale) {
100 int source_size = static_cast<int>(16 * scale + 0.5f);
101 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
102 if (candidate_sizes[i].width() == source_size &&
103 candidate_sizes[i].height() == source_size) {
104 *score = 0.2f;
105 *resize_method = PAD_WITH_BORDER;
106 return i;
107 }
108 }
109 // Try again, with upsizing the base variant.
110 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
111 if (candidate_sizes[i].width() * scale == source_size &&
112 candidate_sizes[i].height() * scale == source_size) {
113 *score = 0.15f;
114 *resize_method = PAD_WITH_BORDER;
115 return i;
116 }
117 }
118 }
119
120 // 2. Integer multiples are built using nearest neighbor sampling.
121 // 3. Else, use Lancosz scaling:
122 // b) If available, from the next bigger variant.
123 int candidate_index = -1;
124 int min_area = INT_MAX;
125 for (size_t i = 0; i < candidate_sizes.size(); ++i) {
126 int area = candidate_sizes[i].GetArea();
127 if (candidate_sizes[i].width() > desired_size &&
128 candidate_sizes[i].height() > desired_size &&
129 (candidate_index == -1 || area < min_area)) {
130 candidate_index = i;
131 min_area = area;
132 }
133 }
134 *score = 0.1f;
135 // c) Else, from the biggest smaller variant.
136 if (candidate_index == -1) {
137 *score = 0;
138 candidate_index = BiggestCandidate(candidate_sizes);
139 }
140
141 const gfx::Size& candidate_size = candidate_sizes[candidate_index];
142 bool is_integer_multiple = desired_size % candidate_size.width() == 0 &&
143 desired_size % candidate_size.height() == 0;
144 *resize_method = is_integer_multiple ? SAMPLE_NEAREST_NEIGHBOUR : LANCZOS;
145 return candidate_index;
146 }
147
148 // Represents the index of the best candidate for a |scale_factor| from the
149 // |candidate_sizes| passed into GetCandidateIndicesWithBestScores().
150 struct SelectionResult {
151 // index in |candidate_sizes| of the best candidate.
152 size_t index;
153
154 // The ScaleFactor for which |index| is the best candidate.
155 ui::ScaleFactor scale_factor;
156
157 // How the bitmap data that the bitmap with |candidate_sizes[index]| should
158 // be resized for displaying in the UI.
159 ResizeMethod resize_method;
160 };
161
162 void GetCandidateIndicesWithBestScores(
163 const std::vector<gfx::Size>& candidate_sizes,
164 const std::vector<ui::ScaleFactor>& scale_factors,
165 int desired_size,
166 float* match_score,
167 std::vector<SelectionResult>* results) {
168 if (candidate_sizes.empty())
169 return;
170
171 if (desired_size == 0) {
172 // Just return the biggest image available.
173 SelectionResult result;
174 result.index = BiggestCandidate(candidate_sizes);
175 result.scale_factor = ui::SCALE_FACTOR_100P;
176 result.resize_method = NONE;
177 results->push_back(result);
178 if (match_score)
179 *match_score = 0.8f;
180 return;
181 }
182
183 float total_score = 0;
184 for (size_t i = 0; i < scale_factors.size(); ++i) {
185 float score;
186 SelectionResult result;
187 result.scale_factor = scale_factors[i];
188 result.index = GetCandidateIndexWithBestScore(candidate_sizes,
189 result.scale_factor, desired_size, &score, &result.resize_method);
190 results->push_back(result);
191 total_score += score;
192 }
193
194 if (match_score)
195 *match_score = total_score / scale_factors.size();
196 }
197
198 // Resize |source_bitmap| using |resize_method|.
199 SkBitmap GetResizedBitmap(const SkBitmap& source_bitmap,
200 int desired_size_in_dip,
201 ui::ScaleFactor scale_factor,
202 ResizeMethod resize_method) {
203 float scale = ui::GetScaleFactorScale(scale_factor);
204 int desired_size_in_pixel = static_cast<int>(
205 desired_size_in_dip * scale + 0.5f);
206
207 switch(resize_method) {
208 case NONE:
209 return source_bitmap;
210 case PAD_WITH_BORDER: {
211 int inner_border_in_pixel = static_cast<int>(16 * scale + 0.5f);
212 return PadWithBorder(source_bitmap, desired_size_in_pixel,
213 inner_border_in_pixel);
214 }
215 case SAMPLE_NEAREST_NEIGHBOUR:
216 return SampleNearestNeighbor(source_bitmap, desired_size_in_pixel);
217 case LANCZOS:
218 return skia::ImageOperations::Resize(
219 source_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
220 desired_size_in_pixel, desired_size_in_pixel);
221 }
222 return source_bitmap;
223 }
224
225 } // namespace
226
227 gfx::ImageSkia SelectFaviconFrames(
228 const std::vector<SkBitmap>& bitmaps,
229 const std::vector<ui::ScaleFactor>& scale_factors,
230 int desired_size,
231 float* match_score) {
232 std::vector<gfx::Size> candidate_sizes;
233 SizesFromBitmaps(bitmaps, &candidate_sizes);
234
235 std::vector<SelectionResult> results;
236 GetCandidateIndicesWithBestScores(candidate_sizes, scale_factors,
237 desired_size, match_score, &results);
238
239 gfx::ImageSkia multi_image;
240 for (size_t i = 0; i < results.size(); ++i) {
241 const SelectionResult& result = results[i];
242 SkBitmap resized_bitmap = GetResizedBitmap(bitmaps[result.index],
243 desired_size, result.scale_factor, result.resize_method);
244 multi_image.AddRepresentation(
245 gfx::ImageSkiaRep(resized_bitmap, result.scale_factor));
246 }
247 return multi_image;
248 }
OLDNEW
« no previous file with comments | « chrome/browser/favicon/select_favicon_frames.h ('k') | chrome/browser/favicon/select_favicon_frames_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698