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