blob: 7e3bd1f900508d23abdba6ff4efb41443fff4285 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/manifest/manifest_icon_selector.h"
#include <limits>
#include "base/strings/utf_string_conversions.h"
#include "components/mime_util/mime_util.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/screen.h"
using content::Manifest;
ManifestIconSelector::ManifestIconSelector(float preferred_icon_size_in_pixels)
: preferred_icon_size_in_pixels_(preferred_icon_size_in_pixels) {
}
bool ManifestIconSelector::IconSizesContainsPreferredSize(
const std::vector<gfx::Size>& sizes) {
for (size_t i = 0; i < sizes.size(); ++i) {
if (sizes[i].height() != sizes[i].width())
continue;
if (sizes[i].width() == preferred_icon_size_in_pixels_)
return true;
}
return false;
}
GURL ManifestIconSelector::FindBestMatchingIconForDensity(
const std::vector<content::Manifest::Icon>& icons,
float density) {
GURL url;
int best_delta = std::numeric_limits<int>::min();
for (size_t i = 0; i < icons.size(); ++i) {
if (icons[i].density != density)
continue;
const std::vector<gfx::Size>& sizes = icons[i].sizes;
for (size_t j = 0; j < sizes.size(); ++j) {
if (sizes[j].height() != sizes[j].width())
continue;
int delta = sizes[j].width() - preferred_icon_size_in_pixels_;
if (delta == 0)
return icons[i].src;
if (best_delta > 0 && delta < 0)
continue;
if ((best_delta > 0 && delta < best_delta) ||
(best_delta < 0 && delta > best_delta)) {
url = icons[i].src;
best_delta = delta;
}
}
}
return url;
}
GURL ManifestIconSelector::FindBestMatchingIcon(
const std::vector<content::Manifest::Icon>& unfiltered_icons,
float density) {
GURL url;
std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons);
// The first pass is to find the ideal icon. That icon is of the right size
// with the default density or the device's density.
for (size_t i = 0; i < icons.size(); ++i) {
if (icons[i].density == density &&
IconSizesContainsPreferredSize(icons[i].sizes)) {
return icons[i].src;
}
// If there is an icon with the right size but not the right density, keep
// it on the side and only use it if nothing better is found.
if (icons[i].density == Manifest::Icon::kDefaultDensity &&
IconSizesContainsPreferredSize(icons[i].sizes)) {
url = icons[i].src;
}
}
// The second pass is to find an icon with 'any'. The current device scale
// factor is preferred. Otherwise, the default scale factor is used.
for (size_t i = 0; i < icons.size(); ++i) {
if (icons[i].density == density &&
IconSizesContainsAny(icons[i].sizes)) {
return icons[i].src;
}
// If there is an icon with 'any' but not the right density, keep it on the
// side and only use it if nothing better is found.
if (icons[i].density == Manifest::Icon::kDefaultDensity &&
IconSizesContainsAny(icons[i].sizes)) {
url = icons[i].src;
}
}
// The last pass will try to find the best suitable icon for the device's
// scale factor. If none, another pass will be run using kDefaultDensity.
if (!url.is_valid())
url = FindBestMatchingIconForDensity(icons, density);
if (!url.is_valid())
url = FindBestMatchingIconForDensity(icons,
Manifest::Icon::kDefaultDensity);
return url;
}
// static
bool ManifestIconSelector::IconSizesContainsAny(
const std::vector<gfx::Size>& sizes) {
for (size_t i = 0; i < sizes.size(); ++i) {
if (sizes[i].IsEmpty())
return true;
}
return false;
}
// static
std::vector<Manifest::Icon> ManifestIconSelector::FilterIconsByType(
const std::vector<content::Manifest::Icon>& icons) {
std::vector<Manifest::Icon> result;
for (size_t i = 0; i < icons.size(); ++i) {
if (icons[i].type.is_null() ||
mime_util::IsSupportedImageMimeType(
base::UTF16ToUTF8(icons[i].type.string()))) {
result.push_back(icons[i]);
}
}
return result;
}
// static
GURL ManifestIconSelector::FindBestMatchingIcon(
const std::vector<Manifest::Icon>& unfiltered_icons,
const float preferred_icon_size_in_dp,
const gfx::Screen* screen) {
const float device_scale_factor =
screen->GetPrimaryDisplay().device_scale_factor();
const float preferred_icon_size_in_pixels =
preferred_icon_size_in_dp * device_scale_factor;
ManifestIconSelector selector(preferred_icon_size_in_pixels);
return selector.FindBestMatchingIcon(unfiltered_icons, device_scale_factor);
}
|