1 // Copyright 2015 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.
5 #include "chrome/browser/android/manifest_icon_selector.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "ui/gfx/screen.h"
10 #include "ui/gfx/screen_type_delegate.h"
14 const int kPreferredIconSize
= 48;
18 // A dummy implementation of gfx::Screen, since ManifestIconSelector needs
19 // access to a gfx::Display's device scale factor.
20 // This is inspired by web_contents_video_capture_device_unittest.cc
21 // A bug has been opened to merge all those mocks: http://crbug.com/417227
22 class FakeScreen
: public gfx::Screen
{
24 FakeScreen() : display_(0x1337, gfx::Rect(0, 0, 2560, 1440)) {
26 ~FakeScreen() override
{}
28 void SetDisplayDeviceScaleFactor(float device_scale_factor
) {
29 display_
.set_device_scale_factor(device_scale_factor
);
32 // gfx::Screen implementation (only what's needed for testing).
33 gfx::Point
GetCursorScreenPoint() override
{ return gfx::Point(); }
34 gfx::NativeWindow
GetWindowUnderCursor() override
{ return nullptr; }
35 gfx::NativeWindow
GetWindowAtScreenPoint(
36 const gfx::Point
& point
) override
{ return nullptr; }
37 int GetNumDisplays() const override
{ return 1; }
38 std::vector
<gfx::Display
> GetAllDisplays() const override
{
39 return std::vector
<gfx::Display
>(1, display_
);
41 gfx::Display
GetDisplayNearestWindow(
42 gfx::NativeView view
) const override
{
45 gfx::Display
GetDisplayNearestPoint(
46 const gfx::Point
& point
) const override
{
49 gfx::Display
GetDisplayMatching(
50 const gfx::Rect
& match_rect
) const override
{
53 gfx::Display
GetPrimaryDisplay() const override
{
56 void AddObserver(gfx::DisplayObserver
* observer
) override
{}
57 void RemoveObserver(gfx::DisplayObserver
* observer
) override
{}
60 gfx::Display display_
;
62 DISALLOW_COPY_AND_ASSIGN(FakeScreen
);
65 class ManifestIconSelectorTest
: public testing::Test
{
67 ManifestIconSelectorTest() {}
68 ~ManifestIconSelectorTest() override
{}
70 GURL
FindBestMatchingIcon(const std::vector
<content::Manifest::Icon
>& icons
) {
71 return ManifestIconSelector::FindBestMatchingIcon(
73 GetPreferredIconSizeInDp(),
77 void SetDisplayDeviceScaleFactor(float device_scale_factor
) {
78 fake_screen_
.SetDisplayDeviceScaleFactor(device_scale_factor
);
81 static int GetPreferredIconSizeInDp() {
82 return kPreferredIconSize
;
85 static content::Manifest::Icon
CreateIcon(
86 const std::string
& url
,
87 const std::string
& type
,
89 const std::vector
<gfx::Size
> sizes
) {
90 content::Manifest::Icon icon
;
93 icon
.type
= base::NullableString16(base::UTF8ToUTF16(type
), false);
94 icon
.density
= density
;
101 FakeScreen fake_screen_
;
103 DISALLOW_COPY_AND_ASSIGN(ManifestIconSelectorTest
);
106 TEST_F(ManifestIconSelectorTest
, NoIcons
) {
107 // No icons should return the empty URL.
108 std::vector
<content::Manifest::Icon
> icons
;
109 GURL url
= FindBestMatchingIcon(icons
);
110 EXPECT_TRUE(url
.is_empty());
113 TEST_F(ManifestIconSelectorTest
, NoSizes
) {
114 // Icon with no sizes are ignored.
115 std::vector
<content::Manifest::Icon
> icons
;
117 CreateIcon("http://foo.com/icon.png", "", 1.0, std::vector
<gfx::Size
>()));
119 GURL url
= FindBestMatchingIcon(icons
);
120 EXPECT_TRUE(url
.is_empty());
123 TEST_F(ManifestIconSelectorTest
, MIMETypeFiltering
) {
124 // Icons with type specified to a MIME type that isn't a valid image MIME type
126 std::vector
<gfx::Size
> sizes
;
127 sizes
.push_back(gfx::Size(10, 10));
129 std::vector
<content::Manifest::Icon
> icons
;
131 CreateIcon("http://foo.com/icon.png", "image/foo_bar", 1.0, sizes
));
132 icons
.push_back(CreateIcon("http://foo.com/icon.png", "image/", 1.0, sizes
));
133 icons
.push_back(CreateIcon("http://foo.com/icon.png", "image/", 1.0, sizes
));
135 CreateIcon("http://foo.com/icon.png", "video/mp4", 1.0, sizes
));
137 GURL url
= FindBestMatchingIcon(icons
);
138 EXPECT_TRUE(url
.is_empty());
142 CreateIcon("http://foo.com/icon.png", "image/png", 1.0, sizes
));
143 url
= FindBestMatchingIcon(icons
);
144 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
148 CreateIcon("http://foo.com/icon.png", "image/gif", 1.0, sizes
));
149 url
= FindBestMatchingIcon(icons
);
150 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
154 CreateIcon("http://foo.com/icon.png", "image/jpeg", 1.0, sizes
));
155 url
= FindBestMatchingIcon(icons
);
156 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
159 TEST_F(ManifestIconSelectorTest
, PreferredSizeOfCurrentDensityIsUsedFirst
) {
160 // This test has three icons each are marked with sizes set to the preferred
161 // icon size for the associated density.
162 std::vector
<gfx::Size
> sizes_1
;
163 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
164 GetPreferredIconSizeInDp()));
166 std::vector
<gfx::Size
> sizes_2
;
167 sizes_2
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 2,
168 GetPreferredIconSizeInDp() * 2));
170 std::vector
<gfx::Size
> sizes_3
;
171 sizes_3
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 3,
172 GetPreferredIconSizeInDp() * 3));
174 std::vector
<content::Manifest::Icon
> icons
;
175 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes_1
));
176 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes_2
));
177 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes_3
));
179 SetDisplayDeviceScaleFactor(1.0f
);
180 GURL url
= FindBestMatchingIcon(icons
);
181 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
183 SetDisplayDeviceScaleFactor(2.0f
);
184 url
= FindBestMatchingIcon(icons
);
185 EXPECT_EQ("http://foo.com/icon_x2.png", url
.spec());
187 SetDisplayDeviceScaleFactor(3.0f
);
188 url
= FindBestMatchingIcon(icons
);
189 EXPECT_EQ("http://foo.com/icon_x3.png", url
.spec());
192 TEST_F(ManifestIconSelectorTest
, PreferredSizeOfDefaultDensityIsUsedSecond
) {
193 // This test has three icons. The first one is of density zero and is marked
194 // with three sizes which are the preferred icon size for density 1, 2 and 3.
195 // The icon for density 2 and 3 have a size set to 2x2 and 3x3.
196 // Regardless of the device scale factor, the icon of density 1 is going to be
197 // used because it matches the preferred size.
198 std::vector
<gfx::Size
> sizes_1
;
199 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
200 GetPreferredIconSizeInDp()));
201 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 2,
202 GetPreferredIconSizeInDp() * 2));
203 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 3,
204 GetPreferredIconSizeInDp() * 3));
206 std::vector
<gfx::Size
> sizes_2
;
207 sizes_2
.push_back(gfx::Size(2, 2));
209 std::vector
<gfx::Size
> sizes_3
;
210 sizes_3
.push_back(gfx::Size(3, 3));
212 std::vector
<content::Manifest::Icon
> icons
;
213 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes_1
));
214 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes_2
));
215 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes_3
));
217 SetDisplayDeviceScaleFactor(1.0f
);
218 GURL url
= FindBestMatchingIcon(icons
);
219 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
221 SetDisplayDeviceScaleFactor(2.0f
);
222 url
= FindBestMatchingIcon(icons
);
223 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
225 SetDisplayDeviceScaleFactor(3.0f
);
226 url
= FindBestMatchingIcon(icons
);
227 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
230 TEST_F(ManifestIconSelectorTest
, DeviceDensityFirst
) {
231 // If there is no perfect icon but an icon of the current device density is
232 // present, it will be picked.
233 // This test has three icons each are marked with sizes set to the preferred
234 // icon size for the associated density.
235 std::vector
<gfx::Size
> sizes
;
236 sizes
.push_back(gfx::Size(2, 2));
238 std::vector
<content::Manifest::Icon
> icons
;
239 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes
));
240 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
241 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes
));
243 SetDisplayDeviceScaleFactor(1.0f
);
244 GURL url
= FindBestMatchingIcon(icons
);
245 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
247 SetDisplayDeviceScaleFactor(2.0f
);
248 url
= FindBestMatchingIcon(icons
);
249 EXPECT_EQ("http://foo.com/icon_x2.png", url
.spec());
251 SetDisplayDeviceScaleFactor(3.0f
);
252 url
= FindBestMatchingIcon(icons
);
253 EXPECT_EQ("http://foo.com/icon_x3.png", url
.spec());
256 TEST_F(ManifestIconSelectorTest
, DeviceDensityFallback
) {
257 // If there is no perfect icon but and no icon of the current display density,
258 // an icon of density 1.0 will be used.
259 std::vector
<gfx::Size
> sizes
;
260 sizes
.push_back(gfx::Size(2, 2));
262 std::vector
<content::Manifest::Icon
> icons
;
263 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes
));
264 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
266 SetDisplayDeviceScaleFactor(3.0f
);
267 GURL url
= FindBestMatchingIcon(icons
);
268 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
271 TEST_F(ManifestIconSelectorTest
, DoNotUseOtherDensities
) {
272 // If there are only icons of densities that are not the current display
273 // density or the default density, they are ignored.
274 std::vector
<gfx::Size
> sizes
;
275 sizes
.push_back(gfx::Size(2, 2));
277 std::vector
<content::Manifest::Icon
> icons
;
278 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
280 SetDisplayDeviceScaleFactor(3.0f
);
281 GURL url
= FindBestMatchingIcon(icons
);
282 EXPECT_TRUE(url
.is_empty());
285 TEST_F(ManifestIconSelectorTest
, NotSquareIconsAreIgnored
) {
286 std::vector
<gfx::Size
> sizes
;
287 sizes
.push_back(gfx::Size(20, 2));
289 std::vector
<content::Manifest::Icon
> icons
;
290 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes
));
292 GURL url
= FindBestMatchingIcon(icons
);
293 EXPECT_TRUE(url
.is_empty());
296 TEST_F(ManifestIconSelectorTest
, ClosestIconToPreferred
) {
297 // This test verifies ManifestIconSelector::FindBestMatchingIcon by passing
298 // different icon sizes and checking which one is picked.
299 // The Device Scale Factor is 1.0 and the preferred icon size is returned by
300 // GetPreferredIconSizeInDp().
301 int very_small
= GetPreferredIconSizeInDp() / 4;
302 int small
= GetPreferredIconSizeInDp() / 2;
303 int bit_small
= GetPreferredIconSizeInDp() - 1;
304 int bit_big
= GetPreferredIconSizeInDp() + 1;
305 int big
= GetPreferredIconSizeInDp() * 2;
306 int very_big
= GetPreferredIconSizeInDp() * 4;
308 // (very_small, bit_small) => bit_small
310 std::vector
<gfx::Size
> sizes_1
;
311 sizes_1
.push_back(gfx::Size(very_small
, very_small
));
313 std::vector
<gfx::Size
> sizes_2
;
314 sizes_2
.push_back(gfx::Size(bit_small
, bit_small
));
316 std::vector
<content::Manifest::Icon
> icons
;
317 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
318 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
320 GURL url
= FindBestMatchingIcon(icons
);
321 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
324 // (very_small, bit_small, smaller) => bit_small
326 std::vector
<gfx::Size
> sizes_1
;
327 sizes_1
.push_back(gfx::Size(very_small
, very_small
));
329 std::vector
<gfx::Size
> sizes_2
;
330 sizes_2
.push_back(gfx::Size(bit_small
, bit_small
));
332 std::vector
<gfx::Size
> sizes_3
;
333 sizes_3
.push_back(gfx::Size(small
, small
));
335 std::vector
<content::Manifest::Icon
> icons
;
336 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
337 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
338 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_3
));
340 GURL url
= FindBestMatchingIcon(icons
);
341 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
344 // (very_big, big) => big
346 std::vector
<gfx::Size
> sizes_1
;
347 sizes_1
.push_back(gfx::Size(very_big
, very_big
));
349 std::vector
<gfx::Size
> sizes_2
;
350 sizes_2
.push_back(gfx::Size(big
, big
));
352 std::vector
<content::Manifest::Icon
> icons
;
353 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
354 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
356 GURL url
= FindBestMatchingIcon(icons
);
357 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
360 // (very_big, big, bit_big) => bit_big
362 std::vector
<gfx::Size
> sizes_1
;
363 sizes_1
.push_back(gfx::Size(very_big
, very_big
));
365 std::vector
<gfx::Size
> sizes_2
;
366 sizes_2
.push_back(gfx::Size(big
, big
));
368 std::vector
<gfx::Size
> sizes_3
;
369 sizes_3
.push_back(gfx::Size(bit_big
, bit_big
));
371 std::vector
<content::Manifest::Icon
> icons
;
372 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
373 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_2
));
374 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_3
));
376 GURL url
= FindBestMatchingIcon(icons
);
377 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
380 // (bit_small, very_big) => very_big
382 std::vector
<gfx::Size
> sizes_1
;
383 sizes_1
.push_back(gfx::Size(bit_small
, bit_small
));
385 std::vector
<gfx::Size
> sizes_2
;
386 sizes_2
.push_back(gfx::Size(very_big
, very_big
));
388 std::vector
<content::Manifest::Icon
> icons
;
389 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
390 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
392 GURL url
= FindBestMatchingIcon(icons
);
393 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
396 // (bit_small, bit_big) => bit_big
398 std::vector
<gfx::Size
> sizes_1
;
399 sizes_1
.push_back(gfx::Size(bit_small
, bit_small
));
401 std::vector
<gfx::Size
> sizes_2
;
402 sizes_2
.push_back(gfx::Size(bit_big
, bit_big
));
404 std::vector
<content::Manifest::Icon
> icons
;
405 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
406 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
408 GURL url
= FindBestMatchingIcon(icons
);
409 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
413 TEST_F(ManifestIconSelectorTest
, UseAnyIfNoPreferredSize
) {
414 // 'any' (ie. gfx::Size(0,0)) should be used if there is no icon of a
415 // preferred size. An icon with the current device scale factor is preferred
416 // over one with the default density.
418 // 'any' with preferred size => preferred size
420 std::vector
<gfx::Size
> sizes_1
;
421 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
422 GetPreferredIconSizeInDp()));
423 std::vector
<gfx::Size
> sizes_2
;
424 sizes_2
.push_back(gfx::Size(0,0));
426 std::vector
<content::Manifest::Icon
> icons
;
427 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_1
));
428 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_2
));
430 GURL url
= FindBestMatchingIcon(icons
);
431 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
434 // 'any' with nearly preferred size => any
436 std::vector
<gfx::Size
> sizes_1
;
437 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() + 1,
438 GetPreferredIconSizeInDp() + 1));
439 std::vector
<gfx::Size
> sizes_2
;
440 sizes_2
.push_back(gfx::Size(0,0));
442 std::vector
<content::Manifest::Icon
> icons
;
443 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
444 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
446 GURL url
= FindBestMatchingIcon(icons
);
447 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
450 // 'any' on default density and current density => current density.
452 std::vector
<gfx::Size
> sizes
;
453 sizes
.push_back(gfx::Size(0,0));
455 std::vector
<content::Manifest::Icon
> icons
;
456 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes
));
457 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 3.0, sizes
));
459 SetDisplayDeviceScaleFactor(3.0f
);
460 GURL url
= FindBestMatchingIcon(icons
);
461 EXPECT_EQ("http://foo.com/icon.png", url
.spec());