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/ui/app_list/arc/arc_app_icon.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/files/file_path.h" | |
11 #include "base/files/file_util.h" | |
12 #include "base/task_runner_util.h" | |
13 #include "chrome/browser/image_decoder.h" | |
14 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "extensions/grit/extensions_browser_resources.h" | |
17 #include "ui/base/resource/resource_bundle.h" | |
18 #include "ui/gfx/geometry/size.h" | |
19 #include "ui/gfx/image/image_skia_source.h" | |
20 | |
21 namespace { | |
22 | |
23 bool g_disable_decoding = false; | |
24 | |
25 } | |
26 | |
27 //////////////////////////////////////////////////////////////////////////////// | |
28 // ArcAppIcon::ReadResult | |
29 | |
30 struct ArcAppIcon::ReadResult { | |
jochen (gone - plz use gerrit)
2015/12/03 10:25:39
please add a ctor that takes args for and initiali
khmel1
2015/12/03 12:34:49
Done.
| |
31 enum Status { | |
32 OK, | |
33 FAIL, | |
34 REQUEST_TO_INSTALL, | |
35 }; | |
36 | |
37 Status status; | |
38 ui::ScaleFactor scale_factor; | |
39 std::string unsafe_icon_data; | |
40 }; | |
41 | |
42 //////////////////////////////////////////////////////////////////////////////// | |
43 // ArcAppIcon::Source | |
44 | |
45 class ArcAppIcon::Source : public gfx::ImageSkiaSource { | |
46 public: | |
47 explicit Source(const base::WeakPtr<ArcAppIcon>& host); | |
48 ~Source() override; | |
49 | |
50 private: | |
51 // gfx::ImageSkiaSource overrides: | |
52 gfx::ImageSkiaRep GetImageForScale(float scale) override; | |
53 | |
54 // Used to load images asynchronously. NULLed out when the ArcAppIcon is | |
55 // destroyed. | |
56 base::WeakPtr<ArcAppIcon> host_; | |
57 | |
58 DISALLOW_COPY_AND_ASSIGN(Source); | |
59 }; | |
60 | |
61 ArcAppIcon::Source::Source(const base::WeakPtr<ArcAppIcon>& host) | |
62 : host_(host) { | |
63 } | |
64 | |
65 ArcAppIcon::Source::~Source() { | |
66 } | |
67 | |
68 gfx::ImageSkiaRep ArcAppIcon::Source::GetImageForScale(float scale) { | |
69 if (host_) { | |
jochen (gone - plz use gerrit)
2015/12/03 10:25:39
no {} for single line bodies
khmel1
2015/12/03 12:34:49
Done.
| |
70 host_->LoadForScaleFactor(ui::GetSupportedScaleFactor(scale)); | |
71 } | |
72 | |
73 // Host loads icon asynchronously, so use default icon so far. | |
74 const gfx::ImageSkia* default_image = ResourceBundle::GetSharedInstance(). | |
75 GetImageSkiaNamed(IDR_APP_DEFAULT_ICON); | |
76 CHECK(default_image); | |
77 | |
78 return default_image->GetRepresentation(scale); | |
79 } | |
80 | |
81 class ArcAppIcon::DecodeRequest : public ImageDecoder::ImageRequest { | |
82 public: | |
83 DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, | |
84 int dimension, | |
85 ui::ScaleFactor scale_factor); | |
86 ~DecodeRequest() override; | |
87 | |
88 // ImageDecoder::ImageRequest | |
89 void OnImageDecoded(const SkBitmap& bitmap) override; | |
90 void OnDecodeImageFailed() override; | |
91 private: | |
92 base::WeakPtr<ArcAppIcon> host_; | |
93 int dimension_; | |
94 ui::ScaleFactor scale_factor_; | |
95 | |
96 DISALLOW_COPY_AND_ASSIGN(DecodeRequest); | |
97 }; | |
98 | |
99 //////////////////////////////////////////////////////////////////////////////// | |
100 // ArcAppIcon::DecodeRequest | |
101 | |
102 ArcAppIcon::DecodeRequest::DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, | |
103 int dimension, | |
104 ui::ScaleFactor scale_factor) | |
105 : host_(host), | |
106 dimension_(dimension), | |
107 scale_factor_(scale_factor) { | |
108 } | |
109 | |
110 ArcAppIcon::DecodeRequest::~DecodeRequest() { | |
111 } | |
112 | |
113 void ArcAppIcon::DecodeRequest::OnImageDecoded(const SkBitmap& bitmap) { | |
114 DCHECK(!bitmap.isNull() && !bitmap.empty()); | |
115 | |
116 if (!host_) { | |
117 return; | |
118 } | |
119 | |
120 int expected_dim = static_cast<int>( | |
121 ui::GetScaleForScaleFactor(scale_factor_) * dimension_ + 0.5f); | |
122 if (bitmap.width() != expected_dim || bitmap.height() != expected_dim) { | |
123 LOG(ERROR) << "Decoded ARC icon has unexpected dimension " | |
124 << bitmap.width() << "x" << bitmap.height() << ". Expected " | |
125 << expected_dim << "x" << "."; | |
126 return; | |
127 } | |
128 | |
129 gfx::ImageSkia image_skia; | |
130 image_skia.AddRepresentation(gfx::ImageSkiaRep( | |
131 bitmap, | |
132 ui::GetScaleForScaleFactor(scale_factor_))); | |
133 | |
134 host_->Update(&image_skia); | |
135 host_->DiscardDecodeRequest(this); | |
136 } | |
137 | |
138 void ArcAppIcon::DecodeRequest::OnDecodeImageFailed() { | |
139 LOG(ERROR) << "Failed to decode ARC icon."; | |
140 | |
141 if (!host_) { | |
142 return; | |
143 } | |
144 | |
145 host_->DiscardDecodeRequest(this); | |
146 } | |
147 | |
148 //////////////////////////////////////////////////////////////////////////////// | |
149 // ArcAppIcon | |
150 | |
151 // static | |
152 void ArcAppIcon::DisableDecodingForTesting() { | |
153 g_disable_decoding = true; | |
154 } | |
155 | |
156 ArcAppIcon::ArcAppIcon(content::BrowserContext* context, | |
157 const std::string& app_id, | |
158 int resource_size_in_dip, | |
159 Observer* observer) | |
160 : context_(context), | |
161 app_id_(app_id), | |
162 resource_size_in_dip_(resource_size_in_dip), | |
163 observer_(observer), | |
164 weak_ptr_factory_(this) { | |
165 CHECK(observer_ != NULL); | |
166 source_ = new Source(weak_ptr_factory_.GetWeakPtr()); | |
167 gfx::Size resource_size(resource_size_in_dip, resource_size_in_dip); | |
168 image_skia_ = gfx::ImageSkia(source_, resource_size); | |
169 } | |
170 | |
171 ArcAppIcon::~ArcAppIcon() { | |
172 } | |
173 | |
174 void ArcAppIcon::LoadForScaleFactor(ui::ScaleFactor scale_factor) { | |
175 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_); | |
176 if (!prefs) { | |
177 LOG(ERROR) << "ARC preferences service is not available."; | |
178 return; | |
179 } | |
180 | |
181 base::FilePath path = prefs->GetIconPath(app_id_, scale_factor); | |
182 if (path.empty()) { | |
183 return; | |
184 } | |
185 | |
186 base::PostTaskAndReplyWithResult(content::BrowserThread::GetBlockingPool(), | |
187 FROM_HERE, | |
188 base::Bind(&ArcAppIcon::ReadOnFileThread, | |
189 scale_factor, | |
190 path), | |
191 base::Bind(&ArcAppIcon::OnIconRead, | |
192 weak_ptr_factory_.GetWeakPtr())); | |
193 } | |
194 | |
195 void ArcAppIcon::RequestIcon(ui::ScaleFactor scale_factor) { | |
196 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
197 ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_); | |
198 if (!prefs) { | |
199 LOG(ERROR) << "ARC preferences service is not available."; | |
200 return; | |
201 } | |
202 // ArcAppListPrefs notifies ArcAppModelBuilder via Observer when icon is ready | |
203 // and ArcAppModelBuilder refreshes the icon of the corresponding item by | |
204 // calling LoadScaleFactor. | |
205 prefs->RequestIcon(app_id_, scale_factor); | |
206 } | |
207 | |
208 // static | |
209 scoped_ptr<ArcAppIcon::ReadResult> ArcAppIcon::ReadOnFileThread( | |
210 ui::ScaleFactor scale_factor, | |
211 const base::FilePath& path) { | |
212 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
213 DCHECK(!path.empty()); | |
214 | |
215 scoped_ptr<ArcAppIcon::ReadResult> result(new ArcAppIcon::ReadResult()); | |
216 result->scale_factor = scale_factor; | |
217 | |
218 if (!base::PathExists(path)) { | |
219 result->status = ArcAppIcon::ReadResult::REQUEST_TO_INSTALL; | |
220 return result.Pass(); | |
221 } | |
222 | |
223 // Read the file from disk. | |
224 if (!base::ReadFileToString(path, &result->unsafe_icon_data)) { | |
225 LOG(ERROR) << "Failed to read an ARC icon from file " | |
226 << path.MaybeAsASCII(); | |
227 result->status = ArcAppIcon::ReadResult::FAIL; | |
228 return result.Pass(); | |
229 } | |
230 | |
231 result->status = ArcAppIcon::ReadResult::OK; | |
232 return result.Pass(); | |
233 } | |
234 | |
235 void ArcAppIcon::OnIconRead(scoped_ptr<ArcAppIcon::ReadResult> read_result) { | |
236 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
237 | |
238 switch (read_result->status) { | |
239 case ReadResult::OK: | |
240 if (!g_disable_decoding) { | |
241 decode_requests_.push_back( | |
242 new DecodeRequest(weak_ptr_factory_.GetWeakPtr(), | |
243 resource_size_in_dip_, | |
244 read_result->scale_factor)); | |
245 ImageDecoder::Start(decode_requests_.back(), | |
246 read_result->unsafe_icon_data); | |
247 } | |
248 break; | |
249 case ReadResult::FAIL: | |
250 break; | |
251 case ReadResult::REQUEST_TO_INSTALL: | |
252 RequestIcon(read_result->scale_factor); | |
253 break; | |
254 default: | |
255 NOTREACHED(); | |
256 } | |
257 } | |
258 | |
259 void ArcAppIcon::Update(const gfx::ImageSkia* image) { | |
260 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
261 CHECK(image && !image->isNull()); | |
262 | |
263 std::vector<gfx::ImageSkiaRep> reps = image->image_reps(); | |
264 for (const auto& image_rep : reps) { | |
265 if (ui::IsSupportedScale(image_rep.scale())) { | |
266 image_skia_.RemoveRepresentation(image_rep.scale()); | |
267 image_skia_.AddRepresentation(image_rep); | |
268 } | |
269 } | |
270 | |
271 image_ = gfx::Image(image_skia_); | |
272 | |
273 observer_->OnIconUpdated(); | |
274 } | |
275 | |
276 void ArcAppIcon::DiscardDecodeRequest(DecodeRequest* request) { | |
277 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
278 | |
279 ScopedVector<DecodeRequest>::iterator it = std::find(decode_requests_.begin(), | |
280 decode_requests_.end(), | |
281 request); | |
282 CHECK(it != decode_requests_.end()); | |
283 decode_requests_.erase(it); | |
284 } | |
OLD | NEW |