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