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/manifest/manifest_icon_selector.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/public/browser/web_contents.h"
11 #include "net/base/mime_util.h"
12 #include "ui/gfx/screen.h"
14 using content::Manifest
;
16 ManifestIconSelector::ManifestIconSelector(float preferred_icon_size_in_pixels
)
17 : preferred_icon_size_in_pixels_(preferred_icon_size_in_pixels
) {
20 bool ManifestIconSelector::IconSizesContainsPreferredSize(
21 const std::vector
<gfx::Size
>& sizes
) {
22 for (size_t i
= 0; i
< sizes
.size(); ++i
) {
23 if (sizes
[i
].height() != sizes
[i
].width())
25 if (sizes
[i
].width() == preferred_icon_size_in_pixels_
)
32 GURL
ManifestIconSelector::FindBestMatchingIconForDensity(
33 const std::vector
<content::Manifest::Icon
>& icons
,
36 int best_delta
= std::numeric_limits
<int>::min();
38 for (size_t i
= 0; i
< icons
.size(); ++i
) {
39 if (icons
[i
].density
!= density
)
42 const std::vector
<gfx::Size
>& sizes
= icons
[i
].sizes
;
43 for (size_t j
= 0; j
< sizes
.size(); ++j
) {
44 if (sizes
[j
].height() != sizes
[j
].width())
46 int delta
= sizes
[j
].width() - preferred_icon_size_in_pixels_
;
49 if (best_delta
> 0 && delta
< 0)
51 if ((best_delta
> 0 && delta
< best_delta
) ||
52 (best_delta
< 0 && delta
> best_delta
)) {
62 GURL
ManifestIconSelector::FindBestMatchingIcon(
63 const std::vector
<content::Manifest::Icon
>& unfiltered_icons
,
66 std::vector
<Manifest::Icon
> icons
= FilterIconsByType(unfiltered_icons
);
68 // The first pass is to find the ideal icon. That icon is of the right size
69 // with the default density or the device's density.
70 for (size_t i
= 0; i
< icons
.size(); ++i
) {
71 if (icons
[i
].density
== density
&&
72 IconSizesContainsPreferredSize(icons
[i
].sizes
)) {
76 // If there is an icon with the right size but not the right density, keep
77 // it on the side and only use it if nothing better is found.
78 if (icons
[i
].density
== Manifest::Icon::kDefaultDensity
&&
79 IconSizesContainsPreferredSize(icons
[i
].sizes
)) {
84 // The second pass is to find an icon with 'any'. The current device scale
85 // factor is preferred. Otherwise, the default scale factor is used.
86 for (size_t i
= 0; i
< icons
.size(); ++i
) {
87 if (icons
[i
].density
== density
&&
88 IconSizesContainsAny(icons
[i
].sizes
)) {
92 // If there is an icon with 'any' but not the right density, keep it on the
93 // side and only use it if nothing better is found.
94 if (icons
[i
].density
== Manifest::Icon::kDefaultDensity
&&
95 IconSizesContainsAny(icons
[i
].sizes
)) {
100 // The last pass will try to find the best suitable icon for the device's
101 // scale factor. If none, another pass will be run using kDefaultDensity.
103 url
= FindBestMatchingIconForDensity(icons
, density
);
105 url
= FindBestMatchingIconForDensity(icons
,
106 Manifest::Icon::kDefaultDensity
);
113 bool ManifestIconSelector::IconSizesContainsAny(
114 const std::vector
<gfx::Size
>& sizes
) {
115 for (size_t i
= 0; i
< sizes
.size(); ++i
) {
116 if (sizes
[i
].IsEmpty())
124 std::vector
<Manifest::Icon
> ManifestIconSelector::FilterIconsByType(
125 const std::vector
<content::Manifest::Icon
>& icons
) {
126 std::vector
<Manifest::Icon
> result
;
128 for (size_t i
= 0; i
< icons
.size(); ++i
) {
129 if (icons
[i
].type
.is_null() ||
130 net::IsSupportedImageMimeType(
131 base::UTF16ToUTF8(icons
[i
].type
.string()))) {
132 result
.push_back(icons
[i
]);
140 GURL
ManifestIconSelector::FindBestMatchingIcon(
141 const std::vector
<Manifest::Icon
>& unfiltered_icons
,
142 const float preferred_icon_size_in_dp
,
143 const gfx::Screen
* screen
) {
144 const float device_scale_factor
=
145 screen
->GetPrimaryDisplay().device_scale_factor();
146 const float preferred_icon_size_in_pixels
=
147 preferred_icon_size_in_dp
* device_scale_factor
;
149 ManifestIconSelector
selector(preferred_icon_size_in_pixels
);
150 return selector
.FindBestMatchingIcon(unfiltered_icons
, device_scale_factor
);