Index: chrome/browser/ui/app_list/arc_app_icon.cc |
diff --git a/chrome/browser/ui/app_list/arc_app_icon.cc b/chrome/browser/ui/app_list/arc_app_icon.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6b7659acd7d0d84e1a91a39d2d114d28bc322e41 |
--- /dev/null |
+++ b/chrome/browser/ui/app_list/arc_app_icon.cc |
@@ -0,0 +1,246 @@ |
+// 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/ui/app_list/arc_app_icon.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/bind.h" |
+#include "base/files/file_path.h" |
+#include "base/files/file_util.h" |
+#include "chrome/browser/image_decoder.h" |
+#include "chrome/browser/ui/app_list/arc_app_prefs.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "extensions/grit/extensions_browser_resources.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/geometry/size.h" |
+#include "ui/gfx/image/image_skia_source.h" |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ArcAppIcon::Source |
+ |
+class ArcAppIcon::Source : public gfx::ImageSkiaSource { |
+ public: |
+ explicit Source(const base::WeakPtr<ArcAppIcon>& host); |
+ ~Source() override; |
+ |
+ private: |
+ // gfx::ImageSkiaSource overrides: |
+ gfx::ImageSkiaRep GetImageForScale(float scale) override; |
+ |
+ // Used to load images asynchronously. NULLed out when the ArcAppIcon is |
+ // destroyed. |
+ base::WeakPtr<ArcAppIcon> host_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Source); |
+}; |
+ |
+ArcAppIcon::Source::Source(const base::WeakPtr<ArcAppIcon>& host) |
+ : host_(host) { |
+} |
+ |
+ArcAppIcon::Source::~Source() { |
+} |
+ |
+gfx::ImageSkiaRep ArcAppIcon::Source::GetImageForScale(float scale) { |
+ if (host_) { |
+ host_->LoadForScaleFactor(ui::GetSupportedScaleFactor(scale)); |
+ } |
+ |
+ // Host loads icon asynchronously, so use default icon so far. |
+ const gfx::ImageSkia* default_image = ResourceBundle::GetSharedInstance(). |
+ GetImageSkiaNamed(IDR_APP_DEFAULT_ICON); |
+ CHECK(default_image); |
+ |
+ return default_image->GetRepresentation(scale); |
+} |
+ |
+class ArcAppIcon::DecodeRequest : public ImageDecoder::ImageRequest { |
+ public: |
+ DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, |
+ int dimension, |
+ ui::ScaleFactor scale_factor); |
+ ~DecodeRequest() override; |
+ |
+ // ImageDecoder::ImageRequest |
+ void OnImageDecoded(const SkBitmap& bitmap) override; |
+ void OnDecodeImageFailed() override; |
+ private: |
+ base::WeakPtr<ArcAppIcon> host_; |
+ int dimension_; |
+ ui::ScaleFactor scale_factor_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(DecodeRequest); |
+}; |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ArcAppIcon::DecodeRequest |
+ |
+ArcAppIcon::DecodeRequest::DecodeRequest(const base::WeakPtr<ArcAppIcon>& host, |
+ int dimension, |
+ ui::ScaleFactor scale_factor) |
+ : host_(host), |
+ dimension_(dimension), |
+ scale_factor_(scale_factor) { |
+} |
+ |
+ArcAppIcon::DecodeRequest::~DecodeRequest() { |
+} |
+ |
+void ArcAppIcon::DecodeRequest::OnImageDecoded(const SkBitmap& bitmap) { |
+ DCHECK(!bitmap.isNull() && !bitmap.empty()); |
+ |
+ if (!host_) { |
+ return; |
+ } |
+ |
+ int expected_dim = static_cast<int>( |
+ ui::GetScaleForScaleFactor(scale_factor_) * dimension_ + 0.5f); |
+ if (bitmap.width() != expected_dim || bitmap.height() != expected_dim) { |
+ LOG(ERROR) << "Decoded ARC icon has unexpected dimension " |
+ << bitmap.width() << "x" << bitmap.height() << ". Expected " |
+ << expected_dim << "x" << "."; |
+ return; |
+ } |
+ |
+ gfx::ImageSkia image_skia; |
+ image_skia.AddRepresentation(gfx::ImageSkiaRep( |
+ bitmap, |
+ ui::GetScaleForScaleFactor(scale_factor_))); |
+ |
+ host_->Update(&image_skia); |
+ host_->DiscardDecodeRequest(this); |
+} |
+ |
+void ArcAppIcon::DecodeRequest::OnDecodeImageFailed() { |
+ LOG(ERROR) << "Failed to decode ARC icon."; |
+ |
+ if (!host_) { |
+ return; |
+ } |
+ |
+ host_->DiscardDecodeRequest(this); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// ArcAppIcon |
+ |
+ArcAppIcon::ArcAppIcon(content::BrowserContext* context, |
+ const std::string& app_id, |
+ int resource_size_in_dip, |
+ Observer* observer) |
+ : context_(context), |
+ app_id_(app_id), |
+ resource_size_in_dip_(resource_size_in_dip), |
+ observer_(observer), |
+ weak_ptr_factory_(this) { |
+ CHECK(observer_ != NULL); |
+ source_ = new Source(weak_ptr_factory_.GetWeakPtr()); |
+ gfx::Size resource_size(resource_size_in_dip, resource_size_in_dip); |
+ image_skia_ = gfx::ImageSkia(source_, resource_size); |
+} |
+ |
+ArcAppIcon::~ArcAppIcon() { |
+} |
+ |
+void ArcAppIcon::LoadForScaleFactor(ui::ScaleFactor scale_factor) { |
+ ArcAppPrefs* prefs = ArcAppPrefs::Get(context_); |
+ if (!prefs) { |
+ LOG(ERROR) << "ARC preferences service is not available."; |
+ return; |
+ } |
+ |
+ base::FilePath path = prefs->GetIconPath(app_id_, scale_factor); |
+ if (path.empty()) { |
+ return; |
+ } |
+ |
+ base::Closure task = base::Bind(&ArcAppIcon::ReadOnFileThread, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ scale_factor, |
+ path); |
+ content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE, task); |
+} |
+ |
+void ArcAppIcon::RequestIcon(ui::ScaleFactor scale_factor) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ ArcAppPrefs* prefs = ArcAppPrefs::Get(context_); |
+ if (!prefs) { |
+ LOG(ERROR) << "ARC preferences service is not available."; |
+ return; |
+ } |
+ // ArcAppPrefs notifies ArcAppModelBuilder via Observer when icon is ready and |
+ // ArcAppModelBuilder refreshes the icon of the corresponding item by calling |
+ // LoadScaleFactor. |
+ prefs->RequestIcon(app_id_, scale_factor); |
+} |
+ |
+void ArcAppIcon::ReadOnFileThread(ui::ScaleFactor scale_factor, |
+ const base::FilePath& path) { |
+ DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
+ DCHECK(!path.empty()); |
+ |
+ if (!base::PathExists(path)) { |
+ base::Closure task = base::Bind(&ArcAppIcon::RequestIcon, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ scale_factor); |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, |
+ FROM_HERE, |
+ task); |
+ return; |
+ } |
+ |
+ std::string unsafe_icon_data; |
+ // Read the file from disk. |
+ if (!base::ReadFileToString(path, &unsafe_icon_data)) { |
+ LOG(ERROR) << "Failed to read an ARC icon from file " |
+ << path.MaybeAsASCII(); |
+ return; |
+ } |
+ |
+ base::Closure task = base::Bind(&ArcAppIcon::OnIconRead, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ scale_factor, |
+ unsafe_icon_data); |
+ content::BrowserThread::PostTask(content::BrowserThread::UI, |
+ FROM_HERE, |
+ task); |
+} |
+ |
+void ArcAppIcon::OnIconRead(ui::ScaleFactor scale_factor, |
+ const std::string& unsafe_image_data) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ |
+ decode_requests_.push_back(new DecodeRequest(weak_ptr_factory_.GetWeakPtr(), |
+ resource_size_in_dip_, |
+ scale_factor)); |
+ ImageDecoder::Start(decode_requests_.back(), unsafe_image_data); |
+} |
+ |
+void ArcAppIcon::Update(const gfx::ImageSkia* image) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ CHECK(image && !image->isNull()); |
+ |
+ std::vector<gfx::ImageSkiaRep> reps = image->image_reps(); |
+ for (const auto& image_rep : reps) { |
+ if (ui::IsSupportedScale(image_rep.scale())) { |
+ image_skia_.RemoveRepresentation(image_rep.scale()); |
+ image_skia_.AddRepresentation(image_rep); |
+ } |
+ } |
+ |
+ image_ = gfx::Image(image_skia_); |
+ |
+ observer_->OnIconUpdated(); |
+} |
+ |
+void ArcAppIcon::DiscardDecodeRequest(DecodeRequest* request) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ |
+ ScopedVector<DecodeRequest>::iterator it = std::find(decode_requests_.begin(), |
+ decode_requests_.end(), |
+ request); |
+ CHECK(it != decode_requests_.end()); |
+ decode_requests_.erase(it); |
+} |