1 // Copyright (c) 2013 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 "android_webview/browser/icon_helper.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/hash.h" 10 #include "base/logging.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/web_contents.h" 13 #include "content/public/common/favicon_url.h" 14 #include "third_party/skia/include/core/SkBitmap.h" 15 #include "ui/gfx/size.h" 16 17 using content::BrowserThread; 18 using content::WebContents; 19 20 namespace android_webview { 21 22 IconHelper::IconHelper(WebContents* web_contents) 23 : WebContentsObserver(web_contents), 24 listener_(NULL), 25 missing_favicon_urls_() { 26 } 27 28 IconHelper::~IconHelper() { 29 } 30 31 void IconHelper::SetListener(Listener* listener) { 32 listener_ = listener; 33 } 34 35 void IconHelper::DownloadFaviconCallback( 36 int id, 37 int http_status_code, 38 const GURL& image_url, 39 const std::vector<SkBitmap>& bitmaps, 40 const std::vector<gfx::Size>& original_bitmap_sizes) { 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 42 if (http_status_code == 404) { 43 MarkUnableToDownloadFavicon(image_url); 44 return; 45 } 46 47 if (bitmaps.size() == 0) { 48 return; 49 } 50 51 // We can protentially have multiple frames of the icon 52 // in different sizes. We need more fine grain API spec 53 // to let clients pick out the frame they want. 54 55 // TODO(acleung): Pick the best icon to return based on size. 56 if (listener_) 57 listener_->OnReceivedIcon(image_url, bitmaps[0]); 58 } 59 60 void IconHelper::DidUpdateFaviconURL( 61 const std::vector<content::FaviconURL>& candidates) { 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 63 for (std::vector<content::FaviconURL>::const_iterator i = candidates.begin(); 64 i != candidates.end(); ++i) { 65 if (!i->icon_url.is_valid()) 66 continue; 67 68 switch(i->icon_type) { 69 case content::FaviconURL::FAVICON: 70 if ((listener_ && !listener_->ShouldDownloadFavicon(i->icon_url)) || 71 WasUnableToDownloadFavicon(i->icon_url)) { 72 break; 73 } 74 web_contents()->DownloadImage(i->icon_url, 75 true, // Is a favicon 76 0, // No maximum size 77 base::Bind( 78 &IconHelper::DownloadFaviconCallback, base::Unretained(this))); 79 break; 80 case content::FaviconURL::TOUCH_ICON: 81 if (listener_) 82 listener_->OnReceivedTouchIconUrl(i->icon_url.spec(), false); 83 break; 84 case content::FaviconURL::TOUCH_PRECOMPOSED_ICON: 85 if (listener_) 86 listener_->OnReceivedTouchIconUrl(i->icon_url.spec(), true); 87 break; 88 case content::FaviconURL::INVALID_ICON: 89 // Silently ignore it. Only trigger a callback on valid icons. 90 break; 91 default: 92 NOTREACHED(); 93 break; 94 } 95 } 96 } 97 98 void IconHelper::DidStartNavigationToPendingEntry( 99 const GURL& url, 100 content::NavigationController::ReloadType reload_type) { 101 if (reload_type == content::NavigationController::RELOAD_IGNORING_CACHE) 102 ClearUnableToDownloadFavicons(); 103 } 104 105 void IconHelper::MarkUnableToDownloadFavicon(const GURL& icon_url) { 106 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); 107 missing_favicon_urls_.insert(url_hash); 108 } 109 110 bool IconHelper::WasUnableToDownloadFavicon(const GURL& icon_url) const { 111 MissingFaviconURLHash url_hash = base::Hash(icon_url.spec()); 112 return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end(); 113 } 114 115 void IconHelper::ClearUnableToDownloadFavicons() { 116 missing_favicon_urls_.clear(); 117 } 118 119 } // namespace android_webview 120