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"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/mime_util/mime_util.h"
13 #include "content/public/browser/web_contents.h"
14 #include "ui/gfx/screen.h"
16 using content::Manifest
;
18 ManifestIconSelector::ManifestIconSelector(float preferred_icon_size_in_pixels
,
19 float minimum_icon_size_in_pixels
)
20 : preferred_icon_size_in_pixels_(preferred_icon_size_in_pixels
),
21 minimum_icon_size_in_pixels_(minimum_icon_size_in_pixels
) {
24 bool ManifestIconSelector::IconSizesContainsPreferredSize(
25 const std::vector
<gfx::Size
>& sizes
) {
26 for (size_t i
= 0; i
< sizes
.size(); ++i
) {
27 if (sizes
[i
].height() != sizes
[i
].width())
29 if (sizes
[i
].width() == preferred_icon_size_in_pixels_
)
36 bool ManifestIconSelector::IconSizesContainsBiggerThanMinimumSize(
37 const std::vector
<gfx::Size
>& sizes
) {
38 for (size_t i
= 0; i
< sizes
.size(); ++i
) {
39 if (sizes
[i
].height() != sizes
[i
].width())
41 if (sizes
[i
].width() >= minimum_icon_size_in_pixels_
)
47 int ManifestIconSelector::FindBestMatchingIconForDensity(
48 const std::vector
<content::Manifest::Icon
>& icons
,
51 int best_delta
= std::numeric_limits
<int>::min();
53 for (size_t i
= 0; i
< icons
.size(); ++i
) {
54 if (icons
[i
].density
!= density
)
57 const std::vector
<gfx::Size
>& sizes
= icons
[i
].sizes
;
58 for (size_t j
= 0; j
< sizes
.size(); ++j
) {
59 if (sizes
[j
].height() != sizes
[j
].width())
61 int delta
= sizes
[j
].width() - preferred_icon_size_in_pixels_
;
64 if (best_delta
> 0 && delta
< 0)
66 if ((best_delta
> 0 && delta
< best_delta
) ||
67 (best_delta
< 0 && delta
> best_delta
)) {
77 int ManifestIconSelector::FindBestMatchingIcon(
78 const std::vector
<content::Manifest::Icon
>& icons
,
82 // The first pass is to find the ideal icon. That icon is of the right size
83 // with the default density or the device's density.
84 for (size_t i
= 0; i
< icons
.size(); ++i
) {
85 if (icons
[i
].density
== density
&&
86 IconSizesContainsPreferredSize(icons
[i
].sizes
)) {
90 // If there is an icon with the right size but not the right density, keep
91 // it on the side and only use it if nothing better is found.
92 if (icons
[i
].density
== Manifest::Icon::kDefaultDensity
&&
93 IconSizesContainsPreferredSize(icons
[i
].sizes
)) {
101 // The second pass is to find an icon with 'any'. The current device scale
102 // factor is preferred. Otherwise, the default scale factor is used.
103 for (size_t i
= 0; i
< icons
.size(); ++i
) {
104 if (icons
[i
].density
== density
&&
105 IconSizesContainsAny(icons
[i
].sizes
)) {
109 // If there is an icon with 'any' but not the right density, keep it on the
110 // side and only use it if nothing better is found.
111 if (icons
[i
].density
== Manifest::Icon::kDefaultDensity
&&
112 IconSizesContainsAny(icons
[i
].sizes
)) {
117 if (best_index
!= -1)
120 // The last pass will try to find the best suitable icon for the device's
121 // scale factor. If none, another pass will be run using kDefaultDensity.
122 best_index
= FindBestMatchingIconForDensity(icons
, density
);
123 if (best_index
!= -1 &&
124 IconSizesContainsBiggerThanMinimumSize(icons
[best_index
].sizes
))
127 best_index
= FindBestMatchingIconForDensity(icons
,
128 Manifest::Icon::kDefaultDensity
);
129 if (best_index
!= -1 &&
130 IconSizesContainsBiggerThanMinimumSize(icons
[best_index
].sizes
))
138 bool ManifestIconSelector::IconSizesContainsAny(
139 const std::vector
<gfx::Size
>& sizes
) {
140 for (size_t i
= 0; i
< sizes
.size(); ++i
) {
141 if (sizes
[i
].IsEmpty())
148 std::vector
<Manifest::Icon
> ManifestIconSelector::FilterIconsByType(
149 const std::vector
<content::Manifest::Icon
>& icons
) {
150 std::vector
<Manifest::Icon
> result
;
152 for (size_t i
= 0; i
< icons
.size(); ++i
) {
153 if (icons
[i
].type
.is_null() ||
154 mime_util::IsSupportedImageMimeType(
155 base::UTF16ToUTF8(icons
[i
].type
.string()))) {
156 result
.push_back(icons
[i
]);
164 GURL
ManifestIconSelector::FindBestMatchingIcon(
165 const std::vector
<Manifest::Icon
>& unfiltered_icons
,
166 const float preferred_icon_size_in_dp
,
167 const gfx::Screen
* screen
) {
168 const float device_scale_factor
=
169 screen
->GetPrimaryDisplay().device_scale_factor();
170 const float preferred_icon_size_in_pixels
=
171 preferred_icon_size_in_dp
* device_scale_factor
;
173 const int minimum_scale_factor
= std::max(
174 static_cast<int>(floor(device_scale_factor
- 1)), 1);
175 const float minimum_icon_size_in_pixels
=
176 preferred_icon_size_in_dp
* minimum_scale_factor
;
178 std::vector
<Manifest::Icon
> icons
=
179 ManifestIconSelector::FilterIconsByType(unfiltered_icons
);
181 ManifestIconSelector
selector(preferred_icon_size_in_pixels
,
182 minimum_icon_size_in_pixels
);
183 int index
= selector
.FindBestMatchingIcon(icons
, device_scale_factor
);
186 return icons
[index
].src
;