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