Merge pull request #7851 from YurySolovyov/image-from-icon
Add an API to fetch file icon
This commit is contained in:
commit
4630f4488e
13 changed files with 758 additions and 1 deletions
|
@ -30,6 +30,7 @@
|
|||
#include "base/path_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "brightray/browser/brightray_paths.h"
|
||||
#include "chrome/browser/icon_manager.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
|
@ -335,6 +336,15 @@ namespace api {
|
|||
|
||||
namespace {
|
||||
|
||||
IconLoader::IconSize GetIconSizeByString(const std::string& size) {
|
||||
if (size == "small") {
|
||||
return IconLoader::IconSize::SMALL;
|
||||
} else if (size == "large") {
|
||||
return IconLoader::IconSize::LARGE;
|
||||
}
|
||||
return IconLoader::IconSize::NORMAL;
|
||||
}
|
||||
|
||||
// Return the path constant from string.
|
||||
int GetPathConstant(const std::string& name) {
|
||||
if (name == "appData")
|
||||
|
@ -462,6 +472,21 @@ int ImportIntoCertStore(
|
|||
}
|
||||
#endif
|
||||
|
||||
void OnIconDataAvailable(v8::Isolate* isolate,
|
||||
const App::FileIconCallback& callback,
|
||||
gfx::Image* icon) {
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
if (icon && !icon->IsEmpty()) {
|
||||
callback.Run(v8::Null(isolate), *icon);
|
||||
} else {
|
||||
v8::Local<v8::String> error_message =
|
||||
v8::String::NewFromUtf8(isolate, "Failed to get file icon.");
|
||||
callback.Run(v8::Exception::Error(error_message), gfx::Image());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
App::App(v8::Isolate* isolate) {
|
||||
|
@ -841,6 +866,42 @@ JumpListResult App::SetJumpList(v8::Local<v8::Value> val,
|
|||
}
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
void App::GetFileIcon(const base::FilePath& path,
|
||||
mate::Arguments* args) {
|
||||
mate::Dictionary options;
|
||||
IconLoader::IconSize icon_size;
|
||||
FileIconCallback callback;
|
||||
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
base::FilePath normalized_path = path.NormalizePathSeparators();
|
||||
|
||||
if (!args->GetNext(&options)) {
|
||||
icon_size = IconLoader::IconSize::NORMAL;
|
||||
} else {
|
||||
std::string icon_size_string;
|
||||
options.Get("size", &icon_size_string);
|
||||
icon_size = GetIconSizeByString(icon_size_string);
|
||||
}
|
||||
|
||||
if (!args->GetNext(&callback)) {
|
||||
args->ThrowError("Missing required callback function");
|
||||
return;
|
||||
}
|
||||
|
||||
IconManager* icon_manager = IconManager::GetInstance();
|
||||
gfx::Image* icon = icon_manager->LookupIconFromFilepath(normalized_path,
|
||||
icon_size);
|
||||
if (icon) {
|
||||
callback.Run(v8::Null(isolate()), *icon);
|
||||
} else {
|
||||
icon_manager->LoadIcon(normalized_path, icon_size,
|
||||
base::Bind(&OnIconDataAvailable, isolate(),
|
||||
callback));
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<App> App::Create(v8::Isolate* isolate) {
|
||||
return mate::CreateHandle(isolate, new App(isolate));
|
||||
|
@ -909,7 +970,8 @@ void App::BuildPrototype(
|
|||
.SetMethod("isAccessibilitySupportEnabled",
|
||||
&App::IsAccessibilitySupportEnabled)
|
||||
.SetMethod("disableHardwareAcceleration",
|
||||
&App::DisableHardwareAcceleration);
|
||||
&App::DisableHardwareAcceleration)
|
||||
.SetMethod("getFileIcon", &App::GetFileIcon);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "chrome/browser/icon_loader.h"
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
@ -43,6 +44,9 @@ class App : public AtomBrowserClient::Delegate,
|
|||
public BrowserObserver,
|
||||
public content::GpuDataManagerObserver {
|
||||
public:
|
||||
using FileIconCallback = base::Callback<void(v8::Local<v8::Value>,
|
||||
const gfx::Image&)>;
|
||||
|
||||
static mate::Handle<App> Create(v8::Isolate* isolate);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
|
@ -129,6 +133,8 @@ class App : public AtomBrowserClient::Delegate,
|
|||
void ImportCertificate(const base::DictionaryValue& options,
|
||||
const net::CompletionCallback& callback);
|
||||
#endif
|
||||
void GetFileIcon(const base::FilePath& path,
|
||||
mate::Arguments* args);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Get the current Jump List settings.
|
||||
|
|
48
chromium_src/chrome/browser/icon_loader.cc
Normal file
48
chromium_src/chrome/browser/icon_loader.cc
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2012 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/icon_loader.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
IconLoader::IconLoader(const base::FilePath& file_path,
|
||||
IconSize size,
|
||||
Delegate* delegate)
|
||||
: target_task_runner_(NULL),
|
||||
file_path_(file_path),
|
||||
icon_size_(size),
|
||||
delegate_(delegate) {}
|
||||
|
||||
IconLoader::~IconLoader() {}
|
||||
|
||||
void IconLoader::Start() {
|
||||
target_task_runner_ = base::ThreadTaskRunnerHandle::Get();
|
||||
|
||||
BrowserThread::PostTaskAndReply(BrowserThread::FILE, FROM_HERE,
|
||||
base::Bind(&IconLoader::ReadGroup, this),
|
||||
base::Bind(&IconLoader::OnReadGroup, this));
|
||||
}
|
||||
|
||||
void IconLoader::ReadGroup() {
|
||||
group_ = ReadGroupIDFromFilepath(file_path_);
|
||||
}
|
||||
|
||||
void IconLoader::OnReadGroup() {
|
||||
if (IsIconMutableFromFilepath(file_path_) ||
|
||||
!delegate_->OnGroupLoaded(this, group_)) {
|
||||
BrowserThread::PostTask(ReadIconThreadID(), FROM_HERE,
|
||||
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.
|
||||
}
|
105
chromium_src/chrome/browser/icon_loader.h
Normal file
105
chromium_src/chrome/browser/icon_loader.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef CHROME_BROWSER_ICON_LOADER_H_
|
||||
#define CHROME_BROWSER_ICON_LOADER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/public/browser/browser_thread.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
|
||||
// thread. Returns the icon in the form of an ImageSkia.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class IconLoader : public base::RefCountedThreadSafe<IconLoader> {
|
||||
public:
|
||||
enum IconSize {
|
||||
SMALL = 0, // 16x16
|
||||
NORMAL, // 32x32
|
||||
LARGE, // Windows: 32x32, Linux: 48x48, Mac: Unsupported
|
||||
ALL, // All sizes available
|
||||
};
|
||||
|
||||
class Delegate {
|
||||
public:
|
||||
// Invoked when an icon group has been read, but before the icon data
|
||||
// is read. If the icon is already cached, this method should call and
|
||||
// return the results of OnImageLoaded with the cached image.
|
||||
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:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
|
||||
IconLoader(const base::FilePath& file_path,
|
||||
IconSize size,
|
||||
Delegate* delegate);
|
||||
|
||||
// Start reading the icon on the file thread.
|
||||
void Start();
|
||||
|
||||
private:
|
||||
friend class base::RefCountedThreadSafe<IconLoader>;
|
||||
|
||||
virtual ~IconLoader();
|
||||
|
||||
// Get the identifying string for the given file. The implementation
|
||||
// is in icon_loader_[platform].cc.
|
||||
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.
|
||||
static content::BrowserThread::ID ReadIconThreadID();
|
||||
|
||||
void ReadGroup();
|
||||
void OnReadGroup();
|
||||
void ReadIcon();
|
||||
|
||||
void NotifyDelegate();
|
||||
|
||||
// The task runner object of the thread in which we notify the delegate.
|
||||
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner_;
|
||||
|
||||
base::FilePath file_path_;
|
||||
|
||||
IconGroupID group_;
|
||||
|
||||
IconSize icon_size_;
|
||||
|
||||
std::unique_ptr<gfx::Image> image_;
|
||||
|
||||
Delegate* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IconLoader);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_ICON_LOADER_H_
|
55
chromium_src/chrome/browser/icon_loader_auralinux.cc
Normal file
55
chromium_src/chrome/browser/icon_loader_auralinux.cc
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2013 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/icon_loader.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/nix/mime_util_xdg.h"
|
||||
#include "ui/views/linux_ui/linux_ui.h"
|
||||
|
||||
// static
|
||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
||||
const base::FilePath& filepath) {
|
||||
return base::nix::GetFileMimeType(filepath);
|
||||
}
|
||||
|
||||
// static
|
||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
content::BrowserThread::ID IconLoader::ReadIconThreadID() {
|
||||
// ReadIcon() calls into views::LinuxUI and GTK2 code, so it must be on the UI
|
||||
// thread.
|
||||
return content::BrowserThread::UI;
|
||||
}
|
||||
|
||||
void IconLoader::ReadIcon() {
|
||||
int size_pixels = 0;
|
||||
switch (icon_size_) {
|
||||
case IconLoader::SMALL:
|
||||
size_pixels = 16;
|
||||
break;
|
||||
case IconLoader::NORMAL:
|
||||
size_pixels = 32;
|
||||
break;
|
||||
case IconLoader::LARGE:
|
||||
size_pixels = 48;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
views::LinuxUI* ui = views::LinuxUI::instance();
|
||||
if (ui) {
|
||||
gfx::Image image = ui->GetIconForContentType(group_, size_pixels);
|
||||
if (!image.IsEmpty())
|
||||
image_.reset(new gfx::Image(image));
|
||||
}
|
||||
|
||||
target_task_runner_->PostTask(FROM_HERE,
|
||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
||||
}
|
62
chromium_src/chrome/browser/icon_loader_mac.mm
Normal file
62
chromium_src/chrome/browser/icon_loader_mac.mm
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2012 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/icon_loader.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/image/image_skia_util_mac.h"
|
||||
|
||||
// static
|
||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
||||
const base::FilePath& filepath) {
|
||||
return filepath.Extension();
|
||||
}
|
||||
|
||||
// static
|
||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
content::BrowserThread::ID IconLoader::ReadIconThreadID() {
|
||||
return content::BrowserThread::FILE;
|
||||
}
|
||||
|
||||
void IconLoader::ReadIcon() {
|
||||
NSString* group = base::SysUTF8ToNSString(group_);
|
||||
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||
NSImage* icon = [workspace iconForFileType:group];
|
||||
|
||||
if (icon_size_ == ALL) {
|
||||
// The NSImage already has all sizes.
|
||||
image_.reset(new gfx::Image([icon retain]));
|
||||
} else {
|
||||
NSSize size = NSZeroSize;
|
||||
switch (icon_size_) {
|
||||
case IconLoader::SMALL:
|
||||
size = NSMakeSize(16, 16);
|
||||
break;
|
||||
case IconLoader::NORMAL:
|
||||
size = NSMakeSize(32, 32);
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
gfx::ImageSkia image_skia(gfx::ImageSkiaFromResizedNSImage(icon, size));
|
||||
if (!image_skia.isNull()) {
|
||||
image_skia.MakeThreadSafe();
|
||||
image_.reset(new gfx::Image(image_skia));
|
||||
}
|
||||
}
|
||||
|
||||
target_task_runner_->PostTask(FROM_HERE,
|
||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
||||
}
|
75
chromium_src/chrome/browser/icon_loader_win.cc
Normal file
75
chromium_src/chrome/browser/icon_loader_win.cc
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2012 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/icon_loader.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "ui/display/win/dpi.h"
|
||||
#include "ui/gfx/geometry/size.h"
|
||||
#include "ui/gfx/icon_util.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
// static
|
||||
IconGroupID IconLoader::ReadGroupIDFromFilepath(
|
||||
const base::FilePath& filepath) {
|
||||
if (!IsIconMutableFromFilepath(filepath))
|
||||
return filepath.Extension();
|
||||
return filepath.value();
|
||||
}
|
||||
|
||||
// static
|
||||
bool IconLoader::IsIconMutableFromFilepath(const base::FilePath& filepath) {
|
||||
return filepath.MatchesExtension(L".exe") ||
|
||||
filepath.MatchesExtension(L".dll") ||
|
||||
filepath.MatchesExtension(L".ico");
|
||||
}
|
||||
|
||||
// static
|
||||
content::BrowserThread::ID IconLoader::ReadIconThreadID() {
|
||||
return content::BrowserThread::FILE;
|
||||
}
|
||||
|
||||
void IconLoader::ReadIcon() {
|
||||
int size = 0;
|
||||
switch (icon_size_) {
|
||||
case IconLoader::SMALL:
|
||||
size = SHGFI_SMALLICON;
|
||||
break;
|
||||
case IconLoader::NORMAL:
|
||||
size = 0;
|
||||
break;
|
||||
case IconLoader::LARGE:
|
||||
size = SHGFI_LARGEICON;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
image_.reset();
|
||||
|
||||
SHFILEINFO file_info = {0};
|
||||
if (SHGetFileInfo(group_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
|
||||
sizeof(SHFILEINFO),
|
||||
SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
|
||||
std::unique_ptr<SkBitmap> bitmap(
|
||||
IconUtil::CreateSkBitmapFromHICON(file_info.hIcon));
|
||||
if (bitmap.get()) {
|
||||
gfx::ImageSkia image_skia(
|
||||
gfx::ImageSkiaRep(*bitmap, display::win::GetDPIScale()));
|
||||
image_skia.MakeThreadSafe();
|
||||
image_.reset(new gfx::Image(image_skia));
|
||||
DestroyIcon(file_info.hIcon);
|
||||
}
|
||||
}
|
||||
|
||||
// Always notify the delegate, regardless of success.
|
||||
target_task_runner_->PostTask(FROM_HERE,
|
||||
base::Bind(&IconLoader::NotifyDelegate, this));
|
||||
}
|
128
chromium_src/chrome/browser/icon_manager.cc
Normal file
128
chromium_src/chrome/browser/icon_manager.cc
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) 2011 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/icon_manager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/task_runner.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
|
||||
struct IconManager::ClientRequest {
|
||||
IconRequestCallback callback;
|
||||
base::FilePath file_path;
|
||||
IconLoader::IconSize size;
|
||||
};
|
||||
|
||||
// static
|
||||
IconManager* IconManager::GetInstance() {
|
||||
return base::Singleton<IconManager>::get();
|
||||
}
|
||||
|
||||
IconManager::IconManager() {}
|
||||
|
||||
IconManager::~IconManager() {
|
||||
base::STLDeleteValues(&icon_cache_);
|
||||
}
|
||||
|
||||
gfx::Image* IconManager::LookupIconFromFilepath(const base::FilePath& file_name,
|
||||
IconLoader::IconSize size) {
|
||||
GroupMap::iterator it = group_cache_.find(file_name);
|
||||
if (it != group_cache_.end())
|
||||
return LookupIconFromGroup(it->second, size);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gfx::Image* IconManager::LookupIconFromGroup(const IconGroupID& group,
|
||||
IconLoader::IconSize size) {
|
||||
IconMap::iterator it = icon_cache_.find(CacheKey(group, size));
|
||||
if (it != icon_cache_.end())
|
||||
return it->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IconManager::LoadIcon(const base::FilePath& file_name,
|
||||
IconLoader::IconSize size,
|
||||
const IconRequestCallback& callback) {
|
||||
IconLoader* loader = new IconLoader(file_name, size, this);
|
||||
loader->AddRef();
|
||||
loader->Start();
|
||||
|
||||
ClientRequest client_request = {callback, file_name, size};
|
||||
requests_[loader] = client_request;
|
||||
}
|
||||
|
||||
// IconLoader::Delegate implementation -----------------------------------------
|
||||
|
||||
bool IconManager::OnGroupLoaded(IconLoader* loader, const IconGroupID& group) {
|
||||
ClientRequests::iterator rit = requests_.find(loader);
|
||||
if (rit == requests_.end()) {
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::Image* result = LookupIconFromGroup(group, rit->second.size);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return OnImageLoaded(loader, result, group);
|
||||
}
|
||||
|
||||
bool IconManager::OnImageLoaded(IconLoader* loader,
|
||||
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)
|
||||
: group(group), size(size) {}
|
||||
|
||||
bool IconManager::CacheKey::operator<(const CacheKey& other) const {
|
||||
return std::tie(group, size) < std::tie(other.group, other.size);
|
||||
}
|
122
chromium_src/chrome/browser/icon_manager.h
Normal file
122
chromium_src/chrome/browser/icon_manager.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) 2012 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.
|
||||
//
|
||||
// Class for finding and caching Windows explorer icons. The IconManager
|
||||
// lives on the UI thread but performs icon extraction work on the file thread
|
||||
// to avoid blocking the UI thread with potentially expensive COM and disk
|
||||
// operations.
|
||||
//
|
||||
// Terminology
|
||||
//
|
||||
// Windows files have icons associated with them that can be of two types:
|
||||
// 1. "Per class": the icon used for this file is used for all files with the
|
||||
// same file extension or class. Examples are PDF or MP3 files, which use
|
||||
// the same icon for all files of that type.
|
||||
// 2. "Per instance": the icon used for this file is embedded in the file
|
||||
// itself and is unique. Executable files are typically "per instance".
|
||||
//
|
||||
// Files that end in the following extensions are considered "per instance":
|
||||
// .exe
|
||||
// .dll
|
||||
// .ico
|
||||
// The IconManager will do explicit icon loads on the full path of these files
|
||||
// and cache the results per file. All other file types will be looked up by
|
||||
// file extension and the results will be cached per extension. That way, all
|
||||
// .mp3 files will share one icon, but all .exe files will have their own icon.
|
||||
//
|
||||
// POSIX files don't have associated icons. We query the OS by the file's
|
||||
// mime type.
|
||||
//
|
||||
// The IconManager can be queried in two ways:
|
||||
// 1. A quick, synchronous check of its caches which does not touch the disk:
|
||||
// IconManager::LookupIcon()
|
||||
// 2. An asynchronous icon load from a file on the file thread:
|
||||
// IconManager::LoadIcon()
|
||||
//
|
||||
// When using the second (asychronous) method, callers must supply a callback
|
||||
// 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
|
||||
// fast.
|
||||
//
|
||||
// Icon bitmaps returned should be treated as const since they may be referenced
|
||||
// by other clients. Make a copy of the icon if you need to modify it.
|
||||
|
||||
#ifndef CHROME_BROWSER_ICON_MANAGER_H_
|
||||
#define CHROME_BROWSER_ICON_MANAGER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "chrome/browser/icon_loader.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
class IconManager : public IconLoader::Delegate {
|
||||
public:
|
||||
static IconManager* GetInstance();
|
||||
// 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
|
||||
// it via 'LoadIcon'. The returned bitmap is owned by the IconManager and must
|
||||
// not be free'd by the caller. If the caller needs to modify the icon, it
|
||||
// must make a copy and modify the copy.
|
||||
gfx::Image* LookupIconFromFilepath(const base::FilePath& file_name,
|
||||
IconLoader::IconSize size);
|
||||
|
||||
typedef base::Callback<void(gfx::Image*)> IconRequestCallback;
|
||||
|
||||
// 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
|
||||
// this function is called.
|
||||
//
|
||||
// Note:
|
||||
// 1. This does *not* check the cache.
|
||||
// 2. The returned bitmap pointer is *not* owned by callback. So callback
|
||||
// should never keep it or delete it.
|
||||
// 3. The gfx::Image pointer passed to the callback may be NULL if decoding
|
||||
// failed.
|
||||
void LoadIcon(const base::FilePath& file_name,
|
||||
IconLoader::IconSize size,
|
||||
const IconRequestCallback& callback);
|
||||
|
||||
// IconLoader::Delegate interface.
|
||||
bool OnGroupLoaded(IconLoader* loader, const IconGroupID& group) override;
|
||||
bool OnImageLoaded(IconLoader* loader,
|
||||
gfx::Image* result,
|
||||
const IconGroupID& group) override;
|
||||
|
||||
private:
|
||||
friend struct base::DefaultSingletonTraits<IconManager>;
|
||||
|
||||
IconManager();
|
||||
~IconManager() override;
|
||||
|
||||
struct CacheKey {
|
||||
CacheKey(const IconGroupID& group, IconLoader::IconSize size);
|
||||
|
||||
// Used as a key in the map below, so we need this comparator.
|
||||
bool operator<(const CacheKey& other) const;
|
||||
|
||||
IconGroupID group;
|
||||
IconLoader::IconSize size;
|
||||
};
|
||||
|
||||
gfx::Image* LookupIconFromGroup(const IconGroupID& group,
|
||||
IconLoader::IconSize size);
|
||||
|
||||
typedef std::map<CacheKey, gfx::Image*> IconMap;
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_ICON_MANAGER_H_
|
|
@ -401,6 +401,28 @@ You can request the following paths by the name:
|
|||
* `videos` Directory for a user's videos.
|
||||
* `pepperFlashSystemPlugin` Full path to the system version of the Pepper Flash plugin.
|
||||
|
||||
### `app.getFileIcon(path[, options], callback)`
|
||||
|
||||
* `path` String
|
||||
* `options` Object (optional)
|
||||
* `size` String
|
||||
* `small` - 16x16
|
||||
* `normal` - 32x32
|
||||
* `large` - 48x48 on _Linux_, 32x32 on _Windows_, unsupported on _macOS_.
|
||||
* `callback` Function
|
||||
* `error` Error
|
||||
* `icon` [NativeImage](native-image.md)
|
||||
|
||||
Fetches a path's associated icon.
|
||||
|
||||
On _Windows_, there a 2 kinds of icons:
|
||||
|
||||
- Icons associated with certain file extensions, like `.mp3`, `.png`, etc.
|
||||
- Icons inside the file itself, like `.exe`, `.dll`, `.ico`.
|
||||
|
||||
On _Linux_ and _macOS_, icons depend on the application associated with file
|
||||
mime type.
|
||||
|
||||
### `app.setPath(name, path)`
|
||||
|
||||
* `name` String
|
||||
|
|
|
@ -328,6 +328,7 @@
|
|||
}], # OS=="mac" and mas_build==1
|
||||
['OS=="linux"', {
|
||||
'sources': [
|
||||
'<@(lib_sources_linux)',
|
||||
'<@(lib_sources_nss)',
|
||||
],
|
||||
'link_settings': {
|
||||
|
|
|
@ -474,6 +474,12 @@
|
|||
'chromium_src/chrome/browser/browser_process.h',
|
||||
'chromium_src/chrome/browser/chrome_process_finder_win.cc',
|
||||
'chromium_src/chrome/browser/chrome_process_finder_win.h',
|
||||
'chromium_src/chrome/browser/icon_loader_mac.mm',
|
||||
'chromium_src/chrome/browser/icon_loader_win.cc',
|
||||
'chromium_src/chrome/browser/icon_loader.cc',
|
||||
'chromium_src/chrome/browser/icon_loader.h',
|
||||
'chromium_src/chrome/browser/icon_manager.cc',
|
||||
'chromium_src/chrome/browser/icon_manager.h',
|
||||
'chromium_src/chrome/browser/chrome_notification_types.h',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener.cc',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener.h',
|
||||
|
@ -601,6 +607,9 @@
|
|||
'<@(native_mate_files)',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/atom_natives.h',
|
||||
],
|
||||
'lib_sources_linux': [
|
||||
'chromium_src/chrome/browser/icon_loader_auralinux.cc',
|
||||
],
|
||||
'lib_sources_nss': [
|
||||
'chromium_src/chrome/browser/certificate_manager_model.cc',
|
||||
'chromium_src/chrome/browser/certificate_manager_model.h',
|
||||
|
|
|
@ -456,4 +456,66 @@ describe('app module', function () {
|
|||
assert.equal(app.isDefaultProtocolClient(protocol), false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getFileIcon() API', function () {
|
||||
const iconPath = path.join(__dirname, 'fixtures/assets/icon.ico')
|
||||
const sizes = {
|
||||
small: 16,
|
||||
normal: 32,
|
||||
large: process.platform === 'win32' ? 32 : 48
|
||||
}
|
||||
|
||||
it('fetches a non-empty icon', function (done) {
|
||||
app.getFileIcon(iconPath, function (err, icon) {
|
||||
assert.equal(err, null)
|
||||
assert.equal(icon.isEmpty(), false)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('fetches normal icon size by default', function (done) {
|
||||
app.getFileIcon(iconPath, function (err, icon) {
|
||||
const size = icon.getSize()
|
||||
assert.equal(err, null)
|
||||
assert.equal(size.height, sizes.normal)
|
||||
assert.equal(size.width, sizes.normal)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
describe('size option', function () {
|
||||
it('fetches a small icon', function (done) {
|
||||
app.getFileIcon(iconPath, { size: 'small' }, function (err, icon) {
|
||||
const size = icon.getSize()
|
||||
assert.equal(err, null)
|
||||
assert.equal(size.height, sizes.small)
|
||||
assert.equal(size.width, sizes.small)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('fetches a normal icon', function (done) {
|
||||
app.getFileIcon(iconPath, { size: 'normal' }, function (err, icon) {
|
||||
const size = icon.getSize()
|
||||
assert.equal(err, null)
|
||||
assert.equal(size.height, sizes.normal)
|
||||
assert.equal(size.width, sizes.normal)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('fetches a large icon', function (done) {
|
||||
// macOS does not support large icons
|
||||
if (process.platform === 'darwin') return done()
|
||||
|
||||
app.getFileIcon(iconPath, { size: 'large' }, function (err, icon) {
|
||||
const size = icon.getSize()
|
||||
assert.equal(err, null)
|
||||
assert.equal(size.height, sizes.large)
|
||||
assert.equal(size.width, sizes.large)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue