blob: e967e4e5bd82d9d2b87fb5ed8eee482b13705d0a [file] [log] [blame]
[email protected]25cc7502012-01-31 19:33:551// 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/lazy_instance.h"
[email protected]90fa2652012-04-24 16:18:3513#include "base/memory/ref_counted_memory.h"
[email protected]25cc7502012-01-31 19:33:5514#include "base/message_loop.h"
15#include "chrome/browser/icon_loader.h"
16#include "grit/component_extension_resources.h"
[email protected]25cc7502012-01-31 19:33:5517#include "third_party/skia/include/core/SkBitmap.h"
[email protected]c49201a2012-05-24 11:04:5718#include "ui/base/layout.h"
[email protected]25cc7502012-01-31 19:33:5519#include "ui/base/resource/resource_bundle.h"
[email protected]a7db88142012-03-14 14:43:0920#include "ui/gfx/canvas.h"
[email protected]25cc7502012-01-31 19:33:5521#include "ui/gfx/codec/png_codec.h"
22#include "ui/gfx/image/image.h"
[email protected]679facce2012-07-25 16:13:1223#include "ui/gfx/image/image_skia_operations.h"
[email protected]25cc7502012-01-31 19:33:5524#include "webkit/glue/image_decoder.h"
25
26namespace {
27
[email protected]679facce2012-07-25 16:13:1228// Used with GenerateImageWithSize() to indicate that the image shouldn't be
[email protected]25cc7502012-01-31 19:33:5529// resized.
30const int kDoNotResize = -1;
31
32struct IdrBySize {
33 int idr_small;
34 int idr_normal;
35 int idr_large;
36};
37
38// Performs mapping of <file extension, icon size> to icon resource IDs.
39class IconMapper {
40 public:
41 IconMapper();
42
43 // Lookup icon resource ID for a given filename |extension| and
44 // |icon_size|. Defaults to generic icons if there are no icons for the given
45 // extension.
46 int Lookup(const std::string& extension, IconLoader::IconSize icon_size);
47
48 private:
49 typedef std::map<std::string, IdrBySize> ExtensionIconMap;
50
51 ExtensionIconMap extension_icon_map_;
52};
53
54const IdrBySize kAudioIdrs = {
55 IDR_FILE_MANAGER_IMG_FILETYPE_AUDIO,
56 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO,
57 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_AUDIO
58};
59const IdrBySize kGenericIdrs = {
60 IDR_FILE_MANAGER_IMG_FILETYPE_GENERIC,
61 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC,
62 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_GENERIC
63};
[email protected]25cc7502012-01-31 19:33:5564const IdrBySize kImageIdrs = {
65 IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE,
66 IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE,
67 IDR_FILE_MANAGER_IMG_FILETYPE_IMAGE
68};
69const IdrBySize kPdfIdrs = {
70 IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
71 IDR_FILE_MANAGER_IMG_FILETYPE_PDF,
72 IDR_FILE_MANAGER_IMG_FILETYPE_PDF
73};
[email protected]25cc7502012-01-31 19:33:5574const IdrBySize kVideoIdrs = {
75 IDR_FILE_MANAGER_IMG_FILETYPE_VIDEO,
76 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO,
77 IDR_FILE_MANAGER_IMG_FILETYPE_LARGE_VIDEO
78};
79
80IconMapper::IconMapper() {
81 // The code below should match translation in
82 // chrome/browser/resources/file_manager/js/file_manager.js
83 // chrome/browser/resources/file_manager/css/file_manager.css
84 // 'audio': /\.(mp3|m4a|oga|ogg|wav)$/i,
85 // 'html': /\.(html?)$/i,
86 // 'image': /\.(bmp|gif|jpe?g|ico|png|webp)$/i,
87 // 'pdf' : /\.(pdf)$/i,
88 // 'text': /\.(pod|rst|txt|log)$/i,
89 // 'video': /\.(mov|mp4|m4v|mpe?g4?|ogm|ogv|ogx|webm)$/i
90
91 const ExtensionIconMap::value_type kExtensionIdrBySizeData[] = {
92#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
93 std::make_pair(".m4a", kAudioIdrs),
94 std::make_pair(".mp3", kAudioIdrs),
95 std::make_pair(".pdf", kPdfIdrs),
96 std::make_pair(".3gp", kVideoIdrs),
97 std::make_pair(".avi", kVideoIdrs),
98 std::make_pair(".m4v", kVideoIdrs),
99 std::make_pair(".mov", kVideoIdrs),
100 std::make_pair(".mp4", kVideoIdrs),
101 std::make_pair(".mpeg", kVideoIdrs),
102 std::make_pair(".mpg", kVideoIdrs),
103 std::make_pair(".mpeg4", kVideoIdrs),
104 std::make_pair(".mpg4", kVideoIdrs),
105#endif
106 std::make_pair(".flac", kAudioIdrs),
107 std::make_pair(".oga", kAudioIdrs),
108 std::make_pair(".ogg", kAudioIdrs),
109 std::make_pair(".wav", kAudioIdrs),
[email protected]25cc7502012-01-31 19:33:55110 std::make_pair(".bmp", kImageIdrs),
111 std::make_pair(".gif", kImageIdrs),
112 std::make_pair(".ico", kImageIdrs),
113 std::make_pair(".jpeg", kImageIdrs),
114 std::make_pair(".jpg", kImageIdrs),
115 std::make_pair(".png", kImageIdrs),
116 std::make_pair(".webp", kImageIdrs),
[email protected]25cc7502012-01-31 19:33:55117 std::make_pair(".ogm", kVideoIdrs),
118 std::make_pair(".ogv", kVideoIdrs),
119 std::make_pair(".ogx", kVideoIdrs),
120 std::make_pair(".webm", kVideoIdrs),
121 };
122
123 const size_t kESize = arraysize(kExtensionIdrBySizeData);
124 ExtensionIconMap source(&kExtensionIdrBySizeData[0],
125 &kExtensionIdrBySizeData[kESize]);
126 extension_icon_map_.swap(source);
127}
128
129int IconMapper::Lookup(const std::string& extension,
130 IconLoader::IconSize icon_size) {
131 DCHECK(icon_size == IconLoader::SMALL ||
132 icon_size == IconLoader::NORMAL ||
133 icon_size == IconLoader::LARGE);
134 ExtensionIconMap::const_iterator it = extension_icon_map_.find(extension);
135 const IdrBySize& idrbysize =
136 ((it == extension_icon_map_.end()) ? kGenericIdrs : it->second);
137 int idr = -1;
138 switch (icon_size) {
139 case IconLoader::SMALL: idr = idrbysize.idr_small; break;
140 case IconLoader::NORMAL: idr = idrbysize.idr_normal; break;
141 case IconLoader::LARGE: idr = idrbysize.idr_large; break;
142 case IconLoader::ALL:
143 default:
144 NOTREACHED();
145 }
146 return idr;
147}
148
[email protected]679facce2012-07-25 16:13:12149// Returns a copy of |source| that is |dip_size| in width and height. If
150// |dip_size| is |kDoNotResize|, returns an unmodified copy of |source|.
[email protected]25cc7502012-01-31 19:33:55151// |source| must be a square image (width == height).
[email protected]679facce2012-07-25 16:13:12152gfx::ImageSkia ResizeImage(const gfx::ImageSkia& source, int dip_size) {
[email protected]93079e02012-05-15 15:42:59153 DCHECK(!source.isNull());
154 DCHECK(source.width() == source.height());
[email protected]25cc7502012-01-31 19:33:55155
[email protected]679facce2012-07-25 16:13:12156 if (dip_size == kDoNotResize || source.width() == dip_size)
[email protected]93079e02012-05-15 15:42:59157 return source;
[email protected]25cc7502012-01-31 19:33:55158
[email protected]679facce2012-07-25 16:13:12159 return gfx::ImageSkiaOperations::CreateResizedImage(source,
[email protected]3a49e502012-08-16 21:24:41160 skia::ImageOperations::RESIZE_BEST, gfx::Size(dip_size, dip_size));
[email protected]25cc7502012-01-31 19:33:55161}
162
[email protected]679facce2012-07-25 16:13:12163int IconSizeToDIPSize(IconLoader::IconSize size) {
[email protected]25cc7502012-01-31 19:33:55164 switch (size) {
165 case IconLoader::SMALL: return 16;
166 case IconLoader::NORMAL: return 32;
167 case IconLoader::LARGE: // fallthrough
168 // On ChromeOS, we consider LARGE to mean "the largest image we have."
169 // Since we have already chosen the largest applicable image resource, we
170 // return the image as-is.
171 case IconLoader::ALL: // fallthrough
172 default:
173 return kDoNotResize;
174 }
175}
176
177} // namespace
178
179void IconLoader::ReadIcon() {
180 static base::LazyInstance<IconMapper>::Leaky icon_mapper =
181 LAZY_INSTANCE_INITIALIZER;
182 int idr = icon_mapper.Get().Lookup(group_, icon_size_);
183 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
[email protected]679facce2012-07-25 16:13:12184 const gfx::ImageSkia* image_skia = rb.GetImageNamed(idr).ToImageSkia();
[email protected]25cc7502012-01-31 19:33:55185 image_.reset(new gfx::Image(
[email protected]679facce2012-07-25 16:13:12186 ResizeImage(*image_skia, IconSizeToDIPSize(icon_size_))));
[email protected]25cc7502012-01-31 19:33:55187 target_message_loop_->PostTask(
188 FROM_HERE, base::Bind(&IconLoader::NotifyDelegate, this));
189}