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) 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <cmath> 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/search/instant_io_context.h" 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/sync/open_tabs_ui_delegate.h" 17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "chrome/browser/sync/profile_sync_service.h" 18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "chrome/browser/sync/profile_sync_service_factory.h" 199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/common/favicon/favicon_url_parser.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/locale_settings.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/url_request/url_request.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/layout.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/webui/web_ui_util.h" 2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FaviconSource::IconRequest::IconRequest() 306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) : size_in_dip(gfx::kFaviconSize), device_scale_factor(1.0f) { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FaviconSource::IconRequest::IconRequest( 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::URLDataSource::GotDataCallback& cb, 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const GURL& path, 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int size, 376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) float scale) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : callback(cb), 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) request_path(path), 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_in_dip(size), 416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) device_scale_factor(scale) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FaviconSource::IconRequest::~IconRequest() { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FaviconSource::FaviconSource(Profile* profile, IconType type) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile->GetOriginalProfile()), 490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch icon_types_(type == FAVICON ? favicon_base::FAVICON 500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch : favicon_base::TOUCH_PRECOMPOSED_ICON | 510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch favicon_base::TOUCH_ICON | 520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch favicon_base::FAVICON) {} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FaviconSource::~FaviconSource() { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string FaviconSource::GetSource() const { 580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch return icon_types_ == favicon_base::FAVICON ? chrome::kChromeUIFaviconHost 590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch : chrome::kChromeUITouchIconHost; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FaviconSource::StartDataRequest( 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const std::string& path, 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int render_process_id, 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int render_frame_id, 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::URLDataSource::GotDataCallback& callback) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService* favicon_service = 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!favicon_service) { 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SendDefaultResponse(callback); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 749ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch chrome::ParsedFaviconPath parsed; 759ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch bool success = chrome::ParseFaviconPath(path, icon_types_, &parsed); 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!success) { 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SendDefaultResponse(callback); 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch GURL url(parsed.url); 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int desired_size_in_pixel = 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::ceil(parsed.size_in_dip * parsed.device_scale_factor); 849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch 859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch if (parsed.is_icon_url) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(michaelbai): Change GetRawFavicon to support combination of 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IconType. 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch favicon_service->GetRawFavicon( 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) url, 900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch favicon_base::FAVICON, 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch desired_size_in_pixel, 926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Bind( 936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) &FaviconSource::OnFaviconDataAvailable, 946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) base::Unretained(this), 956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) IconRequest( 966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback, url, parsed.size_in_dip, parsed.device_scale_factor)), 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &cancelable_task_tracker_); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Intercept requests for prepopulated pages. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) { 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (url.spec() == 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) { 1036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ui::ScaleFactor resource_scale_factor = 1046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ui::GetSupportedScaleFactor(parsed.device_scale_factor); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback.Run( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::kPrepopulatedPages[i].favicon_id, 1086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) resource_scale_factor)); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) favicon_service->GetRawFaviconForPageURL( 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch url, 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch icon_types_, 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch desired_size_in_pixel, 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind( 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) &FaviconSource::OnFaviconDataAvailable, 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Unretained(this), 1206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) IconRequest( 1216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback, url, parsed.size_in_dip, parsed.device_scale_factor)), 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &cancelable_task_tracker_); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FaviconSource::GetMimeType(const std::string&) const { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to explicitly return a mime type, otherwise if the user tries to 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // drag the image they get no extension. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "image/png"; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconSource::ShouldReplaceExistingSource() const { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Leave the existing DataSource in place, otherwise we'll drop any pending 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // requests on the floor. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FaviconSource::ShouldServiceRequest(const net::URLRequest* request) const { 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (request->url().SchemeIs(chrome::kChromeSearchScheme)) 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return InstantIOContext::ShouldServiceRequest(request); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return URLDataSource::ShouldServiceRequest(request); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FaviconSource::HandleMissingResource(const IconRequest& request) { 145d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch // If the favicon is not available, try to use the synced favicon. 146d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch ProfileSyncService* sync_service = 147d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_); 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) browser_sync::OpenTabsUIDelegate* open_tabs = sync_service ? 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) sync_service->GetOpenTabsUIDelegate() : NULL; 150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch 151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch scoped_refptr<base::RefCountedMemory> response; 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (open_tabs && 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) open_tabs->GetSyncedFaviconForPageURL(request.request_path.spec(), 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &response)) { 155d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch request.callback.Run(response.get()); 156d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch return true; 157d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch } 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::OnFaviconDataAvailable( 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const IconRequest& request, 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const favicon_base::FaviconRawBitmapResult& bitmap_result) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bitmap_result.is_valid()) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Forward the data along to the networking system. 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) request.callback.Run(bitmap_result.bitmap_data.get()); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (!HandleMissingResource(request)) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendDefaultResponse(request); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void FaviconSource::SendDefaultResponse( 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::URLDataSource::GotDataCallback& callback) { 1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SendDefaultResponse(IconRequest(callback, GURL(), 16, 1.0f)); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int favicon_index; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int resource_id; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (icon_request.size_in_dip) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 64: 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_64; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON_64; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 32: 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_32; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON_32; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) favicon_index = SIZE_16; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resource_id = IDR_DEFAULT_FAVICON; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::RefCountedMemory* default_favicon = 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) default_favicons_[favicon_index].get(); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!default_favicon) { 1986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ui::ScaleFactor resource_scale_factor = 1996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ui::GetSupportedScaleFactor(icon_request.device_scale_factor); 2006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) default_favicon = 2016d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( 2026d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) resource_id, resource_scale_factor); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_favicons_[favicon_index] = default_favicon; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_request.callback.Run(default_favicon); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 208