Home | History | Annotate | Download | only in extensions
      1 // Copyright 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 "chrome/browser/extensions/favicon_downloader.h"
      6 
      7 #include "base/bind.h"
      8 #include "chrome/browser/favicon/favicon_tab_helper.h"
      9 #include "content/public/browser/web_contents.h"
     10 #include "content/public/common/favicon_url.h"
     11 #include "third_party/skia/include/core/SkBitmap.h"
     12 #include "ui/gfx/size.h"
     13 
     14 FaviconDownloader::FaviconDownloader(
     15   content::WebContents* web_contents,
     16   const std::vector<GURL>& extra_favicon_urls,
     17   FaviconDownloaderCallback callback)
     18   : content::WebContentsObserver(web_contents),
     19     got_favicon_urls_(false),
     20     extra_favicon_urls_(extra_favicon_urls),
     21     callback_(callback),
     22     weak_ptr_factory_(this) {
     23 }
     24 
     25 FaviconDownloader::~FaviconDownloader() {
     26 }
     27 
     28 void FaviconDownloader::Start() {
     29   FetchIcons(extra_favicon_urls_);
     30   // If the candidates aren't loaded, icons will be fetched when
     31   // DidUpdateFaviconURL() is called.
     32   std::vector<content::FaviconURL> favicon_tab_helper_urls =
     33       GetFaviconURLsFromWebContents();
     34   if (!favicon_tab_helper_urls.empty()) {
     35     got_favicon_urls_ = true;
     36     FetchIcons(favicon_tab_helper_urls);
     37   }
     38 }
     39 
     40 int FaviconDownloader::DownloadImage(const GURL& url) {
     41   return web_contents()->DownloadImage(
     42       url,
     43       true,  // is_favicon
     44       0,     // no max size
     45       base::Bind(&FaviconDownloader::DidDownloadFavicon,
     46                  weak_ptr_factory_.GetWeakPtr()));
     47 }
     48 
     49 std::vector<content::FaviconURL>
     50     FaviconDownloader::GetFaviconURLsFromWebContents() {
     51   FaviconTabHelper* favicon_tab_helper =
     52       web_contents() ? FaviconTabHelper::FromWebContents(web_contents()) : NULL;
     53   // If favicon_urls() is empty, we are guaranteed that DidUpdateFaviconURLs has
     54   // not yet been called for the current page's navigation.
     55   return favicon_tab_helper ? favicon_tab_helper->favicon_urls()
     56                             : std::vector<content::FaviconURL>();
     57 }
     58 
     59 void FaviconDownloader::FetchIcons(
     60     const std::vector<content::FaviconURL>& favicon_urls) {
     61   std::vector<GURL> urls;
     62   for (std::vector<content::FaviconURL>::const_iterator it =
     63            favicon_urls.begin();
     64        it != favicon_urls.end(); ++it) {
     65     if (it->icon_type != content::FaviconURL::INVALID_ICON)
     66       urls.push_back(it->icon_url);
     67   }
     68   FetchIcons(urls);
     69 }
     70 
     71 void FaviconDownloader::FetchIcons(const std::vector<GURL>& urls) {
     72   // Download icons; put their download ids into |in_progress_requests_| and
     73   // their urls into |processed_urls_|.
     74   for (std::vector<GURL>::const_iterator it = urls.begin();
     75        it != urls.end(); ++it) {
     76     // Only start the download if the url hasn't been processed before.
     77     if (processed_urls_.insert(*it).second)
     78       in_progress_requests_.insert(DownloadImage(*it));
     79   }
     80 
     81   // If no downloads were initiated, we can proceed directly to running the
     82   // callback.
     83   if (in_progress_requests_.empty() && got_favicon_urls_)
     84     callback_.Run(true, favicon_map_);
     85 }
     86 
     87 void FaviconDownloader::DidDownloadFavicon(
     88     int id,
     89     int http_status_code,
     90     const GURL& image_url,
     91     const std::vector<SkBitmap>& bitmaps,
     92     const std::vector<gfx::Size>& original_bitmap_sizes) {
     93   // Request may have been canceled by DidNavigateMainFrame().
     94   if (in_progress_requests_.erase(id) == 0)
     95     return;
     96 
     97   favicon_map_[image_url] = bitmaps;
     98 
     99   // Once all requests have been resolved, perform post-download tasks.
    100   if (in_progress_requests_.empty() && got_favicon_urls_)
    101     callback_.Run(true, favicon_map_);
    102 }
    103 
    104 // content::WebContentsObserver overrides:
    105 void FaviconDownloader::DidNavigateMainFrame(
    106     const content::LoadCommittedDetails& details,
    107     const content::FrameNavigateParams& params) {
    108   // Clear all pending requests.
    109   in_progress_requests_.clear();
    110   favicon_map_.clear();
    111   callback_.Run(false, favicon_map_);
    112 }
    113 
    114 void FaviconDownloader::DidUpdateFaviconURL(
    115     const std::vector<content::FaviconURL>& candidates) {
    116   // Only consider the first candidates we are given. This prevents pages that
    117   // change their favicon from spamming us.
    118   if (got_favicon_urls_)
    119     return;
    120 
    121   got_favicon_urls_ = true;
    122   FetchIcons(candidates);
    123 }
    124