| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "ios/chrome/browser/ui/webui/history/favicon_source.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "components/favicon_base/favicon_url_parser.h" | |
| 13 #include "components/history/core/browser/top_sites.h" | |
| 14 #include "components/keyed_service/core/service_access_type.h" | |
| 15 #include "components/sync/driver/sync_service.h" | |
| 16 #include "components/sync_sessions/open_tabs_ui_delegate.h" | |
| 17 #include "net/url_request/url_request.h" | |
| 18 #include "ui/base/l10n/l10n_util.h" | |
| 19 #include "ui/base/layout.h" | |
| 20 #include "ui/base/resource/resource_bundle.h" | |
| 21 #include "ui/base/webui/web_ui_util.h" | |
| 22 #include "ui/resources/grit/ui_resources.h" | |
| 23 | |
| 24 FaviconSource::IconRequest::IconRequest() | |
| 25 : size_in_dip(gfx::kFaviconSize), device_scale_factor(1.0f) {} | |
| 26 | |
| 27 FaviconSource::IconRequest::IconRequest( | |
| 28 const web::URLDataSourceIOS::GotDataCallback& cb, | |
| 29 const GURL& path, | |
| 30 int size, | |
| 31 float scale) | |
| 32 : callback(cb), | |
| 33 request_path(path), | |
| 34 size_in_dip(size), | |
| 35 device_scale_factor(scale) {} | |
| 36 | |
| 37 FaviconSource::IconRequest::IconRequest(const IconRequest& other) = default; | |
| 38 | |
| 39 FaviconSource::IconRequest::~IconRequest() {} | |
| 40 | |
| 41 FaviconSource::FaviconSource(favicon::FaviconService* favicon_service, | |
| 42 const scoped_refptr<history::TopSites>& top_sites, | |
| 43 syncer::SyncService* sync_service) | |
| 44 : favicon_service_(favicon_service), | |
| 45 top_sites_(top_sites), | |
| 46 sync_service_(sync_service) {} | |
| 47 | |
| 48 FaviconSource::~FaviconSource() {} | |
| 49 | |
| 50 std::string FaviconSource::GetSource() const { | |
| 51 return std::string("touch-icon"); | |
| 52 } | |
| 53 | |
| 54 void FaviconSource::StartDataRequest( | |
| 55 const std::string& path, | |
| 56 const web::URLDataSourceIOS::GotDataCallback& callback) { | |
| 57 if (!favicon_service_) { | |
| 58 SendDefaultResponse(callback); | |
| 59 return; | |
| 60 } | |
| 61 | |
| 62 const int kIconTypes = favicon_base::TOUCH_PRECOMPOSED_ICON | | |
| 63 favicon_base::TOUCH_ICON | favicon_base::FAVICON; | |
| 64 chrome::ParsedFaviconPath parsed; | |
| 65 bool success = chrome::ParseFaviconPath(path, kIconTypes, &parsed); | |
| 66 if (!success) { | |
| 67 SendDefaultResponse(callback); | |
| 68 return; | |
| 69 } | |
| 70 | |
| 71 GURL url(parsed.url); | |
| 72 int desired_size_in_pixel = | |
| 73 std::ceil(parsed.size_in_dip * parsed.device_scale_factor); | |
| 74 | |
| 75 if (parsed.is_icon_url) { | |
| 76 // TODO(michaelbai): Change GetRawFavicon to support combination of | |
| 77 // IconType. | |
| 78 favicon_service_->GetRawFavicon( | |
| 79 url, favicon_base::FAVICON, desired_size_in_pixel, | |
| 80 base::Bind(&FaviconSource::OnFaviconDataAvailable, | |
| 81 base::Unretained(this), | |
| 82 IconRequest(callback, url, parsed.size_in_dip, | |
| 83 parsed.device_scale_factor)), | |
| 84 &cancelable_task_tracker_); | |
| 85 } else { | |
| 86 // Intercept requests for prepopulated pages if TopSites exists. | |
| 87 if (top_sites_) { | |
| 88 for (const auto& prepopulated_page : top_sites_->GetPrepopulatedPages()) { | |
| 89 if (url == prepopulated_page.most_visited.url) { | |
| 90 ui::ScaleFactor resource_scale_factor = | |
| 91 ui::GetSupportedScaleFactor(parsed.device_scale_factor); | |
| 92 callback.Run( | |
| 93 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( | |
| 94 prepopulated_page.favicon_id, resource_scale_factor)); | |
| 95 return; | |
| 96 } | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 favicon_service_->GetRawFaviconForPageURL( | |
| 101 url, kIconTypes, desired_size_in_pixel, | |
| 102 base::Bind(&FaviconSource::OnFaviconDataAvailable, | |
| 103 base::Unretained(this), | |
| 104 IconRequest(callback, url, parsed.size_in_dip, | |
| 105 parsed.device_scale_factor)), | |
| 106 &cancelable_task_tracker_); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 std::string FaviconSource::GetMimeType(const std::string&) const { | |
| 111 // We need to explicitly return a mime type, otherwise if the user tries to | |
| 112 // drag the image they get no extension. | |
| 113 return "image/png"; | |
| 114 } | |
| 115 | |
| 116 bool FaviconSource::ShouldReplaceExistingSource() const { | |
| 117 // Leave the existing DataSource in place, otherwise we'll drop any pending | |
| 118 // requests on the floor. | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 bool FaviconSource::HandleMissingResource(const IconRequest& request) { | |
| 123 // If the favicon is not available, try to use the synced favicon. | |
| 124 sync_sessions::OpenTabsUIDelegate* open_tabs = | |
| 125 sync_service_ ? sync_service_->GetOpenTabsUIDelegate() : nullptr; | |
| 126 | |
| 127 scoped_refptr<base::RefCountedMemory> response; | |
| 128 if (open_tabs && | |
| 129 open_tabs->GetSyncedFaviconForPageURL(request.request_path.spec(), | |
| 130 &response)) { | |
| 131 request.callback.Run(response.get()); | |
| 132 return true; | |
| 133 } | |
| 134 return false; | |
| 135 } | |
| 136 | |
| 137 void FaviconSource::OnFaviconDataAvailable( | |
| 138 const IconRequest& request, | |
| 139 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | |
| 140 if (bitmap_result.is_valid()) { | |
| 141 // Forward the data along to the networking system. | |
| 142 request.callback.Run(bitmap_result.bitmap_data.get()); | |
| 143 } else if (!HandleMissingResource(request)) { | |
| 144 SendDefaultResponse(request); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 void FaviconSource::SendDefaultResponse( | |
| 149 const web::URLDataSourceIOS::GotDataCallback& callback) { | |
| 150 SendDefaultResponse(IconRequest(callback, GURL(), 16, 1.0f)); | |
| 151 } | |
| 152 | |
| 153 void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) { | |
| 154 int favicon_index; | |
| 155 int resource_id; | |
| 156 switch (icon_request.size_in_dip) { | |
| 157 case 64: | |
| 158 favicon_index = SIZE_64; | |
| 159 resource_id = IDR_DEFAULT_FAVICON_64; | |
| 160 break; | |
| 161 case 32: | |
| 162 favicon_index = SIZE_32; | |
| 163 resource_id = IDR_DEFAULT_FAVICON_32; | |
| 164 break; | |
| 165 default: | |
| 166 favicon_index = SIZE_16; | |
| 167 resource_id = IDR_DEFAULT_FAVICON; | |
| 168 break; | |
| 169 } | |
| 170 base::RefCountedMemory* default_favicon = | |
| 171 default_favicons_[favicon_index].get(); | |
| 172 | |
| 173 if (!default_favicon) { | |
| 174 ui::ScaleFactor resource_scale_factor = | |
| 175 ui::GetSupportedScaleFactor(icon_request.device_scale_factor); | |
| 176 default_favicon = | |
| 177 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( | |
| 178 resource_id, resource_scale_factor); | |
| 179 default_favicons_[favicon_index] = default_favicon; | |
| 180 } | |
| 181 | |
| 182 icon_request.callback.Run(default_favicon); | |
| 183 } | |
| OLD | NEW |