Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an API to fetch file icon #7851

Merged
merged 32 commits into from Feb 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
be5b907
WIP
YurySolovyov Oct 29, 2016
1d24a3a
Add callback converters
YurySolovyov Oct 29, 2016
8e4ed66
Add icon fetching sources
YurySolovyov Oct 29, 2016
d118fed
Try my own class
YurySolovyov Oct 29, 2016
eb889b9
Get it compiling, linking till fails though
YurySolovyov Oct 30, 2016
602aba8
Include proper header
YurySolovyov Oct 30, 2016
1b3cd87
Add icon manager to browser process
YurySolovyov Oct 30, 2016
b25b141
create iconmanager as singleton class and cleanup code (#1)
deepak1556 Nov 2, 2016
ff3aaa5
define icon loader for liunx as separate target
deepak1556 Nov 3, 2016
bec671b
Make size optional
YurySolovyov Nov 3, 2016
05cb26a
Use object for options
YurySolovyov Nov 3, 2016
fe99b25
Add docs
YurySolovyov Nov 3, 2016
3d47c9b
Fix lint
YurySolovyov Nov 3, 2016
2e85ff1
Fix code style
deepak1556 Nov 4, 2016
1b4ee6e
Image from icon node-style callback (#2)
YurySolovyov Nov 5, 2016
5794138
Normalize path
YurySolovyov Nov 5, 2016
11ef2c5
Update docs
YurySolovyov Nov 5, 2016
c2bf5bb
Put locker and handle scope to the top of the function. Remove unneed…
YurySolovyov Nov 6, 2016
0074888
Add tests
YurySolovyov Nov 6, 2016
1aa4fca
Lint tests
YurySolovyov Nov 6, 2016
c36cdb8
Properly skip large size test on macOS
YurySolovyov Nov 6, 2016
2945236
Use isolate() method to get isolate
YurySolovyov Nov 6, 2016
2b60df3
Fix some feedback
YurySolovyov Nov 6, 2016
bcf0964
Fix more review
YurySolovyov Nov 10, 2016
c810e64
Fix doc lint
YurySolovyov Nov 10, 2016
a9dae24
Fix large icon spec
YurySolovyov Nov 11, 2016
ee66776
Update IconManager for Chrome 56 upgrade
kevinsawicki Feb 7, 2017
683a758
Call done instead of skip
kevinsawicki Feb 7, 2017
dddc6ae
Tweak spec descriptions
kevinsawicki Feb 7, 2017
a4277bb
Document sizes
kevinsawicki Feb 7, 2017
fc1b743
Tweak optional syntax
kevinsawicki Feb 7, 2017
82ac4dd
Large is only 48x48 on Linux
kevinsawicki Feb 7, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 63 additions & 1 deletion atom/browser/api/atom_api_app.cc
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -909,7 +970,8 @@ void App::BuildPrototype(
.SetMethod("isAccessibilitySupportEnabled",
&App::IsAccessibilitySupportEnabled)
.SetMethod("disableHardwareAcceleration",
&App::DisableHardwareAcceleration);
&App::DisableHardwareAcceleration)
.SetMethod("getFileIcon", &App::GetFileIcon);
}

} // namespace api
Expand Down
6 changes: 6 additions & 0 deletions atom/browser/api/atom_api_app.h
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down
48 changes: 48 additions & 0 deletions chromium_src/chrome/browser/icon_loader.cc
@@ -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 changes: 105 additions & 0 deletions chromium_src/chrome/browser/icon_loader.h
@@ -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 changes: 55 additions & 0 deletions chromium_src/chrome/browser/icon_loader_auralinux.cc
@@ -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 changes: 62 additions & 0 deletions chromium_src/chrome/browser/icon_loader_mac.mm
@@ -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));
}