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 27FaviconSource::IconRequest::IconRequest() 28 : size_in_dip(gfx::kFaviconSize), 29 scale_factor(ui::SCALE_FACTOR_NONE) { 30} 31 32FaviconSource::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 43FaviconSource::IconRequest::~IconRequest() { 44} 45 46FaviconSource::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 53FaviconSource::~FaviconSource() { 54} 55 56std::string FaviconSource::GetSource() const { 57 return icon_types_ == chrome::FAVICON ? 58 chrome::kChromeUIFaviconHost : chrome::kChromeUITouchIconHost; 59} 60 61void 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 124std::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 130bool 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 136bool 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 142bool 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 159void 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 170void FaviconSource::SendDefaultResponse( 171 const content::URLDataSource::GotDataCallback& callback) { 172 SendDefaultResponse( 173 IconRequest(callback, GURL(), 16, ui::SCALE_FACTOR_100P)); 174} 175 176void 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