Update icon loading API implementation
This commit is contained in:
parent
19b686c90b
commit
977abc6458
9 changed files with 176 additions and 243 deletions
|
@ -890,15 +890,18 @@ void App::GetFileIcon(const base::FilePath& path,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IconManager* icon_manager = IconManager::GetInstance();
|
if (!icon_manager_.get()) {
|
||||||
gfx::Image* icon = icon_manager->LookupIconFromFilepath(normalized_path,
|
icon_manager_.reset(new IconManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::Image* icon = icon_manager_->LookupIconFromFilepath(normalized_path,
|
||||||
icon_size);
|
icon_size);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
callback.Run(v8::Null(isolate()), *icon);
|
callback.Run(v8::Null(isolate()), *icon);
|
||||||
} else {
|
} else {
|
||||||
icon_manager->LoadIcon(normalized_path, icon_size,
|
icon_manager_->LoadIcon(normalized_path, icon_size,
|
||||||
base::Bind(&OnIconDataAvailable, isolate(),
|
base::Bind(&OnIconDataAvailable, isolate(),
|
||||||
callback));
|
callback), &cancelable_task_tracker_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
#include "atom/browser/browser.h"
|
#include "atom/browser/browser.h"
|
||||||
#include "atom/browser/browser_observer.h"
|
#include "atom/browser/browser_observer.h"
|
||||||
#include "atom/common/native_mate_converters/callback.h"
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
#include "chrome/browser/icon_loader.h"
|
#include "base/task/cancelable_task_tracker.h"
|
||||||
|
#include "chrome/browser/icon_manager.h"
|
||||||
#include "chrome/browser/process_singleton.h"
|
#include "chrome/browser/process_singleton.h"
|
||||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||||
#include "native_mate/handle.h"
|
#include "native_mate/handle.h"
|
||||||
|
@ -129,6 +130,8 @@ class App : public AtomBrowserClient::Delegate,
|
||||||
void DisableHardwareAcceleration(mate::Arguments* args);
|
void DisableHardwareAcceleration(mate::Arguments* args);
|
||||||
bool IsAccessibilitySupportEnabled();
|
bool IsAccessibilitySupportEnabled();
|
||||||
Browser::LoginItemSettings GetLoginItemSettings(mate::Arguments* args);
|
Browser::LoginItemSettings GetLoginItemSettings(mate::Arguments* args);
|
||||||
|
base::CancelableTaskTracker cancelable_task_tracker_;
|
||||||
|
std::unique_ptr<IconManager> icon_manager_;
|
||||||
#if defined(USE_NSS_CERTS)
|
#if defined(USE_NSS_CERTS)
|
||||||
void ImportCertificate(const base::DictionaryValue& options,
|
void ImportCertificate(const base::DictionaryValue& options,
|
||||||
const net::CompletionCallback& callback);
|
const net::CompletionCallback& callback);
|
||||||
|
|
|
@ -3,46 +3,40 @@
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
#include "chrome/browser/icon_loader.h"
|
#include "chrome/browser/icon_loader.h"
|
||||||
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/threading/thread_task_runner_handle.h"
|
#include "base/threading/thread_task_runner_handle.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
|
|
||||||
using content::BrowserThread;
|
using content::BrowserThread;
|
||||||
|
|
||||||
IconLoader::IconLoader(const base::FilePath& file_path,
|
// static
|
||||||
IconSize size,
|
IconLoader* IconLoader::Create(const base::FilePath& file_path,
|
||||||
Delegate* delegate)
|
IconSize size,
|
||||||
: target_task_runner_(NULL),
|
IconLoadedCallback callback) {
|
||||||
file_path_(file_path),
|
return new IconLoader(file_path, size, callback);
|
||||||
icon_size_(size),
|
}
|
||||||
delegate_(delegate) {}
|
|
||||||
|
|
||||||
IconLoader::~IconLoader() {}
|
|
||||||
|
|
||||||
void IconLoader::Start() {
|
void IconLoader::Start() {
|
||||||
target_task_runner_ = base::ThreadTaskRunnerHandle::Get();
|
target_task_runner_ = base::ThreadTaskRunnerHandle::Get();
|
||||||
|
BrowserThread::PostTaskAndReply(
|
||||||
BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
|
BrowserThread::FILE, FROM_HERE,
|
||||||
base::Bind(&IconLoader::ReadGroup, this),
|
base::Bind(&IconLoader::ReadGroup, base::Unretained(this)),
|
||||||
base::Bind(&IconLoader::OnReadGroup, this));
|
base::Bind(&IconLoader::OnReadGroup, base::Unretained(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconLoader::IconLoader(const base::FilePath& file_path,
|
||||||
|
IconSize size,
|
||||||
|
IconLoadedCallback callback)
|
||||||
|
: file_path_(file_path), icon_size_(size), callback_(callback) {}
|
||||||
|
|
||||||
|
IconLoader::~IconLoader() {}
|
||||||
|
|
||||||
void IconLoader::ReadGroup() {
|
void IconLoader::ReadGroup() {
|
||||||
group_ = ReadGroupIDFromFilepath(file_path_);
|
group_ = GroupForFilepath(file_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconLoader::OnReadGroup() {
|
void IconLoader::OnReadGroup() {
|
||||||
if (IsIconMutableFromFilepath(file_path_) ||
|
BrowserThread::PostTask(
|
||||||
!delegate_->OnGroupLoaded(this, group_)) {
|
ReadIconThreadID(), FROM_HERE,
|
||||||
BrowserThread::PostTask(ReadIconThreadID(), FROM_HERE,
|
base::Bind(&IconLoader::ReadIcon, base::Unretained(this)));
|
||||||
base::Bind(&IconLoader::ReadIcon, this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IconLoader::NotifyDelegate() {
|
|
||||||
// If the delegate takes ownership of the Image, release it from the scoped
|
|
||||||
// pointer.
|
|
||||||
if (delegate_->OnImageLoaded(this, image_.get(), group_))
|
|
||||||
ignore_result(image_.release()); // Can't ignore return value.
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,31 +8,30 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/callback.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory/ref_counted.h"
|
|
||||||
#include "base/single_thread_task_runner.h"
|
#include "base/single_thread_task_runner.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "content/public/browser/browser_thread.h"
|
#include "content/public/browser/browser_thread.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
|
||||||
// On Windows, we group files by their extension, with several exceptions:
|
|
||||||
// .dll, .exe, .ico. See IconManager.h for explanation.
|
|
||||||
typedef std::wstring IconGroupID;
|
|
||||||
#elif defined(OS_POSIX)
|
|
||||||
// On POSIX, we group files by MIME type.
|
|
||||||
typedef std::string IconGroupID;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// A facility to read a file containing an icon asynchronously in the IO
|
// A facility to read a file containing an icon asynchronously in the IO
|
||||||
// thread. Returns the icon in the form of an ImageSkia.
|
// thread. Returns the icon in the form of an ImageSkia.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
class IconLoader : public base::RefCountedThreadSafe<IconLoader> {
|
class IconLoader {
|
||||||
public:
|
public:
|
||||||
|
// An IconGroup is a class of files that all share the same icon. For all
|
||||||
|
// platforms but Windows, and for most files on Windows, it is the file type
|
||||||
|
// (e.g. all .mp3 files share an icon, all .html files share an icon). On
|
||||||
|
// Windows, for certain file types (.exe, .dll, etc), each file of that type
|
||||||
|
// is assumed to have a unique icon. In that case, each of those files is a
|
||||||
|
// group to itself.
|
||||||
|
using IconGroup = base::FilePath::StringType;
|
||||||
|
|
||||||
enum IconSize {
|
enum IconSize {
|
||||||
SMALL = 0, // 16x16
|
SMALL = 0, // 16x16
|
||||||
NORMAL, // 32x32
|
NORMAL, // 32x32
|
||||||
|
@ -40,42 +39,32 @@ class IconLoader : public base::RefCountedThreadSafe<IconLoader> {
|
||||||
ALL, // All sizes available
|
ALL, // All sizes available
|
||||||
};
|
};
|
||||||
|
|
||||||
class Delegate {
|
// The callback invoked when an icon has been read. The parameters are:
|
||||||
public:
|
// - The icon that was loaded, or null if there was a failure to load it.
|
||||||
// Invoked when an icon group has been read, but before the icon data
|
// - The determined group from the original requested path.
|
||||||
// is read. If the icon is already cached, this method should call and
|
using IconLoadedCallback =
|
||||||
// return the results of OnImageLoaded with the cached image.
|
base::Callback<void(std::unique_ptr<gfx::Image>, const IconGroup&)>;
|
||||||
virtual bool OnGroupLoaded(IconLoader* source,
|
|
||||||
const IconGroupID& group) = 0;
|
|
||||||
// Invoked when an icon has been read. |source| is the IconLoader. If the
|
|
||||||
// icon has been successfully loaded, result is non-null. This method must
|
|
||||||
// return true if it is taking ownership of the returned image.
|
|
||||||
virtual bool OnImageLoaded(IconLoader* source,
|
|
||||||
gfx::Image* result,
|
|
||||||
const IconGroupID& group) = 0;
|
|
||||||
|
|
||||||
protected:
|
// Creates an IconLoader, which owns itself. If the IconLoader might outlive
|
||||||
virtual ~Delegate() {}
|
// the caller, be sure to use a weak pointer in the |callback|.
|
||||||
};
|
static IconLoader* Create(const base::FilePath& file_path,
|
||||||
|
IconSize size,
|
||||||
|
IconLoadedCallback callback);
|
||||||
|
|
||||||
IconLoader(const base::FilePath& file_path,
|
// Starts the process of reading the icon. When the reading of the icon is
|
||||||
IconSize size,
|
// complete, the IconLoadedCallback callback will be fulfilled, and the
|
||||||
Delegate* delegate);
|
// IconLoader will delete itself.
|
||||||
|
|
||||||
// Start reading the icon on the file thread.
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class base::RefCountedThreadSafe<IconLoader>;
|
IconLoader(const base::FilePath& file_path,
|
||||||
|
IconSize size,
|
||||||
|
IconLoadedCallback callback);
|
||||||
|
|
||||||
virtual ~IconLoader();
|
~IconLoader();
|
||||||
|
|
||||||
// Get the identifying string for the given file. The implementation
|
// Given a file path, get the group for the given file.
|
||||||
// is in icon_loader_[platform].cc.
|
static IconGroup GroupForFilepath(const base::FilePath& file_path);
|
||||||
static IconGroupID ReadGroupIDFromFilepath(const base::FilePath& path);
|
|
||||||
|
|
||||||
// Some icons (exe's on windows) can change as they're loaded.
|
|
||||||
static bool IsIconMutableFromFilepath(const base::FilePath& path);
|
|
||||||
|
|
||||||
// The thread ReadIcon() should be called on.
|
// The thread ReadIcon() should be called on.
|
||||||
static content::BrowserThread::ID ReadIconThreadID();
|
static content::BrowserThread::ID ReadIconThreadID();
|
||||||
|
@ -84,20 +73,18 @@ class IconLoader : public base::RefCountedThreadSafe<IconLoader> {
|
||||||
void OnReadGroup();
|
void OnReadGroup();
|
||||||
void ReadIcon();
|
void ReadIcon();
|
||||||
|
|
||||||
void NotifyDelegate();
|
|
||||||
|
|
||||||
// The task runner object of the thread in which we notify the delegate.
|
// The task runner object of the thread in which we notify the delegate.
|
||||||
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
|
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
|
||||||
|
|
||||||
base::FilePath file_path_;
|
base::FilePath file_path_;
|
||||||
|
|
||||||
IconGroupID group_;
|
IconGroup group_;
|
||||||
|
|
||||||
IconSize icon_size_;
|
IconSize icon_size_;
|
||||||
|
|
||||||
std::unique_ptr<gfx::Image> image_;
|
std::unique_ptr<gfx::Image> image_;
|
||||||
|
|
||||||
Delegate* delegate_;
|
IconLoadedCallback callback_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(IconLoader);
|
DISALLOW_COPY_AND_ASSIGN(IconLoader);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,14 +10,9 @@
|
||||||
#include "ui/views/linux_ui/linux_ui.h"
|
#include "ui/views/linux_ui/linux_ui.h"
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
IconLoader::IconGroup IconLoader::GroupForFilepath(
|
||||||
const base::FilePath& filepath) {
|
const base::FilePath& file_path) {
|
||||||
return base::nix::GetFileMimeType(filepath);
|
return base::nix::GetFileMimeType(file_path);
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -50,6 +45,7 @@ void IconLoader::ReadIcon() {
|
||||||
image_.reset(new gfx::Image(image));
|
image_.reset(new gfx::Image(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
target_task_runner_->PostTask(FROM_HERE,
|
target_task_runner_->PostTask(
|
||||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
FROM_HERE, base::Bind(callback_, base::Passed(&image_), group_));
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,9 @@
|
||||||
#include "ui/gfx/image/image_skia_util_mac.h"
|
#include "ui/gfx/image/image_skia_util_mac.h"
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
IconLoader::IconGroup IconLoader::GroupForFilepath(
|
||||||
const base::FilePath& filepath) {
|
const base::FilePath& file_path) {
|
||||||
return filepath.Extension();
|
return file_path.Extension();
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -57,6 +52,7 @@ void IconLoader::ReadIcon() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target_task_runner_->PostTask(FROM_HERE,
|
target_task_runner_->PostTask(
|
||||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
FROM_HERE, base::Bind(callback_, base::Passed(&image_), group_));
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,18 +17,15 @@
|
||||||
#include "ui/gfx/image/image_skia.h"
|
#include "ui/gfx/image/image_skia.h"
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
IconLoader::IconGroup IconLoader::GroupForFilepath(
|
||||||
const base::FilePath& filepath) {
|
const base::FilePath& file_path) {
|
||||||
if (!IsIconMutableFromFilepath(filepath))
|
if (file_path.MatchesExtension(L".exe") ||
|
||||||
return filepath.Extension();
|
file_path.MatchesExtension(L".dll") ||
|
||||||
return filepath.value();
|
file_path.MatchesExtension(L".ico")) {
|
||||||
}
|
return file_path.value();
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
return file_path.Extension();
|
||||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath& filepath) {
|
|
||||||
return filepath.MatchesExtension(L".exe") ||
|
|
||||||
filepath.MatchesExtension(L".dll") ||
|
|
||||||
filepath.MatchesExtension(L".ico");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
@ -54,22 +51,22 @@ void IconLoader::ReadIcon() {
|
||||||
|
|
||||||
image_.reset();
|
image_.reset();
|
||||||
|
|
||||||
SHFILEINFO file_info = {0};
|
SHFILEINFO file_info = { 0 };
|
||||||
if (SHGetFileInfo(group_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
|
if (SHGetFileInfo(group_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
|
||||||
sizeof(SHFILEINFO),
|
sizeof(SHFILEINFO),
|
||||||
SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
|
SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
|
||||||
std::unique_ptr<SkBitmap> bitmap(
|
std::unique_ptr<SkBitmap> bitmap(
|
||||||
IconUtil::CreateSkBitmapFromHICON(file_info.hIcon));
|
IconUtil::CreateSkBitmapFromHICON(file_info.hIcon));
|
||||||
if (bitmap.get()) {
|
if (bitmap.get()) {
|
||||||
gfx::ImageSkia image_skia(
|
gfx::ImageSkia image_skia(gfx::ImageSkiaRep(*bitmap,
|
||||||
gfx::ImageSkiaRep(*bitmap, display::win::GetDPIScale()));
|
display::win::GetDPIScale()));
|
||||||
image_skia.MakeThreadSafe();
|
image_skia.MakeThreadSafe();
|
||||||
image_.reset(new gfx::Image(image_skia));
|
image_.reset(new gfx::Image(image_skia));
|
||||||
DestroyIcon(file_info.hIcon);
|
DestroyIcon(file_info.hIcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always notify the delegate, regardless of success.
|
target_task_runner_->PostTask(
|
||||||
target_task_runner_->PostTask(FROM_HERE,
|
FROM_HERE, base::Bind(callback_, base::Passed(&image_), group_));
|
||||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,121 +8,86 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/stl_util.h"
|
|
||||||
#include "base/task_runner.h"
|
#include "base/task_runner.h"
|
||||||
#include "third_party/skia/include/core/SkBitmap.h"
|
#include "third_party/skia/include/core/SkBitmap.h"
|
||||||
#include "third_party/skia/include/core/SkCanvas.h"
|
#include "third_party/skia/include/core/SkCanvas.h"
|
||||||
|
|
||||||
struct IconManager::ClientRequest {
|
namespace {
|
||||||
IconRequestCallback callback;
|
|
||||||
base::FilePath file_path;
|
|
||||||
IconLoader::IconSize size;
|
|
||||||
};
|
|
||||||
|
|
||||||
// static
|
void RunCallbackIfNotCanceled(
|
||||||
IconManager* IconManager::GetInstance() {
|
const base::CancelableTaskTracker::IsCanceledCallback& is_canceled,
|
||||||
return base::Singleton<IconManager>::get();
|
const IconManager::IconRequestCallback& callback,
|
||||||
|
gfx::Image* image) {
|
||||||
|
if (is_canceled.Run())
|
||||||
|
return;
|
||||||
|
callback.Run(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
IconManager::IconManager() {}
|
} // namespace
|
||||||
|
|
||||||
|
IconManager::IconManager() : weak_factory_(this) {}
|
||||||
|
|
||||||
IconManager::~IconManager() {
|
IconManager::~IconManager() {
|
||||||
base::STLDeleteValues(&icon_cache_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Image* IconManager::LookupIconFromFilepath(const base::FilePath& file_name,
|
gfx::Image* IconManager::LookupIconFromFilepath(const base::FilePath& file_path,
|
||||||
IconLoader::IconSize size) {
|
IconLoader::IconSize size) {
|
||||||
GroupMap::iterator it = group_cache_.find(file_name);
|
auto group_it = group_cache_.find(file_path);
|
||||||
if (it != group_cache_.end())
|
if (group_it == group_cache_.end())
|
||||||
return LookupIconFromGroup(it->second, size);
|
return nullptr;
|
||||||
|
|
||||||
return NULL;
|
CacheKey key(group_it->second, size);
|
||||||
|
auto icon_it = icon_cache_.find(key);
|
||||||
|
if (icon_it == icon_cache_.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return icon_it->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Image* IconManager::LookupIconFromGroup(const IconGroupID& group,
|
base::CancelableTaskTracker::TaskId IconManager::LoadIcon(
|
||||||
IconLoader::IconSize size) {
|
const base::FilePath& file_path,
|
||||||
IconMap::iterator it = icon_cache_.find(CacheKey(group, size));
|
IconLoader::IconSize size,
|
||||||
if (it != icon_cache_.end())
|
const IconRequestCallback& callback,
|
||||||
return it->second;
|
base::CancelableTaskTracker* tracker) {
|
||||||
|
base::CancelableTaskTracker::IsCanceledCallback is_canceled;
|
||||||
|
base::CancelableTaskTracker::TaskId id =
|
||||||
|
tracker->NewTrackedTaskId(&is_canceled);
|
||||||
|
IconRequestCallback callback_runner = base::Bind(
|
||||||
|
&RunCallbackIfNotCanceled, is_canceled, callback);
|
||||||
|
|
||||||
return nullptr;
|
IconLoader* loader = IconLoader::Create(
|
||||||
}
|
file_path, size,
|
||||||
|
base::Bind(&IconManager::OnIconLoaded, weak_factory_.GetWeakPtr(),
|
||||||
void IconManager::LoadIcon(const base::FilePath& file_name,
|
callback_runner, file_path, size));
|
||||||
IconLoader::IconSize size,
|
|
||||||
const IconRequestCallback& callback) {
|
|
||||||
IconLoader* loader = new IconLoader(file_name, size, this);
|
|
||||||
loader->AddRef();
|
|
||||||
loader->Start();
|
loader->Start();
|
||||||
|
|
||||||
ClientRequest client_request = {callback, file_name, size};
|
return id;
|
||||||
requests_[loader] = client_request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IconLoader::Delegate implementation -----------------------------------------
|
void IconManager::OnIconLoaded(IconRequestCallback callback,
|
||||||
|
base::FilePath file_path,
|
||||||
bool IconManager::OnGroupLoaded(IconLoader* loader, const IconGroupID& group) {
|
IconLoader::IconSize size,
|
||||||
ClientRequests::iterator rit = requests_.find(loader);
|
std::unique_ptr<gfx::Image> result,
|
||||||
if (rit == requests_.end()) {
|
const IconLoader::IconGroup& group) {
|
||||||
NOTREACHED();
|
// Cache the bitmap. Watch out: |result| may be null, which indicates a
|
||||||
return false;
|
// failure. We assume that if we have an entry in |icon_cache_| it must not be
|
||||||
|
// null.
|
||||||
|
CacheKey key(group, size);
|
||||||
|
if (result) {
|
||||||
|
callback.Run(result.get());
|
||||||
|
icon_cache_[key] = std::move(result);
|
||||||
|
} else {
|
||||||
|
callback.Run(nullptr);
|
||||||
|
icon_cache_.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Image* result = LookupIconFromGroup(group, rit->second.size);
|
group_cache_[file_path] = group;
|
||||||
if (!result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OnImageLoaded(loader, result, group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconManager::OnImageLoaded(IconLoader* loader,
|
IconManager::CacheKey::CacheKey(const IconLoader::IconGroup& group,
|
||||||
gfx::Image* result,
|
|
||||||
const IconGroupID& group) {
|
|
||||||
ClientRequests::iterator rit = requests_.find(loader);
|
|
||||||
|
|
||||||
// Balances the AddRef() in LoadIcon().
|
|
||||||
loader->Release();
|
|
||||||
|
|
||||||
// Look up our client state.
|
|
||||||
if (rit == requests_.end()) {
|
|
||||||
NOTREACHED();
|
|
||||||
return false; // Return false to indicate result should be deleted.
|
|
||||||
}
|
|
||||||
|
|
||||||
const ClientRequest& client_request = rit->second;
|
|
||||||
|
|
||||||
// Cache the bitmap. Watch out: |result| may be NULL to indicate a current
|
|
||||||
// failure. We assume that if we have an entry in |icon_cache_|
|
|
||||||
// it must not be NULL.
|
|
||||||
CacheKey key(group, client_request.size);
|
|
||||||
IconMap::iterator it = icon_cache_.find(key);
|
|
||||||
if (it != icon_cache_.end()) {
|
|
||||||
if (!result) {
|
|
||||||
delete it->second;
|
|
||||||
icon_cache_.erase(it);
|
|
||||||
} else if (result != it->second) {
|
|
||||||
it->second->SwapRepresentations(result);
|
|
||||||
delete result;
|
|
||||||
result = it->second;
|
|
||||||
}
|
|
||||||
} else if (result) {
|
|
||||||
icon_cache_[key] = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
group_cache_[client_request.file_path] = group;
|
|
||||||
|
|
||||||
// Inform our client that the request has completed.
|
|
||||||
client_request.callback.Run(result);
|
|
||||||
requests_.erase(rit);
|
|
||||||
|
|
||||||
return true; // Indicates we took ownership of result.
|
|
||||||
}
|
|
||||||
|
|
||||||
IconManager::CacheKey::CacheKey(const IconGroupID& group,
|
|
||||||
IconLoader::IconSize size)
|
IconLoader::IconSize size)
|
||||||
: group(group), size(size) {}
|
: group(group), size(size) {}
|
||||||
|
|
||||||
bool IconManager::CacheKey::operator<(const CacheKey& other) const {
|
bool IconManager::CacheKey::operator<(const CacheKey &other) const {
|
||||||
return std::tie(group, size) < std::tie(other.group, other.size);
|
return std::tie(group, size) < std::tie(other.group, other.size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
// 2. An asynchronous icon load from a file on the file thread:
|
// 2. An asynchronous icon load from a file on the file thread:
|
||||||
// IconManager::LoadIcon()
|
// IconManager::LoadIcon()
|
||||||
//
|
//
|
||||||
// When using the second (asychronous) method, callers must supply a callback
|
// When using the second (asynchronous) method, callers must supply a callback
|
||||||
// which will be run once the icon has been extracted. The icon manager will
|
// which will be run once the icon has been extracted. The icon manager will
|
||||||
// cache the results of the icon extraction so that subsequent lookups will be
|
// cache the results of the icon extraction so that subsequent lookups will be
|
||||||
// fast.
|
// fast.
|
||||||
|
@ -46,25 +46,29 @@
|
||||||
#define CHROME_BROWSER_ICON_MANAGER_H_
|
#define CHROME_BROWSER_ICON_MANAGER_H_
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "base/memory/singleton.h"
|
#include "base/memory/weak_ptr.h"
|
||||||
|
#include "base/task/cancelable_task_tracker.h"
|
||||||
#include "chrome/browser/icon_loader.h"
|
#include "chrome/browser/icon_loader.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
|
|
||||||
class IconManager : public IconLoader::Delegate {
|
class IconManager {
|
||||||
public:
|
public:
|
||||||
static IconManager* GetInstance();
|
IconManager();
|
||||||
|
~IconManager();
|
||||||
|
|
||||||
// Synchronous call to examine the internal caches for the icon. Returns the
|
// Synchronous call to examine the internal caches for the icon. Returns the
|
||||||
// icon if we have already loaded it, NULL if we don't have it and must load
|
// icon if we have already loaded it, or null if we don't have it and must
|
||||||
// it via 'LoadIcon'. The returned bitmap is owned by the IconManager and must
|
// load it via LoadIcon(). The returned bitmap is owned by the IconManager and
|
||||||
// not be free'd by the caller. If the caller needs to modify the icon, it
|
// must not be free'd by the caller. If the caller needs to modify the icon,
|
||||||
// must make a copy and modify the copy.
|
// it must make a copy and modify the copy.
|
||||||
gfx::Image* LookupIconFromFilepath(const base::FilePath& file_name,
|
gfx::Image* LookupIconFromFilepath(const base::FilePath& file_path,
|
||||||
IconLoader::IconSize size);
|
IconLoader::IconSize size);
|
||||||
|
|
||||||
typedef base::Callback<void(gfx::Image*)> IconRequestCallback;
|
using IconRequestCallback = base::Callback<void(gfx::Image*)>;
|
||||||
|
|
||||||
// Asynchronous call to lookup and return the icon associated with file. The
|
// Asynchronous call to lookup and return the icon associated with file. The
|
||||||
// work is done on the file thread, with the callbacks running on the thread
|
// work is done on the file thread, with the callbacks running on the thread
|
||||||
|
@ -74,47 +78,35 @@ class IconManager : public IconLoader::Delegate {
|
||||||
// 1. This does *not* check the cache.
|
// 1. This does *not* check the cache.
|
||||||
// 2. The returned bitmap pointer is *not* owned by callback. So callback
|
// 2. The returned bitmap pointer is *not* owned by callback. So callback
|
||||||
// should never keep it or delete it.
|
// should never keep it or delete it.
|
||||||
// 3. The gfx::Image pointer passed to the callback may be NULL if decoding
|
// 3. The gfx::Image pointer passed to the callback will be null if decoding
|
||||||
// failed.
|
// failed.
|
||||||
void LoadIcon(const base::FilePath& file_name,
|
base::CancelableTaskTracker::TaskId LoadIcon(
|
||||||
IconLoader::IconSize size,
|
const base::FilePath& file_name,
|
||||||
const IconRequestCallback& callback);
|
IconLoader::IconSize size,
|
||||||
|
const IconRequestCallback& callback,
|
||||||
// IconLoader::Delegate interface.
|
base::CancelableTaskTracker* tracker);
|
||||||
bool OnGroupLoaded(IconLoader* loader, const IconGroupID& group) override;
|
|
||||||
bool OnImageLoaded(IconLoader* loader,
|
|
||||||
gfx::Image* result,
|
|
||||||
const IconGroupID& group) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct base::DefaultSingletonTraits<IconManager>;
|
void OnIconLoaded(IconRequestCallback callback,
|
||||||
|
base::FilePath file_path,
|
||||||
IconManager();
|
IconLoader::IconSize size,
|
||||||
~IconManager() override;
|
std::unique_ptr<gfx::Image> result,
|
||||||
|
const IconLoader::IconGroup& group);
|
||||||
|
|
||||||
struct CacheKey {
|
struct CacheKey {
|
||||||
CacheKey(const IconGroupID& group, IconLoader::IconSize size);
|
CacheKey(const IconLoader::IconGroup& group, IconLoader::IconSize size);
|
||||||
|
|
||||||
// Used as a key in the map below, so we need this comparator.
|
// Used as a key in the map below, so we need this comparator.
|
||||||
bool operator<(const CacheKey& other) const;
|
bool operator<(const CacheKey &other) const;
|
||||||
|
|
||||||
IconGroupID group;
|
IconLoader::IconGroup group;
|
||||||
IconLoader::IconSize size;
|
IconLoader::IconSize size;
|
||||||
};
|
};
|
||||||
|
|
||||||
gfx::Image* LookupIconFromGroup(const IconGroupID& group,
|
std::map<base::FilePath, IconLoader::IconGroup> group_cache_;
|
||||||
IconLoader::IconSize size);
|
std::map<CacheKey, std::unique_ptr<gfx::Image>> icon_cache_;
|
||||||
|
|
||||||
typedef std::map<CacheKey, gfx::Image*> IconMap;
|
base::WeakPtrFactory<IconManager> weak_factory_;
|
||||||
IconMap icon_cache_;
|
|
||||||
|
|
||||||
typedef std::map<base::FilePath, IconGroupID> GroupMap;
|
|
||||||
GroupMap group_cache_;
|
|
||||||
|
|
||||||
// Asynchronous requests that have not yet been completed.
|
|
||||||
struct ClientRequest;
|
|
||||||
typedef std::map<IconLoader*, ClientRequest> ClientRequests;
|
|
||||||
ClientRequests requests_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(IconManager);
|
DISALLOW_COPY_AND_ASSIGN(IconManager);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue