blob: bd2622b05642a3b8934a18e87b4c7e6f3e6a5960 [file] [log] [blame]
[email protected]93079e02012-05-15 15:42:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]46728b1f2009-05-07 20:42:242// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]0f38ceae2009-05-08 19:01:025#include "chrome/browser/icon_loader.h"
[email protected]46728b1f2009-05-07 20:42:246
7#include <windows.h>
8#include <shellapi.h>
9
[email protected]a27a2bc2011-11-15 21:25:5110#include "base/bind.h"
Alex Gougha4160b852020-06-23 00:21:2911#include "base/callback.h"
12#include "base/files/file_path.h"
Gabriel Charette53381852020-03-02 15:27:2013#include "base/task/thread_pool.h"
[email protected]34b99632011-01-01 01:01:0614#include "base/threading/thread.h"
Alex Gougha4160b852020-06-23 00:21:2915#include "chrome/browser/win/icon_reader_service.h"
16#include "chrome/services/util_win/public/mojom/util_read_icon.mojom.h"
17#include "content/public/browser/browser_task_traits.h"
18#include "content/public/browser/browser_thread.h"
robliao18e220e82016-04-19 16:47:1219#include "ui/display/win/dpi.h"
tfarinaebe974f02015-01-03 04:25:3220#include "ui/gfx/geometry/size.h"
[email protected]08397d52011-02-05 01:53:3821#include "ui/gfx/icon_util.h"
[email protected]2b8ac342012-08-29 03:46:2722#include "ui/gfx/image/image_skia.h"
[email protected]46728b1f2009-05-07 20:42:2423
Alex Gougha4160b852020-06-23 00:21:2924namespace {
25// Helper class to manage lifetime of icon reader service.
26class IconLoaderHelper {
27 public:
28 static void ExecuteLoadIcon(
29 base::FilePath filename,
30 chrome::mojom::IconSize size,
31 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
32 IconLoader::IconLoadedCallback icon_loaded_callback);
33
34 IconLoaderHelper(base::FilePath filename, chrome::mojom::IconSize size);
35
36 private:
37 void StartReadIconRequest();
38 void OnConnectionError();
39 void OnReadIconExecuted(const gfx::ImageSkia& icon,
40 const base::string16& group);
41
42 using IconLoaderHelperCallback =
43 base::OnceCallback<void(gfx::Image image,
44 const IconLoader::IconGroup& icon_group)>;
45
46 void set_finally(IconLoaderHelperCallback finally) {
47 finally_ = std::move(finally);
48 }
49
50 mojo::Remote<chrome::mojom::UtilReadIcon> remote_read_icon_;
51 base::FilePath filename_;
52 chrome::mojom::IconSize size_;
53 // This callback owns the object until work is done.
54 IconLoaderHelperCallback finally_;
55
56 SEQUENCE_CHECKER(sequence_checker_);
57
58 DISALLOW_COPY_AND_ASSIGN(IconLoaderHelper);
59};
60
61void IconLoaderHelper::ExecuteLoadIcon(
62 base::FilePath filename,
63 chrome::mojom::IconSize size,
64 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
65 IconLoader::IconLoadedCallback icon_loaded_callback) {
66 // Self-deleting helper manages service lifetime.
67 auto helper = std::make_unique<IconLoaderHelper>(filename, size);
68 auto* helper_raw = helper.get();
69 // This callback owns the helper and extinguishes itself once work is done.
70 auto finally_callback = base::BindOnce(
71 [](std::unique_ptr<IconLoaderHelper> helper,
72 IconLoader::IconLoadedCallback icon_loaded_callback,
73 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner,
74 gfx::Image image, const IconLoader::IconGroup& icon_group) {
75 target_task_runner->PostTask(
76 FROM_HERE, base::BindOnce(std::move(icon_loaded_callback),
77 std::move(image), icon_group));
78 },
79 std::move(helper), std::move(icon_loaded_callback), target_task_runner);
80
81 helper_raw->set_finally(std::move(finally_callback));
82 helper_raw->StartReadIconRequest();
83}
84
85IconLoaderHelper::IconLoaderHelper(base::FilePath filename,
86 chrome::mojom::IconSize size)
87 : filename_(filename), size_(size) {
88 remote_read_icon_ = LaunchIconReaderInstance();
89 remote_read_icon_.set_disconnect_handler(base::BindOnce(
90 &IconLoaderHelper::OnConnectionError, base::Unretained(this)));
91}
92
93void IconLoaderHelper::StartReadIconRequest() {
94 remote_read_icon_->ReadIcon(
95 filename_, size_,
96 base::BindOnce(&IconLoaderHelper::OnReadIconExecuted,
97 base::Unretained(this)));
98}
99
100void IconLoaderHelper::OnConnectionError() {
101 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
102 if (finally_.is_null())
103 return;
104
105 gfx::Image image;
106 std::move(finally_).Run(std::move(image), filename_.value());
107}
108
109void IconLoaderHelper::OnReadIconExecuted(const gfx::ImageSkia& icon,
110 const base::string16& group) {
111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
112
113 gfx::Image image(icon);
114 std::move(finally_).Run(std::move(image), group);
115}
116
117} // namespace
118
[email protected]bc0147b2013-04-03 20:50:59119// static
avi381f719f2016-12-16 00:05:02120IconLoader::IconGroup IconLoader::GroupForFilepath(
121 const base::FilePath& file_path) {
122 if (file_path.MatchesExtension(L".exe") ||
123 file_path.MatchesExtension(L".dll") ||
124 file_path.MatchesExtension(L".ico")) {
125 return file_path.value();
126 }
[email protected]681b4b82013-04-09 23:34:21127
avi381f719f2016-12-16 00:05:02128 return file_path.Extension();
[email protected]bc0147b2013-04-03 20:50:59129}
130
[email protected]b3b6a372014-03-12 01:48:04131// static
avif4d431c2017-06-22 23:30:53132scoped_refptr<base::TaskRunner> IconLoader::GetReadIconTaskRunner() {
133 // Technically speaking, only a thread with COM is needed, not one that has
134 // a COM STA. However, this is what is available for now.
Gabriel Charette53381852020-03-02 15:27:20135 return base::ThreadPool::CreateCOMSTATaskRunner(traits());
[email protected]b3b6a372014-03-12 01:48:04136}
137
Alex Gougha4160b852020-06-23 00:21:29138void IconLoader::ReadGroup() {
139 group_ = GroupForFilepath(file_path_);
140
141 if (group_ == file_path_.value()) {
142 // Calls a Windows API that parses the file so must be sandboxed. Call on
143 // target sequence as we don't need COM in this process.
144 target_task_runner_->PostTask(
145 FROM_HERE,
146 base::BindOnce(&IconLoader::ReadIconInSandbox, base::Unretained(this)));
147 } else {
148 // Looks up generic icons for groups based only on the file's extension.
149 GetReadIconTaskRunner()->PostTask(
150 FROM_HERE,
151 base::BindOnce(&IconLoader::ReadIcon, base::Unretained(this)));
152 }
153}
154
[email protected]0f38ceae2009-05-08 19:01:02155void IconLoader::ReadIcon() {
Maxim Kolosovskiy40269bd2020-06-18 09:40:18156 int size = 0;
157 switch (icon_size_) {
158 case IconLoader::SMALL:
159 size = SHGFI_SMALLICON;
160 break;
161 case IconLoader::NORMAL:
162 size = 0;
163 break;
164 case IconLoader::LARGE:
165 size = SHGFI_LARGEICON;
166 break;
167 default:
168 NOTREACHED();
169 }
170
171 gfx::Image image;
172
173 SHFILEINFO file_info = { 0 };
174 if (SHGetFileInfo(group_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
Alex Gougha4160b852020-06-23 00:21:29175 sizeof(file_info),
176 SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES)) {
Maxim Kolosovskiy40269bd2020-06-18 09:40:18177 const SkBitmap bitmap = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon);
178 if (!bitmap.isNull()) {
179 gfx::ImageSkia image_skia(
180 gfx::ImageSkiaRep(bitmap, display::win::GetDPIScale()));
181 image_skia.MakeThreadSafe();
182 image = gfx::Image(image_skia);
183 }
Alex Gougha4160b852020-06-23 00:21:29184 DestroyIcon(file_info.hIcon);
Maxim Kolosovskiy40269bd2020-06-18 09:40:18185 }
[email protected]ab6d23f2012-09-07 18:43:12186
avif0a7b5b812016-12-17 19:01:31187 target_task_runner_->PostTask(
Avi Drissmanefe4dc82018-02-23 17:55:39188 FROM_HERE,
189 base::BindOnce(std::move(callback_), std::move(image), group_));
avif0a7b5b812016-12-17 19:01:31190 delete this;
[email protected]46728b1f2009-05-07 20:42:24191}
Alex Gougha4160b852020-06-23 00:21:29192
193void IconLoader::ReadIconInSandbox() {
194 chrome::mojom::IconSize size = chrome::mojom::IconSize::kNormal;
195 switch (icon_size_) {
196 case IconLoader::SMALL:
197 size = chrome::mojom::IconSize::kSmall;
198 break;
199 case IconLoader::NORMAL:
200 size = chrome::mojom::IconSize::kNormal;
201 break;
202 case IconLoader::LARGE:
203 size = chrome::mojom::IconSize::kLarge;
204 break;
205 default:
206 NOTREACHED();
207 }
208
209 IconLoaderHelper::ExecuteLoadIcon(base::FilePath(group_), size,
210 target_task_runner_, std::move(callback_));
211
212 delete this;
213}