Commit 676d0cb1 authored by Alex Gough's avatar Alex Gough Committed by Commit Bot

Use default icons for PE files lacking their own.

PrivateExtractIcon (underlying the icon loading service) may fail to
supply an icon for PE files that do not have one embedded and would
display as a blank area when downloaded. This change fetches the
default for the file extension prior to fetching the file's embedded
icon. It is difficult to do this only on failure as the ownership of
IconLoader means it has already been deleted when we learn about the
failure. It should be relatively cheap to fetch the default icons as
these will be cached by the OS, and this occurs in the main process.

Tests: Added LoadDefaultIcon in icon_loader_browser_test
Bug: 1032250
Change-Id: Ifad1c9f013d0e4fe87aaec5ec0cdeae08d06799e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2242371
Commit-Queue: Alex Gough <ajgo@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779542}
parent 02997c65
...@@ -86,4 +86,20 @@ IN_PROC_BROWSER_TEST_F(IconLoaderBrowserTest, LoadExeIcon) { ...@@ -86,4 +86,20 @@ IN_PROC_BROWSER_TEST_F(IconLoaderBrowserTest, LoadExeIcon) {
runner.Run(); runner.Run();
EXPECT_TRUE(test_loader.load_succeeded()); EXPECT_TRUE(test_loader.load_succeeded());
} }
const base::FilePath::CharType kNotExistingExeFile[] =
FILE_PATH_LITERAL("unlikely-to-exist-file.exe");
IN_PROC_BROWSER_TEST_F(IconLoaderBrowserTest, LoadDefaultExeIcon) {
base::RunLoop runner;
TestIconLoader test_loader(runner.QuitClosure());
test_loader.TryLoadIcon(base::FilePath(kNotExistingExeFile),
IconLoader::NORMAL);
runner.Run();
EXPECT_TRUE(test_loader.load_succeeded());
}
#endif #endif
...@@ -28,10 +28,13 @@ class IconLoaderHelper { ...@@ -28,10 +28,13 @@ class IconLoaderHelper {
static void ExecuteLoadIcon( static void ExecuteLoadIcon(
base::FilePath filename, base::FilePath filename,
chrome::mojom::IconSize size, chrome::mojom::IconSize size,
gfx::Image default_icon,
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner, scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
IconLoader::IconLoadedCallback icon_loaded_callback); IconLoader::IconLoadedCallback icon_loaded_callback);
IconLoaderHelper(base::FilePath filename, chrome::mojom::IconSize size); IconLoaderHelper(base::FilePath filename,
chrome::mojom::IconSize size,
gfx::Image default_icon);
private: private:
void StartReadIconRequest(); void StartReadIconRequest();
...@@ -52,6 +55,7 @@ class IconLoaderHelper { ...@@ -52,6 +55,7 @@ class IconLoaderHelper {
chrome::mojom::IconSize size_; chrome::mojom::IconSize size_;
// This callback owns the object until work is done. // This callback owns the object until work is done.
IconLoaderHelperCallback finally_; IconLoaderHelperCallback finally_;
gfx::Image default_icon_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
...@@ -61,10 +65,12 @@ class IconLoaderHelper { ...@@ -61,10 +65,12 @@ class IconLoaderHelper {
void IconLoaderHelper::ExecuteLoadIcon( void IconLoaderHelper::ExecuteLoadIcon(
base::FilePath filename, base::FilePath filename,
chrome::mojom::IconSize size, chrome::mojom::IconSize size,
gfx::Image default_icon,
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner, scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
IconLoader::IconLoadedCallback icon_loaded_callback) { IconLoader::IconLoadedCallback icon_loaded_callback) {
// Self-deleting helper manages service lifetime. // Self-deleting helper manages service lifetime.
auto helper = std::make_unique<IconLoaderHelper>(filename, size); auto helper = std::make_unique<IconLoaderHelper>(filename, size,
std::move(default_icon));
auto* helper_raw = helper.get(); auto* helper_raw = helper.get();
// This callback owns the helper and extinguishes itself once work is done. // This callback owns the helper and extinguishes itself once work is done.
auto finally_callback = base::BindOnce( auto finally_callback = base::BindOnce(
...@@ -83,8 +89,9 @@ void IconLoaderHelper::ExecuteLoadIcon( ...@@ -83,8 +89,9 @@ void IconLoaderHelper::ExecuteLoadIcon(
} }
IconLoaderHelper::IconLoaderHelper(base::FilePath filename, IconLoaderHelper::IconLoaderHelper(base::FilePath filename,
chrome::mojom::IconSize size) chrome::mojom::IconSize size,
: filename_(filename), size_(size) { gfx::Image default_icon)
: filename_(filename), size_(size), default_icon_(std::move(default_icon)) {
remote_read_icon_ = LaunchIconReaderInstance(); remote_read_icon_ = LaunchIconReaderInstance();
remote_read_icon_.set_disconnect_handler(base::BindOnce( remote_read_icon_.set_disconnect_handler(base::BindOnce(
&IconLoaderHelper::OnConnectionError, base::Unretained(this))); &IconLoaderHelper::OnConnectionError, base::Unretained(this)));
...@@ -102,16 +109,55 @@ void IconLoaderHelper::OnConnectionError() { ...@@ -102,16 +109,55 @@ void IconLoaderHelper::OnConnectionError() {
if (finally_.is_null()) if (finally_.is_null())
return; return;
gfx::Image image; std::move(finally_).Run(std::move(default_icon_), filename_.value());
std::move(finally_).Run(std::move(image), filename_.value());
} }
void IconLoaderHelper::OnReadIconExecuted(const gfx::ImageSkia& icon, void IconLoaderHelper::OnReadIconExecuted(const gfx::ImageSkia& icon,
const base::string16& group) { const base::string16& group) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gfx::Image image(icon); if (icon.isNull()) {
std::move(finally_).Run(std::move(image), group); std::move(finally_).Run(std::move(default_icon_), group);
} else {
gfx::Image image(icon);
std::move(finally_).Run(std::move(image), group);
}
}
// Must be called in a COM context. |group| should be a file extension.
gfx::Image GetIconForFileExtension(base::string16 group,
IconLoader::IconSize icon_size) {
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();
}
gfx::Image image;
SHFILEINFO file_info = {0};
if (SHGetFileInfo(group.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
sizeof(file_info),
SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon);
if (!bitmap.isNull()) {
gfx::ImageSkia image_skia(
gfx::ImageSkiaRep(bitmap, display::win::GetDPIScale()));
image_skia.MakeThreadSafe();
image = gfx::Image(image_skia);
}
DestroyIcon(file_info.hIcon);
}
return image;
} }
} // namespace } // namespace
...@@ -139,9 +185,8 @@ void IconLoader::ReadGroup() { ...@@ -139,9 +185,8 @@ void IconLoader::ReadGroup() {
group_ = GroupForFilepath(file_path_); group_ = GroupForFilepath(file_path_);
if (group_ == file_path_.value()) { if (group_ == file_path_.value()) {
// Calls a Windows API that parses the file so must be sandboxed. Call on // Calls a Windows API that parses the file so must be sandboxed.
// target sequence as we don't need COM in this process. GetReadIconTaskRunner()->PostTask(
target_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&IconLoader::ReadIconInSandbox, base::Unretained(this))); base::BindOnce(&IconLoader::ReadIconInSandbox, base::Unretained(this)));
} else { } else {
...@@ -153,44 +198,21 @@ void IconLoader::ReadGroup() { ...@@ -153,44 +198,21 @@ void IconLoader::ReadGroup() {
} }
void IconLoader::ReadIcon() { void IconLoader::ReadIcon() {
int size = 0; auto image = GetIconForFileExtension(group_, icon_size_);
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();
}
gfx::Image image;
SHFILEINFO file_info = { 0 };
if (SHGetFileInfo(group_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
sizeof(file_info),
SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon);
if (!bitmap.isNull()) {
gfx::ImageSkia image_skia(
gfx::ImageSkiaRep(bitmap, display::win::GetDPIScale()));
image_skia.MakeThreadSafe();
image = gfx::Image(image_skia);
}
DestroyIcon(file_info.hIcon);
}
target_task_runner_->PostTask( target_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(std::move(callback_), std::move(image), group_)); base::BindOnce(std::move(callback_), std::move(image), group_));
delete this; delete this;
} }
void IconLoader::ReadIconInSandbox() { void IconLoader::ReadIconInSandbox() {
// Get default first as loader is deleted before ExecuteLoadIcon
// completes.
auto path = base::FilePath(group_);
auto default_icon = GetIconForFileExtension(path.Extension(), icon_size_);
chrome::mojom::IconSize size = chrome::mojom::IconSize::kNormal; chrome::mojom::IconSize size = chrome::mojom::IconSize::kNormal;
switch (icon_size_) { switch (icon_size_) {
case IconLoader::SMALL: case IconLoader::SMALL:
...@@ -206,8 +228,10 @@ void IconLoader::ReadIconInSandbox() { ...@@ -206,8 +228,10 @@ void IconLoader::ReadIconInSandbox() {
NOTREACHED(); NOTREACHED();
} }
IconLoaderHelper::ExecuteLoadIcon(base::FilePath(group_), size, target_task_runner_->PostTask(
target_task_runner_, std::move(callback_)); FROM_HERE, base::BindOnce(&IconLoaderHelper::ExecuteLoadIcon,
std::move(path), size, std::move(default_icon),
target_task_runner_, std::move(callback_)));
delete this; delete this;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment