12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "android_webview/browser/icon_helper.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/hash.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/favicon_url.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/size.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::WebContents;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace android_webview {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IconHelper::IconHelper(WebContents* web_contents)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : WebContentsObserver(web_contents),
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      listener_(NULL),
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      missing_favicon_urls_() {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)IconHelper::~IconHelper() {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IconHelper::SetListener(Listener* listener) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener_ = listener;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void IconHelper::DownloadFaviconCallback(
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int id,
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int http_status_code,
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const GURL& image_url,
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_bitmap_sizes) {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (http_status_code == 404) {
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    MarkUnableToDownloadFavicon(image_url);
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (bitmaps.size() == 0) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We can protentially have multiple frames of the icon
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // in different sizes. We need more fine grain API spec
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to let clients pick out the frame they want.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(acleung): Pick the best icon to return based on size.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (listener_)
57ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    listener_->OnReceivedIcon(image_url, bitmaps[0]);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void IconHelper::DidUpdateFaviconURL(
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<content::FaviconURL>& candidates) {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<content::FaviconURL>::const_iterator i = candidates.begin();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i != candidates.end(); ++i) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!i->icon_url.is_valid())
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch(i->icon_type) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case content::FaviconURL::FAVICON:
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        if ((listener_ && !listener_->ShouldDownloadFavicon(i->icon_url)) ||
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            WasUnableToDownloadFavicon(i->icon_url)) {
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          break;
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        }
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        web_contents()->DownloadImage(i->icon_url,
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            true,  // Is a favicon
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            0,  // No maximum size
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::Bind(
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                &IconHelper::DownloadFaviconCallback, base::Unretained(this)));
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case content::FaviconURL::TOUCH_ICON:
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (listener_)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          listener_->OnReceivedTouchIconUrl(i->icon_url.spec(), false);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case content::FaviconURL::TOUCH_PRECOMPOSED_ICON:
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (listener_)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          listener_->OnReceivedTouchIconUrl(i->icon_url.spec(), true);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case content::FaviconURL::INVALID_ICON:
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Silently ignore it. Only trigger a callback on valid icons.
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NOTREACHED();
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid IconHelper::DidStartNavigationToPendingEntry(
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const GURL& url,
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    content::NavigationController::ReloadType reload_type) {
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (reload_type == content::NavigationController::RELOAD_IGNORING_CACHE)
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ClearUnableToDownloadFavicons();
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid IconHelper::MarkUnableToDownloadFavicon(const GURL& icon_url) {
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  missing_favicon_urls_.insert(url_hash);
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool IconHelper::WasUnableToDownloadFavicon(const GURL& icon_url) const {
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MissingFaviconURLHash url_hash = base::Hash(icon_url.spec());
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return missing_favicon_urls_.find(url_hash) != missing_favicon_urls_.end();
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid IconHelper::ClearUnableToDownloadFavicons() {
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  missing_favicon_urls_.clear();
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace android_webview
120