| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/favicon/ios/web_favicon_driver.h" |
| |
| #include "base/bind.h" |
| #include "components/favicon/core/favicon_url.h" |
| #include "components/favicon/ios/favicon_url_util.h" |
| #include "ios/web/public/browser_state.h" |
| #include "ios/web/public/favicon_status.h" |
| #include "ios/web/public/navigation_item.h" |
| #include "ios/web/public/navigation_manager.h" |
| #include "ios/web/public/web_state/web_state.h" |
| #include "ios/web/public/web_thread.h" |
| #include "skia/ext/skia_utils_ios.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/gfx/image/image.h" |
| |
| DEFINE_WEB_STATE_USER_DATA_KEY(favicon::WebFaviconDriver); |
| |
| // Callback for the download of favicon. |
| using ImageDownloadCallback = |
| base::Callback<void(int image_id, |
| int http_status_code, |
| const GURL& image_url, |
| const std::vector<SkBitmap>& bitmaps, |
| const std::vector<gfx::Size>& sizes)>; |
| |
| namespace favicon { |
| |
| // static |
| void WebFaviconDriver::CreateForWebState( |
| web::WebState* web_state, |
| FaviconService* favicon_service, |
| history::HistoryService* history_service, |
| bookmarks::BookmarkModel* bookmark_model) { |
| if (FromWebState(web_state)) |
| return; |
| |
| web_state->SetUserData(UserDataKey(), |
| new WebFaviconDriver(web_state, favicon_service, |
| history_service, bookmark_model)); |
| } |
| |
| void WebFaviconDriver::FetchFavicon(const GURL& url) { |
| fetch_favicon_url_ = url; |
| FaviconDriverImpl::FetchFavicon(url); |
| } |
| |
| gfx::Image WebFaviconDriver::GetFavicon() const { |
| web::NavigationItem* item = |
| web_state()->GetNavigationManager()->GetLastCommittedItem(); |
| return item ? item->GetFavicon().image : gfx::Image(); |
| } |
| |
| bool WebFaviconDriver::FaviconIsValid() const { |
| web::NavigationItem* item = |
| web_state()->GetNavigationManager()->GetLastCommittedItem(); |
| return item ? item->GetFavicon().valid : false; |
| } |
| |
| int WebFaviconDriver::StartDownload(const GURL& url, int max_image_size) { |
| if (WasUnableToDownloadFavicon(url)) { |
| DVLOG(1) << "Skip Failed FavIcon: " << url; |
| return 0; |
| } |
| |
| static int downloaded_image_count = 0; |
| int local_download_id = ++downloaded_image_count; |
| |
| ImageDownloadCallback local_image_callback = base::Bind( |
| &FaviconDriverImpl::DidDownloadFavicon, base::Unretained(this)); |
| GURL local_url(url); |
| |
| image_fetcher::IOSImageDataFetcherCallback local_callback = |
| ^(NSData* data, const image_fetcher::RequestMetadata& metadata) { |
| if (metadata.response_code == |
| image_fetcher::ImageDataFetcher::RESPONSE_CODE_INVALID) |
| return; |
| |
| std::vector<SkBitmap> frames; |
| std::vector<gfx::Size> sizes; |
| if (data) { |
| frames = skia::ImageDataToSkBitmaps(data); |
| for (const auto& frame : frames) { |
| sizes.push_back(gfx::Size(frame.width(), frame.height())); |
| } |
| } |
| local_image_callback.Run(local_download_id, metadata.response_code, |
| local_url, frames, sizes); |
| }; |
| image_fetcher_.FetchImageDataWebpDecoded(url, local_callback); |
| |
| return downloaded_image_count; |
| } |
| |
| bool WebFaviconDriver::IsOffTheRecord() { |
| DCHECK(web_state()); |
| return web_state()->GetBrowserState()->IsOffTheRecord(); |
| } |
| |
| GURL WebFaviconDriver::GetActiveURL() { |
| web::NavigationItem* item = |
| web_state()->GetNavigationManager()->GetVisibleItem(); |
| return item ? item->GetURL() : GURL(); |
| } |
| |
| void WebFaviconDriver::OnFaviconUpdated( |
| const GURL& page_url, |
| FaviconDriverObserver::NotificationIconType notification_icon_type, |
| const GURL& icon_url, |
| bool icon_url_changed, |
| const gfx::Image& image) { |
| // Check whether the active URL has changed since FetchFavicon() was called. |
| // On iOS, the active URL can change between calls to FetchFavicon(). For |
| // instance, FetchFavicon() is not synchronously called when the active URL |
| // changes as a result of CRWSessionController::goToEntry(). |
| web::NavigationItem* item = |
| web_state()->GetNavigationManager()->GetVisibleItem(); |
| if (!item || item->GetURL() != page_url) |
| return; |
| |
| NotifyFaviconUpdatedObservers(notification_icon_type, icon_url, |
| icon_url_changed, image); |
| } |
| |
| WebFaviconDriver::WebFaviconDriver(web::WebState* web_state, |
| FaviconService* favicon_service, |
| history::HistoryService* history_service, |
| bookmarks::BookmarkModel* bookmark_model) |
| : web::WebStateObserver(web_state), |
| FaviconDriverImpl(favicon_service, history_service, bookmark_model), |
| image_fetcher_(web_state->GetBrowserState()->GetRequestContext(), |
| web::WebThread::GetBlockingPool()) {} |
| |
| WebFaviconDriver::~WebFaviconDriver() { |
| } |
| |
| void WebFaviconDriver::FaviconUrlUpdated( |
| const std::vector<web::FaviconURL>& candidates) { |
| DCHECK(!candidates.empty()); |
| OnUpdateFaviconURL(GetActiveURL(), FaviconURLsFromWebFaviconURLs(candidates)); |
| } |
| |
| } // namespace favicon |