Home | History | Annotate | Download | only in browser
      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 
     28 namespace {
     29 
     30 // Used with GenerateImageWithSize() to indicate that the image shouldn't be
     31 // resized.
     32 const int kDoNotResize = -1;
     33 
     34 struct 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.
     41 class 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 
     56 const IdrBySize kAudioIdrs = {
     57   IDR_FILETYPE_AUDIO,
     58   IDR_FILETYPE_LARGE_AUDIO,
     59   IDR_FILETYPE_LARGE_AUDIO
     60 };
     61 const IdrBySize kGenericIdrs = {
     62   IDR_FILETYPE_GENERIC,
     63   IDR_FILETYPE_LARGE_GENERIC,
     64   IDR_FILETYPE_LARGE_GENERIC
     65 };
     66 const IdrBySize kImageIdrs = {
     67   IDR_FILETYPE_IMAGE,
     68   IDR_FILETYPE_IMAGE,
     69   IDR_FILETYPE_IMAGE
     70 };
     71 #if defined(USE_PROPRIETARY_CODECS)
     72 const IdrBySize kPdfIdrs = {
     73   IDR_FILETYPE_PDF,
     74   IDR_FILETYPE_PDF,
     75   IDR_FILETYPE_PDF
     76 };
     77 #endif
     78 const IdrBySize kVideoIdrs = {
     79   IDR_FILETYPE_VIDEO,
     80   IDR_FILETYPE_LARGE_VIDEO,
     81   IDR_FILETYPE_LARGE_VIDEO
     82 };
     83 
     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
     94 
     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),
    109 #endif
    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),
    125   };
    126 
    127   const size_t kESize = arraysize(kExtensionIdrBySizeData);
    128   ExtensionIconMap source(&kExtensionIdrBySizeData[0],
    129                           &kExtensionIdrBySizeData[kESize]);
    130   extension_icon_map_.swap(source);
    131 }
    132 
    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);
    141   int idr = -1;
    142   switch (icon_size) {
    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:
    147     default:
    148       NOTREACHED();
    149   }
    150   return idr;
    151 }
    152 
    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());
    159 
    160   if (dip_size == kDoNotResize || source.width() == dip_size)
    161     return source;
    162 
    163   return gfx::ImageSkiaOperations::CreateResizedImage(source,
    164       skia::ImageOperations::RESIZE_BEST, gfx::Size(dip_size, dip_size));
    165 }
    166 
    167 int IconSizeToDIPSize(IconLoader::IconSize size) {
    168   switch (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
    176     default:
    177       return kDoNotResize;
    178   }
    179 }
    180 
    181 }  // namespace
    182 
    183 // static
    184 IconGroupID IconLoader::ReadGroupIDFromFilepath(
    185     const base::FilePath& filepath) {
    186   return base::StringToLowerASCII(filepath.Extension());
    187 }
    188 
    189 // static
    190 bool IconLoader::IsIconMutableFromFilepath(const base::FilePath&) {
    191   return false;
    192 }
    193 
    194 // static
    195 content::BrowserThread::ID IconLoader::ReadIconThreadID() {
    196   return content::BrowserThread::FILE;
    197 }
    198 
    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));
    210 }
    211