1 // Copyright (c) 2012 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 "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h" 6 7 #include "ash/shelf/shelf_constants.h" 8 #include "base/logging.h" 9 #include "base/memory/weak_ptr.h" 10 #include "content/public/browser/render_view_host.h" 11 #include "content/public/browser/web_contents.h" 12 #include "content/public/browser/web_contents_observer.h" 13 #include "third_party/skia/include/core/SkBitmap.h" 14 #include "url/gurl.h" 15 16 namespace internal { 17 18 const int kMaxBitmapSize = 256; 19 20 //////////////////////////////////////////////////////////////////////////////// 21 // FaviconRawBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut 22 // icon') 23 // link tag, storing the one that best matches ash::kShelfSize. 24 // These icon bitmaps are not resized and are not cached beyond the lifetime 25 // of the class. Bitmaps larger than kMaxBitmapSize are ignored. 26 27 class FaviconRawBitmapHandler : public content::WebContentsObserver { 28 public: 29 FaviconRawBitmapHandler(content::WebContents* web_contents, 30 LauncherFaviconLoader::Delegate* delegate) 31 : content::WebContentsObserver(web_contents), 32 delegate_(delegate), 33 web_contents_(web_contents), 34 weak_ptr_factory_(this) {} 35 36 virtual ~FaviconRawBitmapHandler() {} 37 38 const SkBitmap& bitmap() const { return bitmap_; } 39 40 bool HasPendingDownloads() const; 41 42 // content::WebContentObserver implementation. 43 virtual void DidUpdateFaviconURL( 44 const std::vector<content::FaviconURL>& candidates) OVERRIDE; 45 46 private: 47 void DidDownloadFavicon( 48 int id, 49 int http_status_code, 50 const GURL& image_url, 51 const std::vector<SkBitmap>& bitmaps, 52 const std::vector<gfx::Size>& original_bitmap_sizes); 53 54 void AddFavicon(const GURL& image_url, const SkBitmap& new_bitmap); 55 56 LauncherFaviconLoader::Delegate* delegate_; 57 58 content::WebContents* web_contents_; 59 60 typedef std::set<GURL> UrlSet; 61 // Map of pending download urls. 62 UrlSet pending_requests_; 63 // Map of processed urls. 64 UrlSet processed_requests_; 65 // Current bitmap and source url. 66 SkBitmap bitmap_; 67 GURL bitmap_url_; 68 69 base::WeakPtrFactory<FaviconRawBitmapHandler> weak_ptr_factory_; 70 71 DISALLOW_COPY_AND_ASSIGN(FaviconRawBitmapHandler); 72 }; 73 74 void FaviconRawBitmapHandler::DidUpdateFaviconURL( 75 const std::vector<content::FaviconURL>& candidates) { 76 // This function receives a complete list of faviocn urls for the page. 77 // It may get called multiple times with the same list, and will also get 78 // called any time an item is added or removed. As such, we track processed 79 // and pending urls, but only until they are removed from the list. 80 UrlSet new_pending, new_processed; 81 // Create a map of valid favicon urls. 82 std::set<GURL> urls; 83 std::vector<content::FaviconURL>::const_iterator iter; 84 for (iter = candidates.begin(); iter != candidates.end(); ++iter) { 85 if (iter->icon_type != content::FaviconURL::FAVICON) 86 continue; 87 const GURL& url = iter->icon_url; 88 if (url.is_valid()) 89 urls.insert(url); 90 // Preserve matching pending requests amd processed requests. 91 if (pending_requests_.find(url) != pending_requests_.end()) 92 new_pending.insert(url); 93 if (processed_requests_.find(url) != processed_requests_.end()) 94 new_processed.insert(url); 95 } 96 pending_requests_ = new_pending; 97 processed_requests_ = new_processed; 98 // Reset bitmap_ if no longer valid (i.e. not in the list of urls). 99 if (urls.find(bitmap_url_) == urls.end()) { 100 bitmap_url_ = GURL(); 101 bitmap_.reset(); 102 } 103 // Request any new urls. 104 for (std::set<GURL>::iterator iter = urls.begin(); 105 iter != urls.end(); ++iter) { 106 if (processed_requests_.find(*iter) != processed_requests_.end()) 107 continue; // Skip already processed downloads. 108 if (pending_requests_.find(*iter) != pending_requests_.end()) 109 continue; // Skip already pending downloads. 110 pending_requests_.insert(*iter); 111 web_contents_->DownloadImage( 112 *iter, 113 true, // is a favicon 114 0, // no maximum size 115 base::Bind(&FaviconRawBitmapHandler::DidDownloadFavicon, 116 weak_ptr_factory_.GetWeakPtr())); 117 } 118 } 119 120 bool FaviconRawBitmapHandler::HasPendingDownloads() const { 121 return !pending_requests_.empty(); 122 } 123 124 void FaviconRawBitmapHandler::DidDownloadFavicon( 125 int id, 126 int http_status_code, 127 const GURL& image_url, 128 const std::vector<SkBitmap>& bitmaps, 129 const std::vector<gfx::Size>& original_bitmap_sizes) { 130 UrlSet::iterator iter = pending_requests_.find(image_url); 131 if (iter == pending_requests_.end()) { 132 // Updates are received for all downloads; ignore unrequested urls. 133 return; 134 } 135 pending_requests_.erase(iter); 136 137 // Favicon bitmaps are ordered by decreasing width. 138 if (!bitmaps.empty()) 139 AddFavicon(image_url, bitmaps[0]); 140 } 141 142 void FaviconRawBitmapHandler::AddFavicon(const GURL& image_url, 143 const SkBitmap& new_bitmap) { 144 processed_requests_.insert(image_url); 145 if (new_bitmap.height() > kMaxBitmapSize || 146 new_bitmap.width() > kMaxBitmapSize) 147 return; 148 if (new_bitmap.height() < ash::kShelfSize) 149 return; 150 if (!bitmap_.isNull()) { 151 // We want the smallest icon that is large enough. 152 if (new_bitmap.height() > bitmap_.height()) 153 return; 154 } 155 bitmap_url_ = image_url; 156 bitmap_ = new_bitmap; 157 delegate_->FaviconUpdated(); 158 } 159 160 } // namespace internal 161 162 //////////////////////////////////////////////////////////////////////////////// 163 164 LauncherFaviconLoader::LauncherFaviconLoader(Delegate* delegate, 165 content::WebContents* web_contents) 166 : web_contents_(web_contents) { 167 favicon_handler_.reset( 168 new internal::FaviconRawBitmapHandler(web_contents, delegate)); 169 } 170 171 LauncherFaviconLoader::~LauncherFaviconLoader() { 172 } 173 174 SkBitmap LauncherFaviconLoader::GetFavicon() const { 175 return favicon_handler_->bitmap(); 176 } 177 178 bool LauncherFaviconLoader::HasPendingDownloads() const { 179 return favicon_handler_->HasPendingDownloads(); 180 } 181