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/open_tabs_ui_delegate.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/base/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(url, icon_types_, 112 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::OpenTabsUIDelegate* open_tabs = sync_service ? 147 sync_service->GetOpenTabsUIDelegate() : NULL; 148 149 scoped_refptr<base::RefCountedMemory> response; 150 if (open_tabs && 151 open_tabs->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