15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf_constants.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/weak_ptr.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxBitmapSize = 256;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// FaviconRawBitmapHandler fetchs all bitmaps with the 'icon' (or 'shortcut
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// icon')
23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// link tag, storing the one that best matches ash::kShelfSize.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These icon bitmaps are not resized and are not cached beyond the lifetime
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the class. Bitmaps larger than kMaxBitmapSize are ignored.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class FaviconRawBitmapHandler : public content::WebContentsObserver {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  FaviconRawBitmapHandler(content::WebContents* web_contents,
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                          LauncherFaviconLoader::Delegate* delegate)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : content::WebContentsObserver(web_contents),
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        delegate_(delegate),
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        weak_ptr_factory_(this) {}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~FaviconRawBitmapHandler() {}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SkBitmap& bitmap() const { return bitmap_; }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HasPendingDownloads() const;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // content::WebContentObserver implementation.
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void DidUpdateFaviconURL(
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<content::FaviconURL>& candidates) OVERRIDE;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void DidDownloadFavicon(
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int id,
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      int http_status_code,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& image_url,
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      const std::vector<SkBitmap>& bitmaps,
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      const std::vector<gfx::Size>& original_bitmap_sizes);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddFavicon(const GURL& image_url, const SkBitmap& new_bitmap);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LauncherFaviconLoader::Delegate* delegate_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::set<GURL> UrlSet;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Map of pending download urls.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UrlSet pending_requests_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Map of processed urls.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UrlSet processed_requests_;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current bitmap and source url.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap bitmap_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL bitmap_url_;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::WeakPtrFactory<FaviconRawBitmapHandler> weak_ptr_factory_;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(FaviconRawBitmapHandler);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FaviconRawBitmapHandler::DidUpdateFaviconURL(
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<content::FaviconURL>& candidates) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This function receives a complete list of faviocn urls for the page.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It may get called multiple times with the same list, and will also get
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // called any time an item is added or removed. As such, we track processed
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and pending urls, but only until they are removed from the list.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UrlSet new_pending, new_processed;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a map of valid favicon urls.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<GURL> urls;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<content::FaviconURL>::const_iterator iter;
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (iter = candidates.begin(); iter != candidates.end(); ++iter) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (iter->icon_type != content::FaviconURL::FAVICON)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url = iter->icon_url;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url.is_valid())
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urls.insert(url);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Preserve matching pending requests amd processed requests.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pending_requests_.find(url) != pending_requests_.end())
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_pending.insert(url);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (processed_requests_.find(url) != processed_requests_.end())
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_processed.insert(url);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_requests_ = new_pending;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  processed_requests_ = new_processed;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset bitmap_ if no longer valid (i.e. not in the list of urls).
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (urls.find(bitmap_url_) == urls.end()) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_url_ = GURL();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bitmap_.reset();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Request any new urls.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::set<GURL>::iterator iter = urls.begin();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != urls.end(); ++iter) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (processed_requests_.find(*iter) != processed_requests_.end())
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Skip already processed downloads.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pending_requests_.find(*iter) != pending_requests_.end())
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;  // Skip already pending downloads.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_requests_.insert(*iter);
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    web_contents()->DownloadImage(
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        *iter,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        true,  // is a favicon
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        0,     // no maximum size
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        base::Bind(&FaviconRawBitmapHandler::DidDownloadFavicon,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool FaviconRawBitmapHandler::HasPendingDownloads() const {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !pending_requests_.empty();
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FaviconRawBitmapHandler::DidDownloadFavicon(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int id,
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int http_status_code,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& image_url,
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_bitmap_sizes) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UrlSet::iterator iter = pending_requests_.find(image_url);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (iter == pending_requests_.end()) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Updates are received for all downloads; ignore unrequested urls.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_requests_.erase(iter);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Favicon bitmaps are ordered by decreasing width.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!bitmaps.empty())
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddFavicon(image_url, bitmaps[0]);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void FaviconRawBitmapHandler::AddFavicon(const GURL& image_url,
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                         const SkBitmap& new_bitmap) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  processed_requests_.insert(image_url);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_bitmap.height() > kMaxBitmapSize ||
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_bitmap.width() > kMaxBitmapSize)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
145a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (new_bitmap.height() < ash::kShelfSize)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bitmap_.isNull()) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We want the smallest icon that is large enough.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_bitmap.height() > bitmap_.height())
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bitmap_url_ = image_url;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bitmap_ = new_bitmap;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->FaviconUpdated();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LauncherFaviconLoader::LauncherFaviconLoader(Delegate* delegate,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             content::WebContents* web_contents)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : web_contents_(web_contents) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  favicon_handler_.reset(
165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new internal::FaviconRawBitmapHandler(web_contents, delegate));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LauncherFaviconLoader::~LauncherFaviconLoader() {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkBitmap LauncherFaviconLoader::GetFavicon() const {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return favicon_handler_->bitmap();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LauncherFaviconLoader::HasPendingDownloads() const {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return favicon_handler_->HasPendingDownloads();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
178