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/favicon_source.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "chrome/browser/favicon/favicon_service_factory.h"
     11 #include "chrome/browser/history/top_sites.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/search/instant_io_context.h"
     14 #include "chrome/browser/sync/glue/session_model_associator.h"
     15 #include "chrome/browser/sync/profile_sync_service.h"
     16 #include "chrome/browser/sync/profile_sync_service_factory.h"
     17 #include "chrome/common/favicon/favicon_url_parser.h"
     18 #include "chrome/common/url_constants.h"
     19 #include "grit/locale_settings.h"
     20 #include "grit/ui_resources.h"
     21 #include "net/url_request/url_request.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 #include "ui/base/layout.h"
     24 #include "ui/base/resource/resource_bundle.h"
     25 #include "ui/webui/web_ui_util.h"
     26 
     27 FaviconSource::IconRequest::IconRequest()
     28     : size_in_dip(gfx::kFaviconSize),
     29       scale_factor(ui::SCALE_FACTOR_NONE) {
     30 }
     31 
     32 FaviconSource::IconRequest::IconRequest(
     33     const content::URLDataSource::GotDataCallback& cb,
     34     const GURL& path,
     35     int size,
     36     ui::ScaleFactor scale)
     37     : callback(cb),
     38       request_path(path),
     39       size_in_dip(size),
     40       scale_factor(scale) {
     41 }
     42 
     43 FaviconSource::IconRequest::~IconRequest() {
     44 }
     45 
     46 FaviconSource::FaviconSource(Profile* profile, IconType type)
     47     : profile_(profile->GetOriginalProfile()),
     48       icon_types_(type == FAVICON ? chrome::FAVICON :
     49           chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON |
     50           chrome::FAVICON) {
     51 }
     52 
     53 FaviconSource::~FaviconSource() {
     54 }
     55 
     56 std::string FaviconSource::GetSource() const {
     57   return icon_types_ == chrome::FAVICON ?
     58       chrome::kChromeUIFaviconHost : chrome::kChromeUITouchIconHost;
     59 }
     60 
     61 void FaviconSource::StartDataRequest(
     62     const std::string& path,
     63     int render_process_id,
     64     int render_view_id,
     65     const content::URLDataSource::GotDataCallback& callback) {
     66   FaviconService* favicon_service =
     67       FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
     68   if (!favicon_service) {
     69     SendDefaultResponse(callback);
     70     return;
     71   }
     72 
     73   chrome::ParsedFaviconPath parsed;
     74   bool success = chrome::ParseFaviconPath(path, icon_types_, &parsed);
     75   if (!success) {
     76     SendDefaultResponse(callback);
     77     return;
     78   }
     79 
     80   GURL url(parsed.url);
     81 
     82   if (parsed.is_icon_url) {
     83     // TODO(michaelbai): Change GetRawFavicon to support combination of
     84     // IconType.
     85     favicon_service->GetRawFavicon(
     86         url,
     87         chrome::FAVICON,
     88         parsed.size_in_dip,
     89         parsed.scale_factor,
     90         base::Bind(&FaviconSource::OnFaviconDataAvailable,
     91                    base::Unretained(this),
     92                    IconRequest(callback,
     93                                url,
     94                                parsed.size_in_dip,
     95                                parsed.scale_factor)),
     96         &cancelable_task_tracker_);
     97   } else {
     98     // Intercept requests for prepopulated pages.
     99     for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) {
    100       if (url.spec() ==
    101           l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) {
    102         callback.Run(
    103             ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
    104                 history::kPrepopulatedPages[i].favicon_id,
    105                 parsed.scale_factor));
    106         return;
    107       }
    108     }
    109 
    110     favicon_service->GetRawFaviconForURL(
    111         FaviconService::FaviconForURLParams(
    112             profile_, url, icon_types_, parsed.size_in_dip),
    113         parsed.scale_factor,
    114         base::Bind(&FaviconSource::OnFaviconDataAvailable,
    115                    base::Unretained(this),
    116                    IconRequest(callback,
    117                                url,
    118                                parsed.size_in_dip,
    119                                parsed.scale_factor)),
    120         &cancelable_task_tracker_);
    121   }
    122 }
    123 
    124 std::string FaviconSource::GetMimeType(const std::string&) const {
    125   // We need to explicitly return a mime type, otherwise if the user tries to
    126   // drag the image they get no extension.
    127   return "image/png";
    128 }
    129 
    130 bool FaviconSource::ShouldReplaceExistingSource() const {
    131   // Leave the existing DataSource in place, otherwise we'll drop any pending
    132   // requests on the floor.
    133   return false;
    134 }
    135 
    136 bool FaviconSource::ShouldServiceRequest(const net::URLRequest* request) const {
    137   if (request->url().SchemeIs(chrome::kChromeSearchScheme))
    138     return InstantIOContext::ShouldServiceRequest(request);
    139   return URLDataSource::ShouldServiceRequest(request);
    140 }
    141 
    142 bool FaviconSource::HandleMissingResource(const IconRequest& request) {
    143   // If the favicon is not available, try to use the synced favicon.
    144   ProfileSyncService* sync_service =
    145       ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_);
    146   browser_sync::SessionModelAssociator* associator = sync_service ?
    147       sync_service->GetSessionModelAssociator() : NULL;
    148 
    149   scoped_refptr<base::RefCountedMemory> response;
    150   if (associator &&
    151       associator->GetSyncedFaviconForPageURL(request.request_path.spec(),
    152                                              &response)) {
    153     request.callback.Run(response.get());
    154     return true;
    155   }
    156   return false;
    157 }
    158 
    159 void FaviconSource::OnFaviconDataAvailable(
    160     const IconRequest& request,
    161     const chrome::FaviconBitmapResult& bitmap_result) {
    162   if (bitmap_result.is_valid()) {
    163     // Forward the data along to the networking system.
    164     request.callback.Run(bitmap_result.bitmap_data.get());
    165   } else if (!HandleMissingResource(request)) {
    166     SendDefaultResponse(request);
    167   }
    168 }
    169 
    170 void FaviconSource::SendDefaultResponse(
    171     const content::URLDataSource::GotDataCallback& callback) {
    172   SendDefaultResponse(
    173       IconRequest(callback, GURL(), 16, ui::SCALE_FACTOR_100P));
    174 }
    175 
    176 void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) {
    177   int favicon_index;
    178   int resource_id;
    179   switch (icon_request.size_in_dip) {
    180     case 64:
    181       favicon_index = SIZE_64;
    182       resource_id = IDR_DEFAULT_FAVICON_64;
    183       break;
    184     case 32:
    185       favicon_index = SIZE_32;
    186       resource_id = IDR_DEFAULT_FAVICON_32;
    187       break;
    188     default:
    189       favicon_index = SIZE_16;
    190       resource_id = IDR_DEFAULT_FAVICON;
    191       break;
    192   }
    193   base::RefCountedMemory* default_favicon =
    194       default_favicons_[favicon_index].get();
    195 
    196   if (!default_favicon) {
    197     ui::ScaleFactor scale_factor = icon_request.scale_factor;
    198     default_favicon = ResourceBundle::GetSharedInstance()
    199         .LoadDataResourceBytesForScale(resource_id, scale_factor);
    200     default_favicons_[favicon_index] = default_favicon;
    201   }
    202 
    203   icon_request.callback.Run(default_favicon);
    204 }
    205