1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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"
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/lazy_instance.h"
14 #include "base/memory/ref_counted_memory.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/strings/string_util.h"
17 #include "chrome/browser/icon_loader.h"
18 #include "grit/theme_resources.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "ui/base/layout.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/gfx/codec/png_codec.h"
24 #include "ui/gfx/image/image.h"
25 #include "ui/gfx/image/image_skia.h"
26 #include "ui/gfx/image/image_skia_operations.h"
30 // Used with GenerateImageWithSize() to indicate that the image shouldn't be
32 const int kDoNotResize
= -1;
40 // Performs mapping of <file extension, icon size> to icon resource IDs.
45 // Lookup icon resource ID for a given filename |extension| and
46 // |icon_size|. Defaults to generic icons if there are no icons for the given
48 int Lookup(const std::string
& extension
, IconLoader::IconSize icon_size
);
51 typedef std::map
<std::string
, IdrBySize
> ExtensionIconMap
;
53 ExtensionIconMap extension_icon_map_
;
56 const IdrBySize kAudioIdrs
= {
58 IDR_FILETYPE_LARGE_AUDIO
,
59 IDR_FILETYPE_LARGE_AUDIO
61 const IdrBySize kGenericIdrs
= {
63 IDR_FILETYPE_LARGE_GENERIC
,
64 IDR_FILETYPE_LARGE_GENERIC
66 const IdrBySize kImageIdrs
= {
71 #if defined(USE_PROPRIETARY_CODECS)
72 const IdrBySize kPdfIdrs
= {
78 const IdrBySize kVideoIdrs
= {
80 IDR_FILETYPE_LARGE_VIDEO
,
81 IDR_FILETYPE_LARGE_VIDEO
84 IconMapper::IconMapper() {
85 // The code below should match translation in
86 // ui/file_manager/file_manager/js/file_manager.js
87 // ui/file_manager/file_manager/css/file_manager.css
88 // 'audio': /\.(mp3|m4a|oga|ogg|wav)$/i,
89 // 'html': /\.(html?)$/i,
90 // 'image': /\.(bmp|gif|jpe?g|ico|png|webp)$/i,
91 // 'pdf' : /\.(pdf)$/i,
92 // 'text': /\.(pod|rst|txt|log)$/i,
93 // 'video': /\.(mov|mp4|m4v|mpe?g4?|ogm|ogv|ogx|webm)$/i
95 const ExtensionIconMap::value_type kExtensionIdrBySizeData
[] = {
96 #if defined(USE_PROPRIETARY_CODECS)
97 std::make_pair(".m4a", kAudioIdrs
),
98 std::make_pair(".mp3", kAudioIdrs
),
99 std::make_pair(".pdf", kPdfIdrs
),
100 std::make_pair(".3gp", kVideoIdrs
),
101 std::make_pair(".avi", kVideoIdrs
),
102 std::make_pair(".m4v", kVideoIdrs
),
103 std::make_pair(".mov", kVideoIdrs
),
104 std::make_pair(".mp4", kVideoIdrs
),
105 std::make_pair(".mpeg", kVideoIdrs
),
106 std::make_pair(".mpg", kVideoIdrs
),
107 std::make_pair(".mpeg4", kVideoIdrs
),
108 std::make_pair(".mpg4", kVideoIdrs
),
110 std::make_pair(".flac", kAudioIdrs
),
111 std::make_pair(".oga", kAudioIdrs
),
112 std::make_pair(".ogg", kAudioIdrs
),
113 std::make_pair(".wav", kAudioIdrs
),
114 std::make_pair(".bmp", kImageIdrs
),
115 std::make_pair(".gif", kImageIdrs
),
116 std::make_pair(".ico", kImageIdrs
),
117 std::make_pair(".jpeg", kImageIdrs
),
118 std::make_pair(".jpg", kImageIdrs
),
119 std::make_pair(".png", kImageIdrs
),
120 std::make_pair(".webp", kImageIdrs
),
121 std::make_pair(".ogm", kVideoIdrs
),
122 std::make_pair(".ogv", kVideoIdrs
),
123 std::make_pair(".ogx", kVideoIdrs
),
124 std::make_pair(".webm", kVideoIdrs
),
127 const size_t kESize
= arraysize(kExtensionIdrBySizeData
);
128 ExtensionIconMap
source(&kExtensionIdrBySizeData
[0],
129 &kExtensionIdrBySizeData
[kESize
]);
130 extension_icon_map_
.swap(source
);
133 int IconMapper::Lookup(const std::string
& extension
,
134 IconLoader::IconSize icon_size
) {
135 DCHECK(icon_size
== IconLoader::SMALL
||
136 icon_size
== IconLoader::NORMAL
||
137 icon_size
== IconLoader::LARGE
);
138 ExtensionIconMap::const_iterator it
= extension_icon_map_
.find(extension
);
139 const IdrBySize
& idrbysize
=
140 ((it
== extension_icon_map_
.end()) ? kGenericIdrs
: it
->second
);
143 case IconLoader::SMALL
: idr
= idrbysize
.idr_small
; break;
144 case IconLoader::NORMAL
: idr
= idrbysize
.idr_normal
; break;
145 case IconLoader::LARGE
: idr
= idrbysize
.idr_large
; break;
146 case IconLoader::ALL
:
153 // Returns a copy of |source| that is |dip_size| in width and height. If
154 // |dip_size| is |kDoNotResize|, returns an unmodified copy of |source|.
155 // |source| must be a square image (width == height).
156 gfx::ImageSkia
ResizeImage(const gfx::ImageSkia
& source
, int dip_size
) {
157 DCHECK(!source
.isNull());
158 DCHECK(source
.width() == source
.height());
160 if (dip_size
== kDoNotResize
|| source
.width() == dip_size
)
163 return gfx::ImageSkiaOperations::CreateResizedImage(source
,
164 skia::ImageOperations::RESIZE_BEST
, gfx::Size(dip_size
, dip_size
));
167 int IconSizeToDIPSize(IconLoader::IconSize size
) {
169 case IconLoader::SMALL
: return 16;
170 case IconLoader::NORMAL
: return 32;
171 case IconLoader::LARGE
: // fallthrough
172 // On ChromeOS, we consider LARGE to mean "the largest image we have."
173 // Since we have already chosen the largest applicable image resource, we
174 // return the image as-is.
175 case IconLoader::ALL
: // fallthrough
184 IconGroupID
IconLoader::ReadGroupIDFromFilepath(
185 const base::FilePath
& filepath
) {
186 return StringToLowerASCII(filepath
.Extension());
190 bool IconLoader::IsIconMutableFromFilepath(const base::FilePath
&) {
195 content::BrowserThread::ID
IconLoader::ReadIconThreadID() {
196 return content::BrowserThread::FILE;
199 void IconLoader::ReadIcon() {
200 static base::LazyInstance
<IconMapper
>::Leaky icon_mapper
=
201 LAZY_INSTANCE_INITIALIZER
;
202 int idr
= icon_mapper
.Get().Lookup(group_
, icon_size_
);
203 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
204 gfx::ImageSkia
image_skia(ResizeImage(*(rb
.GetImageNamed(idr
)).ToImageSkia(),
205 IconSizeToDIPSize(icon_size_
)));
206 image_skia
.MakeThreadSafe();
207 image_
.reset(new gfx::Image(image_skia
));
208 target_message_loop_
->PostTask(
209 FROM_HERE
, base::Bind(&IconLoader::NotifyDelegate
, this));