Home | History | Annotate | Download | only in webui
      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/ui/webui/fileicon_source.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/bind.h"
      9 #include "base/callback.h"
     10 #include "base/files/file_path.h"
     11 #include "base/memory/ref_counted_memory.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/strings/string_split.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "chrome/browser/browser_process.h"
     16 #include "net/base/escape.h"
     17 #include "third_party/skia/include/core/SkBitmap.h"
     18 #include "ui/base/webui/web_ui_util.h"
     19 #include "ui/gfx/codec/png_codec.h"
     20 #include "ui/gfx/image/image.h"
     21 #include "ui/gfx/image/image_skia.h"
     22 #include "url/gurl.h"
     23 
     24 namespace {
     25 
     26 typedef std::map<std::string, IconLoader::IconSize> QueryIconSizeMap;
     27 
     28 // The path used in internal URLs to file icon data.
     29 const char kFileIconPath[] = "fileicon";
     30 
     31 // URL parameter specifying icon size.
     32 const char kIconSize[] = "iconsize";
     33 
     34 // URL parameter specifying scale factor.
     35 const char kScaleFactor[] = "scale";
     36 
     37 // Assuming the url is of the form '/path?query', convert the path portion into
     38 // a FilePath and return the resulting |file_path| and |query|.  The path
     39 // portion may have been encoded using encodeURIComponent().
     40 void GetFilePathAndQuery(const std::string& url,
     41                          base::FilePath* file_path,
     42                          std::string* query) {
     43   // We receive the url with chrome://fileicon/ stripped but GURL expects it.
     44   const GURL gurl("chrome://fileicon/" + url);
     45   std::string path = net::UnescapeURLComponent(
     46       gurl.path().substr(1), (net::UnescapeRule::URL_SPECIAL_CHARS |
     47                               net::UnescapeRule::SPACES));
     48 
     49   *file_path = base::FilePath::FromUTF8Unsafe(path);
     50   *file_path = file_path->NormalizePathSeparators();
     51   query->assign(gurl.query());
     52 }
     53 
     54 IconLoader::IconSize SizeStringToIconSize(const std::string& size_string) {
     55   if (size_string == "small") return IconLoader::SMALL;
     56   if (size_string == "large") return IconLoader::LARGE;
     57   // We default to NORMAL if we don't recognize the size_string. Including
     58   // size_string=="normal".
     59   return IconLoader::NORMAL;
     60 }
     61 
     62 // Simple parser for data on the query.
     63 void ParseQueryParams(const std::string& query,
     64                       float* scale_factor,
     65                       IconLoader::IconSize* icon_size) {
     66   typedef std::pair<std::string, std::string> KVPair;
     67   std::vector<KVPair> parameters;
     68   if (icon_size)
     69     *icon_size = IconLoader::NORMAL;
     70   if (scale_factor)
     71     *scale_factor = 1.0f;
     72   base::SplitStringIntoKeyValuePairs(query, '=', '&', &parameters);
     73   for (std::vector<KVPair>::const_iterator iter = parameters.begin();
     74        iter != parameters.end(); ++iter) {
     75     if (icon_size && iter->first == kIconSize)
     76       *icon_size = SizeStringToIconSize(iter->second);
     77     else if (scale_factor && iter->first == kScaleFactor)
     78       webui::ParseScaleFactor(iter->second, scale_factor);
     79   }
     80 }
     81 
     82 }  // namespace
     83 
     84 FileIconSource::IconRequestDetails::IconRequestDetails() : scale_factor(1.0f) {
     85 }
     86 
     87 FileIconSource::IconRequestDetails::~IconRequestDetails() {
     88 }
     89 
     90 FileIconSource::FileIconSource() {}
     91 
     92 FileIconSource::~FileIconSource() {}
     93 
     94 void FileIconSource::FetchFileIcon(
     95     const base::FilePath& path,
     96     float scale_factor,
     97     IconLoader::IconSize icon_size,
     98     const content::URLDataSource::GotDataCallback& callback) {
     99   IconManager* im = g_browser_process->icon_manager();
    100   gfx::Image* icon = im->LookupIconFromFilepath(path, icon_size);
    101 
    102   if (icon) {
    103     scoped_refptr<base::RefCountedBytes> icon_data(new base::RefCountedBytes);
    104     gfx::PNGCodec::EncodeBGRASkBitmap(
    105         icon->ToImageSkia()->GetRepresentation(scale_factor).sk_bitmap(),
    106         false,
    107         &icon_data->data());
    108 
    109     callback.Run(icon_data.get());
    110   } else {
    111     // Attach the ChromeURLDataManager request ID to the history request.
    112     IconRequestDetails details;
    113     details.callback = callback;
    114     details.scale_factor = scale_factor;
    115 
    116     // Icon was not in cache, go fetch it slowly.
    117     im->LoadIcon(path,
    118                  icon_size,
    119                  base::Bind(&FileIconSource::OnFileIconDataAvailable,
    120                             base::Unretained(this), details),
    121                  &cancelable_task_tracker_);
    122   }
    123 }
    124 
    125 std::string FileIconSource::GetSource() const {
    126   return kFileIconPath;
    127 }
    128 
    129 void FileIconSource::StartDataRequest(
    130     const std::string& url_path,
    131     int render_process_id,
    132     int render_frame_id,
    133     const content::URLDataSource::GotDataCallback& callback) {
    134   std::string query;
    135   base::FilePath file_path;
    136   IconLoader::IconSize icon_size;
    137   float scale_factor = 1.0f;
    138   GetFilePathAndQuery(url_path, &file_path, &query);
    139   ParseQueryParams(query, &scale_factor, &icon_size);
    140   FetchFileIcon(file_path, scale_factor, icon_size, callback);
    141 }
    142 
    143 std::string FileIconSource::GetMimeType(const std::string&) const {
    144   // Rely on image decoder inferring the correct type.
    145   return std::string();
    146 }
    147 
    148 void FileIconSource::OnFileIconDataAvailable(const IconRequestDetails& details,
    149                                              gfx::Image* icon) {
    150   if (icon) {
    151     scoped_refptr<base::RefCountedBytes> icon_data(new base::RefCountedBytes);
    152     gfx::PNGCodec::EncodeBGRASkBitmap(
    153         icon->ToImageSkia()->GetRepresentation(
    154             details.scale_factor).sk_bitmap(),
    155         false,
    156         &icon_data->data());
    157 
    158     details.callback.Run(icon_data.get());
    159   } else {
    160     // TODO(glen): send a dummy icon.
    161     details.callback.Run(NULL);
    162   }
    163 }
    164