1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/icon_loader.h"
7 #import <AppKit/AppKit.h>
8 #import <CoreServices/CoreServices.h> // pre-macOS 11
9 #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h> // macOS 11
11 #include "base/apple/foundation_util.h"
12 #include "base/apple/scoped_cftyperef.h"
13 #include "base/files/file_path.h"
14 #include "base/functional/bind.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/task/thread_pool.h"
17 #include "base/threading/thread.h"
18 #include "ui/gfx/image/image_skia.h"
19 #include "ui/gfx/image/image_skia_util_mac.h"
22 IconLoader::IconGroup IconLoader::GroupForFilepath(
23 const base::FilePath& file_path) {
24 // The best option is to get the type directly from the file. The next best
25 // option is to pull the extension from the file and get the type from that.
26 // The last and worst option is to fall back to `public.content` which will
27 // give a generic file icon.
29 if (@available(macOS 11, *)) {
31 NSURL* file_url = base::apple::FilePathToNSURL(file_path);
32 if (file_url && [file_url getResourceValue:&type
33 forKey:NSURLContentTypeKey
35 return base::SysNSStringToUTF8(type.identifier);
38 std::string extension_string = file_path.FinalExtension();
39 if (!extension_string.empty()) {
40 // Remove the leading dot.
41 extension_string.erase(extension_string.begin());
44 typeWithFilenameExtension:base::SysUTF8ToNSString(extension_string)];
46 return base::SysNSStringToUTF8(type.identifier);
50 return base::SysNSStringToUTF8(UTTypeContent.identifier);
53 NSURL* file_url = base::apple::FilePathToNSURL(file_path);
54 if (file_url && [file_url getResourceValue:&type
55 forKey:NSURLTypeIdentifierKey
57 return base::SysNSStringToUTF8(type);
60 std::string extension_string = file_path.FinalExtension();
61 if (!extension_string.empty()) {
62 // Remove the leading dot.
63 extension_string.erase(extension_string.begin());
65 base::apple::ScopedCFTypeRef<CFStringRef> extension_cf =
66 base::SysUTF8ToCFStringRef(extension_string);
67 base::apple::ScopedCFTypeRef<CFStringRef> cftype(
68 UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
70 /*inConformingToUTI=*/nullptr));
72 return base::SysCFStringRefToUTF8(cftype);
76 return base::SysCFStringRefToUTF8(kUTTypeContent);
81 scoped_refptr<base::TaskRunner> IconLoader::GetReadIconTaskRunner() {
82 // NSWorkspace is thread-safe.
83 return base::ThreadPool::CreateTaskRunner(traits());
86 void IconLoader::ReadIcon() {
88 if (@available(macOS 11, *)) {
89 UTType* type = [UTType typeWithIdentifier:base::SysUTF8ToNSString(group_)];
90 icon = [NSWorkspace.sharedWorkspace iconForContentType:type];
92 NSString* type = base::SysUTF8ToNSString(group_);
93 icon = [NSWorkspace.sharedWorkspace iconForFileType:type];
97 if (icon_size_ == ALL) {
98 // The NSImage already has all sizes.
99 image = gfx::Image(icon);
101 NSSize size = NSZeroSize;
102 switch (icon_size_) {
103 case IconLoader::SMALL:
104 size = NSMakeSize(16, 16);
106 case IconLoader::NORMAL:
107 size = NSMakeSize(32, 32);
113 gfx::ImageSkia image_skia = gfx::ImageSkiaFromResizedNSImage(icon, size);
114 if (!image_skia.isNull()) {
115 image_skia.MakeThreadSafe();
116 image = gfx::Image(image_skia);
120 target_task_runner_->PostTask(
122 base::BindOnce(std::move(callback_), std::move(image), group_));