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 "components/favicon_base/select_favicon_frames.h"
6
7#include "testing/gtest/include/gtest/gtest.h"
8#include "third_party/skia/include/core/SkBitmap.h"
9#include "third_party/skia/include/core/SkColor.h"
10#include "ui/base/layout.h"
11#include "ui/gfx/image/image_skia.h"
12
13using std::vector;
14
15namespace {
16
17const ui::ScaleFactor FaviconScaleFactor1x[] = {
18  ui::SCALE_FACTOR_100P,
19};
20
21const ui::ScaleFactor FaviconScaleFactor1xAnd2x[] = {
22  ui::SCALE_FACTOR_100P,
23  ui::SCALE_FACTOR_200P,
24};
25
26#define SCOPED_FAVICON_SCALE_FACTOR(list)          \
27  ui::test::ScopedSetSupportedScaleFactors scoped( \
28      std::vector<ui::ScaleFactor>(list, list + arraysize(list)))
29
30#define SCOPED_FAVICON_SCALE_FACTOR_1X \
31  SCOPED_FAVICON_SCALE_FACTOR(FaviconScaleFactor1x)
32#define SCOPED_FAVICON_SCALE_FACTOR_1XAND2X \
33  SCOPED_FAVICON_SCALE_FACTOR(FaviconScaleFactor1xAnd2x)
34
35// Return gfx::Size vector with the pixel sizes of |bitmaps|.
36vector<gfx::Size> SizesFromBitmaps(const vector<SkBitmap>& bitmaps) {
37  vector<gfx::Size> sizes;
38  for (size_t i = 0; i < bitmaps.size(); ++i)
39    sizes.push_back(gfx::Size(bitmaps[i].width(), bitmaps[i].height()));
40  return sizes;
41}
42
43SkBitmap MakeBitmap(SkColor color, int w, int h) {
44  SkBitmap bitmap;
45  bitmap.allocN32Pixels(w, h);
46  bitmap.eraseColor(color);
47  return bitmap;
48}
49
50SkColor GetColor(const gfx::ImageSkia& image, float scale,
51                 int x = -1, int y = -1) {
52  const SkBitmap& bitmap =
53      image.GetRepresentation(scale).sk_bitmap();
54  if (x == -1)
55    x = bitmap.width() / 2;
56  if (y == -1)
57    y = bitmap.width() / 2;
58  bitmap.lockPixels();
59  SkColor color = bitmap.getColor(x, y);
60  bitmap.unlockPixels();
61  return color;
62}
63
64SkColor GetColor1x(const gfx::ImageSkia& image) {
65  return GetColor(image, 1.0f);
66}
67
68SkColor GetColor2x(const gfx::ImageSkia& image) {
69  return GetColor(image, 2.0f);
70}
71
72TEST(SelectFaviconFramesTest, ZeroSizePicksLargest) {
73  vector<SkBitmap> bitmaps;
74  bitmaps.push_back(MakeBitmap(SK_ColorRED, 16, 16));
75  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 48, 48));
76  bitmaps.push_back(MakeBitmap(SK_ColorBLUE, 32, 32));
77
78  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
79      SizesFromBitmaps(bitmaps), 0, NULL);
80  EXPECT_EQ(1u, image.image_reps().size());
81  ASSERT_TRUE(image.HasRepresentation(1.0f));
82  EXPECT_EQ(48, image.width());
83  EXPECT_EQ(48, image.height());
84
85  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
86}
87
88TEST(SelectFaviconFramesTest, _16From16) {
89  SCOPED_FAVICON_SCALE_FACTOR_1X;
90
91  vector<SkBitmap> bitmaps;
92  bitmaps.push_back(MakeBitmap(SK_ColorRED, 15, 15));
93  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
94  bitmaps.push_back(MakeBitmap(SK_ColorBLUE, 17, 17));
95
96  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
97      SizesFromBitmaps(bitmaps), 16, NULL);
98  image.EnsureRepsForSupportedScales();
99  EXPECT_EQ(1u, image.image_reps().size());
100  ASSERT_TRUE(image.HasRepresentation(1.0f));
101  EXPECT_EQ(16, image.width());
102  EXPECT_EQ(16, image.height());
103  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
104
105#if !defined(OS_IOS)
106  const gfx::ImageSkiaRep& rep = image.GetRepresentation(1.5f);
107  EXPECT_EQ(1.5f, rep.scale());
108  EXPECT_EQ(16, rep.GetWidth());
109  EXPECT_EQ(16, rep.GetHeight());
110  EXPECT_EQ(24, rep.pixel_width());
111  EXPECT_EQ(24, rep.pixel_height());
112  EXPECT_EQ(2u, image.image_reps().size());
113#endif
114}
115
116TEST(SelectFaviconFramesTest, _16From17) {
117  SCOPED_FAVICON_SCALE_FACTOR_1X;
118
119  vector<SkBitmap> bitmaps;
120  bitmaps.push_back(MakeBitmap(SK_ColorRED, 15, 15));
121  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 17, 17));
122
123  // Should resample from the bigger candidate.
124  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
125      SizesFromBitmaps(bitmaps), 16, NULL);
126  image.EnsureRepsForSupportedScales();
127  EXPECT_EQ(1u, image.image_reps().size());
128  ASSERT_TRUE(image.HasRepresentation(1.0f));
129  EXPECT_EQ(16, image.width());
130  EXPECT_EQ(16, image.height());
131  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
132}
133
134TEST(SelectFaviconFramesTest, _16From15) {
135  SCOPED_FAVICON_SCALE_FACTOR_1X;
136
137  vector<SkBitmap> bitmaps;
138  bitmaps.push_back(MakeBitmap(SK_ColorRED, 14, 14));
139  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 15, 15));
140
141  // If nothing else is available, should resample from the next smaller
142  // candidate.
143  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
144      SizesFromBitmaps(bitmaps), 16, NULL);
145  image.EnsureRepsForSupportedScales();
146  EXPECT_EQ(1u, image.image_reps().size());
147  ASSERT_TRUE(image.HasRepresentation(1.0f));
148  EXPECT_EQ(16, image.width());
149  EXPECT_EQ(16, image.height());
150  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
151}
152
153TEST(SelectFaviconFramesTest, _16From16_Scale2x_32_From_16) {
154  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
155  vector<SkBitmap> bitmaps;
156  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
157
158  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
159      SizesFromBitmaps(bitmaps), 16, NULL);
160  image.EnsureRepsForSupportedScales();
161  EXPECT_EQ(2u, image.image_reps().size());
162  ASSERT_TRUE(image.HasRepresentation(1.0f));
163  ASSERT_TRUE(image.HasRepresentation(2.0f));
164  EXPECT_EQ(16, image.width());
165  EXPECT_EQ(16, image.height());
166  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
167  EXPECT_EQ(SK_ColorGREEN, GetColor2x(image));
168}
169
170TEST(SelectFaviconFramesTest, _16From16_Scale2x_32_From_32) {
171  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
172
173  vector<SkBitmap> bitmaps;
174  bitmaps.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
175  bitmaps.push_back(MakeBitmap(SK_ColorBLUE, 32, 32));
176
177  gfx::ImageSkia image = CreateFaviconImageSkia(bitmaps,
178      SizesFromBitmaps(bitmaps), 16, NULL);
179  image.EnsureRepsForSupportedScales();
180  EXPECT_EQ(2u, image.image_reps().size());
181  ASSERT_TRUE(image.HasRepresentation(1.0f));
182  ASSERT_TRUE(image.HasRepresentation(2.0f));
183  EXPECT_EQ(16, image.width());
184  EXPECT_EQ(16, image.height());
185  EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
186  EXPECT_EQ(SK_ColorBLUE, GetColor2x(image));
187
188#if !defined(OS_IOS)
189  const gfx::ImageSkiaRep& rep = image.GetRepresentation(1.5f);
190  EXPECT_EQ(1.5f, rep.scale());
191  EXPECT_EQ(16, rep.GetWidth());
192  EXPECT_EQ(16, rep.GetHeight());
193  EXPECT_EQ(24, rep.pixel_width());
194  EXPECT_EQ(24, rep.pixel_height());
195  EXPECT_EQ(3u, image.image_reps().size());
196#endif
197}
198
199TEST(SelectFaviconFramesTest, ExactMatchBetterThanLargeBitmap) {
200  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
201
202  float score1;
203  vector<SkBitmap> bitmaps1;
204  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 48, 48));
205  CreateFaviconImageSkia(
206      bitmaps1,
207      SizesFromBitmaps(bitmaps1), 16, &score1);
208
209  float score2;
210  vector<SkBitmap> bitmaps2;
211  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
212  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 32, 32));
213  CreateFaviconImageSkia(bitmaps2,
214      SizesFromBitmaps(bitmaps2), 16, &score2);
215
216  EXPECT_GT(score2, score1);
217}
218
219TEST(SelectFaviconFramesTest, UpsampleABitBetterThanHugeBitmap) {
220  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
221
222  float score1;
223  vector<SkBitmap> bitmaps1;
224  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 128, 128));
225  CreateFaviconImageSkia(bitmaps1,
226      SizesFromBitmaps(bitmaps1), 16, &score1);
227
228  float score2;
229  vector<SkBitmap> bitmaps2;
230  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 24, 24));
231  CreateFaviconImageSkia(bitmaps2,
232      SizesFromBitmaps(bitmaps2), 16, &score2);
233
234  float score3;
235  vector<SkBitmap> bitmaps3;
236  bitmaps3.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
237  CreateFaviconImageSkia(bitmaps3,
238      SizesFromBitmaps(bitmaps3), 16, &score3);
239
240  float score4;
241  vector<SkBitmap> bitmaps4;
242  bitmaps4.push_back(MakeBitmap(SK_ColorGREEN, 15, 15));
243  CreateFaviconImageSkia(bitmaps4,
244      SizesFromBitmaps(bitmaps4), 16, &score4);
245
246  EXPECT_GT(score2, score1);
247  EXPECT_GT(score3, score1);
248  EXPECT_GT(score4, score1);
249}
250
251TEST(SelectFaviconFramesTest, DownsamplingBetterThanUpsampling) {
252  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
253
254  float score1;
255  vector<SkBitmap> bitmaps1;
256  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 8, 8));
257  CreateFaviconImageSkia(bitmaps1,
258                         SizesFromBitmaps(bitmaps1), 16, &score1);
259
260  float score2;
261  vector<SkBitmap> bitmaps2;
262  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 24, 24));
263  CreateFaviconImageSkia(bitmaps2,
264                         SizesFromBitmaps(bitmaps2), 16, &score2);
265
266  EXPECT_GT(score2, score1);
267}
268
269TEST(SelectFaviconFramesTest, DownsamplingLessIsBetter) {
270  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
271
272  float score1;
273  vector<SkBitmap> bitmaps1;
274  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 34, 34));
275  CreateFaviconImageSkia(bitmaps1,
276      SizesFromBitmaps(bitmaps1), 16, &score1);
277
278  float score2;
279  vector<SkBitmap> bitmaps2;
280  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 33, 33));
281  CreateFaviconImageSkia(bitmaps2,
282      SizesFromBitmaps(bitmaps2), 16, &score2);
283
284  EXPECT_GT(score2, score1);
285}
286
287TEST(SelectFaviconFramesTest, UpsamplingLessIsBetter) {
288  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
289
290  float score1;
291  vector<SkBitmap> bitmaps1;
292  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 8, 8));
293  CreateFaviconImageSkia(bitmaps1,
294      SizesFromBitmaps(bitmaps1), 16, &score1);
295
296  float score2;
297  vector<SkBitmap> bitmaps2;
298  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 9, 9));
299  CreateFaviconImageSkia(bitmaps2,
300      SizesFromBitmaps(bitmaps2), 16, &score2);
301
302  EXPECT_GT(score2, score1);
303}
304
305// Test that the score is determined by the |original_sizes| parameter, not the
306// |bitmaps| parameter to SelectFaviconFrames().
307TEST(SelectFaviconFramesTest, ScoreDeterminedByOriginalSizes) {
308  SCOPED_FAVICON_SCALE_FACTOR_1XAND2X;
309
310  vector<SkBitmap> bitmaps1;
311  bitmaps1.push_back(MakeBitmap(SK_ColorGREEN, 16, 16));
312  vector<gfx::Size> sizes1;
313  sizes1.push_back(gfx::Size(256, 256));
314  float score1;
315  CreateFaviconImageSkia(bitmaps1, sizes1, 16, &score1);
316
317  vector<SkBitmap> bitmaps2;
318  bitmaps2.push_back(MakeBitmap(SK_ColorGREEN, 15, 15));
319  vector<gfx::Size> sizes2;
320  sizes2.push_back(gfx::Size(15, 15));
321  float score2;
322  CreateFaviconImageSkia(bitmaps2, sizes2, 16, &score2);
323
324  EXPECT_GT(score2, score1);
325}
326
327}  // namespace
328