icon_loader_chromeos.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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.
4
5#include "chrome/browser/icon_loader.h"
6
7#include <map>
8#include <string>
9#include <utility>
10
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"
27
28namespace {
29
30// Used with GenerateImageWithSize() to indicate that the image shouldn't be
31// resized.
32const int kDoNotResize = -1;
33
34struct IdrBySize {
35  int idr_small;
36  int idr_normal;
37  int idr_large;
38};
39
40// Performs mapping of <file extension, icon size> to icon resource IDs.
41class IconMapper {
42 public:
43  IconMapper();
44
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
47  // extension.
48  int Lookup(const std::string& extension, IconLoader::IconSize icon_size);
49
50 private:
51  typedef std::map<std::string, IdrBySize> ExtensionIconMap;
52
53  ExtensionIconMap extension_icon_map_;
54};
55
56const IdrBySize kAudioIdrs = {
57  IDR_FILE_MANAGER_IMG_FILETYPE_AUDIO,
58  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO,
59  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO
60};
61const IdrBySize kGenericIdrs = {
62  IDR_FILE_MANAGER_IMG_FILETYPE_GENERIC,
63  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC,
64  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC
65};
66const IdrBySize kImageIdrs = {
67  IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE,
68  IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE,
69  IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE
70};
71const IdrBySize kPdfIdrs = {
72  IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
73  IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
74  IDR_FILE_MANAGER_IMG_FILETYPE_PDF
75};
76const IdrBySize kVideoIdrs = {
77  IDR_FILE_MANAGER_IMG_FILETYPE_VIDEO,
78  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO,
79  IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO
80};
81
82IconMapper::IconMapper() {
83  // The code below should match translation in
84  // chrome/browser/resources/file_manager/js/file_manager.js
85  // chrome/browser/resources/file_manager/css/file_manager.css
86  // 'audio': /\.(mp3|m4a|oga|ogg|wav)$/i,
87  // 'html': /\.(html?)$/i,
88  // 'image': /\.(bmp|gif|jpe?g|ico|png|webp)$/i,
89  // 'pdf' : /\.(pdf)$/i,
90  // 'text': /\.(pod|rst|txt|log)$/i,
91  // 'video': /\.(mov|mp4|m4v|mpe?g4?|ogm|ogv|ogx|webm)$/i
92
93  const ExtensionIconMap::value_type kExtensionIdrBySizeData[] = {
94#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
95    std::make_pair(".m4a", kAudioIdrs),
96    std::make_pair(".mp3", kAudioIdrs),
97    std::make_pair(".pdf", kPdfIdrs),
98    std::make_pair(".3gp", kVideoIdrs),
99    std::make_pair(".avi", kVideoIdrs),
100    std::make_pair(".m4v", kVideoIdrs),
101    std::make_pair(".mov", kVideoIdrs),
102    std::make_pair(".mp4", kVideoIdrs),
103    std::make_pair(".mpeg", kVideoIdrs),
104    std::make_pair(".mpg", kVideoIdrs),
105    std::make_pair(".mpeg4", kVideoIdrs),
106    std::make_pair(".mpg4", kVideoIdrs),
107#endif
108    std::make_pair(".flac", kAudioIdrs),
109    std::make_pair(".oga", kAudioIdrs),
110    std::make_pair(".ogg", kAudioIdrs),
111    std::make_pair(".wav", kAudioIdrs),
112    std::make_pair(".bmp", kImageIdrs),
113    std::make_pair(".gif", kImageIdrs),
114    std::make_pair(".ico", kImageIdrs),
115    std::make_pair(".jpeg", kImageIdrs),
116    std::make_pair(".jpg", kImageIdrs),
117    std::make_pair(".png", kImageIdrs),
118    std::make_pair(".webp", kImageIdrs),
119    std::make_pair(".ogm", kVideoIdrs),
120    std::make_pair(".ogv", kVideoIdrs),
121    std::make_pair(".ogx", kVideoIdrs),
122    std::make_pair(".webm", kVideoIdrs),
123  };
124
125  const size_t kESize = arraysize(kExtensionIdrBySizeData);
126  ExtensionIconMap source(&kExtensionIdrBySizeData[0],
127                          &kExtensionIdrBySizeData[kESize]);
128  extension_icon_map_.swap(source);
129}
130
131int IconMapper::Lookup(const std::string& extension,
132                       IconLoader::IconSize icon_size) {
133  DCHECK(icon_size == IconLoader::SMALL ||
134         icon_size == IconLoader::NORMAL ||
135         icon_size == IconLoader::LARGE);
136  ExtensionIconMap::const_iterator it = extension_icon_map_.find(extension);
137  const IdrBySize& idrbysize =
138      ((it == extension_icon_map_.end()) ? kGenericIdrs : it->second);
139  int idr = -1;
140  switch (icon_size) {
141    case IconLoader::SMALL:  idr = idrbysize.idr_small;  break;
142    case IconLoader::NORMAL: idr = idrbysize.idr_normal; break;
143    case IconLoader::LARGE:  idr = idrbysize.idr_large;  break;
144    case IconLoader::ALL:
145    default:
146      NOTREACHED();
147  }
148  return idr;
149}
150
151// Returns a copy of |source| that is |dip_size| in width and height. If
152// |dip_size| is |kDoNotResize|, returns an unmodified copy of |source|.
153// |source| must be a square image (width == height).
154gfx::ImageSkia ResizeImage(const gfx::ImageSkia& source, int dip_size) {
155  DCHECK(!source.isNull());
156  DCHECK(source.width() == source.height());
157
158  if (dip_size == kDoNotResize || source.width() == dip_size)
159    return source;
160
161  return gfx::ImageSkiaOperations::CreateResizedImage(source,
162      skia::ImageOperations::RESIZE_BEST, gfx::Size(dip_size, dip_size));
163}
164
165int IconSizeToDIPSize(IconLoader::IconSize size) {
166  switch (size) {
167    case IconLoader::SMALL:  return 16;
168    case IconLoader::NORMAL: return 32;
169    case IconLoader::LARGE:  // fallthrough
170      // On ChromeOS, we consider LARGE to mean "the largest image we have."
171      // Since we have already chosen the largest applicable image resource, we
172      // return the image as-is.
173    case IconLoader::ALL:    // fallthrough
174    default:
175      return kDoNotResize;
176  }
177}
178
179}  // namespace
180
181// static
182IconGroupID IconLoader::ReadGroupIDFromFilepath(
183    const base::FilePath& filepath) {
184  return StringToLowerASCII(filepath.Extension());
185}
186
187bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
188  return false;
189}
190
191void IconLoader::ReadIcon() {
192  static base::LazyInstance<IconMapper>::Leaky icon_mapper =
193      LAZY_INSTANCE_INITIALIZER;
194  int idr = icon_mapper.Get().Lookup(group_, icon_size_);
195  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
196  gfx::ImageSkia image_skia(ResizeImage(*(rb.GetImageNamed(idr)).ToImageSkia(),
197                                        IconSizeToDIPSize(icon_size_)));
198  image_skia.MakeThreadSafe();
199  image_.reset(new gfx::Image(image_skia));
200  target_message_loop_->PostTask(
201      FROM_HERE, base::Bind(&IconLoader::NotifyDelegate, this));
202}
203