favicon_source.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/favicon_source.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/web_ui_util.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/locale_settings.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/layout.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconSource::FaviconSource(Profile* profile, IconType type) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : DataSource(type == FAVICON ? chrome::kChromeUIFaviconHost : 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::kChromeUITouchIconHost, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoop::current()) { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(profile, type); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconSource::FaviconSource(Profile* profile, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconType type, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& source_name) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : DataSource(source_name, MessageLoop::current()) { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(profile, type); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconSource::~FaviconSource() { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::Init(Profile* profile, IconType type) { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_ = profile->GetOriginalProfile(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_types_ = type == FAVICON ? history::FAVICON : 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON | 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::FAVICON; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::StartDataRequest(const std::string& path, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_incognito, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int request_id) { 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService* favicon_service = 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!favicon_service || path.empty()) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDefaultResponse(IconRequest(request_id, 16, ui::SCALE_FACTOR_NONE)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size_in_dip = gfx::kFaviconSize; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_NONE; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService::Handle handle; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path.size() > 8 && 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (path.substr(0, 8) == "iconurl/" || path.substr(0, 8) == "iconurl@")) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t prefix_length = 8; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Optional scale factor appended to iconurl, which may be @1x or @2x. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path.at(7) == '@') { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t slash = path.find("/"); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string scale_str = path.substr(8, slash - 8); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_util::ParseScaleFactor(scale_str, &scale_factor); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefix_length = slash + 1; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(michaelbai): Change GetRawFavicon to support combination of 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IconType. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle = favicon_service->GetRawFavicon( 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL(path.substr(prefix_length)), 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::FAVICON, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_in_dip, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scale_factor, 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &cancelable_consumer_, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FaviconSource::OnFaviconDataAvailable, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GURL url; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path.size() > 5 && path.substr(0, 5) == "size/") { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t slash = path.find("/", 5); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t scale_delimiter = path.find("@", 5); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string size = path.substr(5, slash - 5); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_in_dip = atoi(size.c_str()); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(size_in_dip == 64 || size_in_dip == 32 || size_in_dip == 16) << 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "only 64x64, 32x32 and 16x16 icons are supported"; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Optional scale factor. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scale_delimiter != std::string::npos && scale_delimiter < slash) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(size_in_dip == 16); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string scale_str = path.substr(scale_delimiter + 1, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) slash - scale_delimiter - 1); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) web_ui_util::ParseScaleFactor(scale_str, &scale_factor); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = GURL(path.substr(slash + 1)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // URL requests prefixed with "origin/" are converted to a form with an 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // empty path and a valid scheme. (e.g., example.com --> 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // http://example.com/ or http://example.com/a --> http://example.com/) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (path.size() > 7 && path.substr(0, 7) == "origin/") { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string originalUrl = path.substr(7); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the original URL does not specify a scheme (e.g., example.com 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instead of http://example.com), add "http://" as a default. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GURL(originalUrl).has_scheme()) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) originalUrl = "http://" + originalUrl; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip the path beyond the top-level domain. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = GURL(originalUrl).GetOrigin(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url = GURL(path); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Intercept requests for prepopulated pages. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.spec() == 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(request_id, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::kPrepopulatedPages[i].favicon_id, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scale_factor)); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle = favicon_service->GetRawFaviconForURL( 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService::FaviconForURLParams( 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile_, 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_types_, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_in_dip, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &cancelable_consumer_), 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scale_factor, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&FaviconSource::OnFaviconDataAvailable, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Unretained(this))); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Attach the ChromeURLDataManager request ID to the history request. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancelable_consumer_.SetClientData(favicon_service, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handle, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconRequest(request_id, 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_in_dip, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scale_factor)); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FaviconSource::GetMimeType(const std::string&) const { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to explicitly return a mime type, otherwise if the user tries to 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // drag the image they get no extension. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "image/png"; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconSource::ShouldReplaceExistingSource() const { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Leave the existing DataSource in place, otherwise we'll drop any pending 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // requests on the floor. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::OnFaviconDataAvailable( 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService::Handle request_handle, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::FaviconBitmapResult& bitmap_result) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService* favicon_service = 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IconRequest& request = 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cancelable_consumer_.GetClientData(favicon_service, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_handle); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bitmap_result.is_valid()) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Forward the data along to the networking system. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(request.request_id, bitmap_result.bitmap_data); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDefaultResponse(request); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int favicon_index; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int resource_id; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (icon_request.size_in_dip) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 64: 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_64; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON_64; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 32: 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_32; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON_32; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_16; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::RefCountedMemory* default_favicon = default_favicons_[favicon_index]; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_favicon) { 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ScaleFactor scale_factor = icon_request.scale_factor; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_favicon = ResourceBundle::GetSharedInstance() 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .LoadDataResourceBytesForScale(resource_id, scale_factor); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_favicons_[favicon_index] = default_favicon; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendResponse(icon_request.request_id, default_favicon); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 203