Reland "Use default icons for PE files lacking their own."
This is a reland of 676d0cb1f6ac3488102c1024c70ae3c272861431.
[email protected]
Bug: 1032250
Original change's description:
> 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 <[email protected]>
> Reviewed-by: François Doray <[email protected]>
> Reviewed-by: Avi Drissman <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#779542}
Change-Id: Ie7f5e57dbbfb1ebf5d9fc588e15b1a2687212bce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2254823
Reviewed-by: Alex Gough <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Commit-Queue: Alex Gough <[email protected]>
Cr-Commit-Position: refs/heads/master@{#781108}
diff --git a/chrome/browser/icon_loader_win.cc b/chrome/browser/icon_loader_win.cc
index bd2622b..a6c4d17c 100644
--- a/chrome/browser/icon_loader_win.cc
+++ b/chrome/browser/icon_loader_win.cc
@@ -28,10 +28,13 @@
static void ExecuteLoadIcon(
base::FilePath filename,
chrome::mojom::IconSize size,
+ gfx::Image default_icon,
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
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:
void StartReadIconRequest();
@@ -52,6 +55,7 @@
chrome::mojom::IconSize size_;
// This callback owns the object until work is done.
IconLoaderHelperCallback finally_;
+ gfx::Image default_icon_;
SEQUENCE_CHECKER(sequence_checker_);
@@ -61,10 +65,12 @@
void IconLoaderHelper::ExecuteLoadIcon(
base::FilePath filename,
chrome::mojom::IconSize size,
+ gfx::Image default_icon,
scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
IconLoader::IconLoadedCallback icon_loaded_callback) {
// 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();
// This callback owns the helper and extinguishes itself once work is done.
auto finally_callback = base::BindOnce(
@@ -83,8 +89,9 @@
}
IconLoaderHelper::IconLoaderHelper(base::FilePath filename,
- chrome::mojom::IconSize size)
- : filename_(filename), size_(size) {
+ chrome::mojom::IconSize size,
+ gfx::Image default_icon)
+ : filename_(filename), size_(size), default_icon_(std::move(default_icon)) {
remote_read_icon_ = LaunchIconReaderInstance();
remote_read_icon_.set_disconnect_handler(base::BindOnce(
&IconLoaderHelper::OnConnectionError, base::Unretained(this)));
@@ -102,16 +109,55 @@
if (finally_.is_null())
return;
- gfx::Image image;
- std::move(finally_).Run(std::move(image), filename_.value());
+ std::move(finally_).Run(std::move(default_icon_), filename_.value());
}
void IconLoaderHelper::OnReadIconExecuted(const gfx::ImageSkia& icon,
const base::string16& group) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- gfx::Image image(icon);
- std::move(finally_).Run(std::move(image), group);
+ if (icon.isNull()) {
+ 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
@@ -139,9 +185,8 @@
group_ = GroupForFilepath(file_path_);
if (group_ == file_path_.value()) {
- // Calls a Windows API that parses the file so must be sandboxed. Call on
- // target sequence as we don't need COM in this process.
- target_task_runner_->PostTask(
+ // Calls a Windows API that parses the file so must be sandboxed.
+ GetReadIconTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&IconLoader::ReadIconInSandbox, base::Unretained(this)));
} else {
@@ -153,44 +198,21 @@
}
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();
- }
-
- 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);
- }
+ auto image = GetIconForFileExtension(group_, icon_size_);
target_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback_), std::move(image), group_));
+
delete this;
}
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;
switch (icon_size_) {
case IconLoader::SMALL:
@@ -206,8 +228,10 @@
NOTREACHED();
}
- IconLoaderHelper::ExecuteLoadIcon(base::FilePath(group_), size,
- target_task_runner_, std::move(callback_));
+ target_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&IconLoaderHelper::ExecuteLoadIcon,
+ std::move(path), size, std::move(default_icon),
+ target_task_runner_, std::move(callback_)));
delete this;
}