// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_FAVICON_HELPER_H__
#define CHROME_BROWSER_FAVICON_HELPER_H__
#pragma once
#include <map>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/common/favicon_url.h"
#include "chrome/common/ref_counted_util.h"
#include "content/browser/cancelable_request.h"
#include "content/browser/tab_contents/tab_contents_observer.h"
#include "googleurl/src/gurl.h"
#include "ui/gfx/favicon_size.h"
class NavigationEntry;
class Profile;
class RefCountedMemory;
class SkBitmap;
class TabContents;
// FaviconHelper is used to fetch the favicon for TabContents.
//
// FetchFavicon requests the favicon from the favicon service which in turn
// requests the favicon from the history database. At this point
// we only know the URL of the page, and not necessarily the url of the
// favicon. To ensure we handle reloading stale favicons as well as
// reloading a favicon on page reload we always request the favicon from
// history regardless of whether the NavigationEntry has a favicon.
//
// After the navigation two types of events are delivered (which is
// first depends upon who is faster): notification from the history
// db on our request for the favicon (OnFaviconDataForInitialURL),
// or a message from the renderer giving us the URL of the favicon for
// the page (SetFaviconURL).
// . If the history db has a valid up to date favicon for the page, we update
// the NavigationEntry and use the favicon.
// . When we receive the favicon url if it matches that of the NavigationEntry
// and the NavigationEntry's favicon is set, we do nothing (everything is
// ok).
// . On the other hand if the database does not know the favicon for url, or
// the favicon is out date, or the URL from the renderer does not match that
// NavigationEntry we proceed to DownloadFaviconOrAskHistory. Before we
// invoke DownloadFaviconOrAskHistory we wait until we've received both
// the favicon url and the callback from history. We wait to ensure we
// truly know both the favicon url and the state of the database.
//
// DownloadFaviconOrAskHistory does the following:
// . If we have a valid favicon, but it is expired we ask the renderer to
// download the favicon.
// . Otherwise we ask the history database to update the mapping from
// page url to favicon url and call us back with the favicon. Remember, it is
// possible for the db to already have the favicon, just not the mapping
// between page to favicon url. The callback for this is OnFaviconData.
//
// OnFaviconData either updates the favicon of the NavigationEntry (if the
// db knew about the favicon), or requests the renderer to download the
// favicon.
//
// When the renderer downloads the favicon SetFaviconImageData is invoked,
// at which point we update the favicon of the NavigationEntry and notify
// the database to save the favicon.
class FaviconHelper : public TabContentsObserver {
public:
enum Type {
FAVICON,
TOUCH,
};
FaviconHelper(TabContents* tab_contents, Type icon_type);
virtual ~FaviconHelper();
// Initiates loading the favicon for the specified url.
void FetchFavicon(const GURL& url);
// Initiates loading an image from given |image_url|. Returns a download id
// for caller to track the request. When download completes, |callback| is
// called with the three params: the download_id, a boolean flag to indicate
// whether the download succeeds and a SkBitmap as the downloaded image.
// Note that |image_size| is a hint for images with multiple sizes. The
// downloaded image is not resized to the given image_size. If 0 is passed,
// the first frame of the image is returned.
typedef Callback3<int, bool, const SkBitmap&>::Type ImageDownloadCallback;
int DownloadImage(const GURL& image_url,
int image_size,
history::IconType icon_type,
ImageDownloadCallback* callback);
// Message Handler. Must be public, because also called from
// PrerenderContents.
void OnUpdateFaviconURL(int32 page_id,
const std::vector<FaviconURL>& candidates);
protected:
// These virtual methods make FaviconHelper testable and are overridden by
// TestFaviconHelper
//
// Return the NavigationEntry for the active entry, or NULL if the active
// entries URL does not match that of the URL last passed to FetchFavicon.
virtual NavigationEntry* GetEntry();
// Asks the render to download favicon, returns the request id.
virtual int DownloadFavicon(const GURL& image_url, int image_size);
// Ask the favicon from history
virtual void UpdateFaviconMappingAndFetch(
const GURL& page_url,
const GURL& icon_url,
history::IconType icon_type,
CancelableRequestConsumerBase* consumer,
FaviconService::FaviconDataCallback* callback);
virtual void GetFavicon(
const GURL& icon_url,
history::IconType icon_type,
CancelableRequestConsumerBase* consumer,
FaviconService::FaviconDataCallback* callback);
virtual void GetFaviconForURL(
const GURL& page_url,
int icon_types,
CancelableRequestConsumerBase* consumer,
FaviconService::FaviconDataCallback* callback);
virtual void SetHistoryFavicon(const GURL& page_url,
const GURL& icon_url,
const std::vector<unsigned char>& image_data,
history::IconType icon_type);
virtual FaviconService* GetFaviconService();
// Returns true if the favicon should be saved.
virtual bool ShouldSaveFavicon(const GURL& url);
private:
friend class TestFaviconHelper; // For testing
struct DownloadRequest {
DownloadRequest();
DownloadRequest(const GURL& url,
const GURL& image_url,
ImageDownloadCallback* callback,
history::IconType icon_type);
GURL url;
GURL image_url;
ImageDownloadCallback* callback;
history::IconType icon_type;
};
// TabContentsObserver overrides.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnDidDownloadFavicon(int id,
const GURL& image_url,
bool errored,
const SkBitmap& image);
// See description above class for details.
void OnFaviconDataForInitialURL(FaviconService::Handle handle,
history::FaviconData favicon);
// If the favicon has expired, asks the renderer to download the favicon.
// Otherwise asks history to update the mapping between page url and icon
// url with a callback to OnFaviconData when done.
void DownloadFaviconOrAskHistory(const GURL& page_url,
const GURL& icon_url,
history::IconType icon_type);
// See description above class for details.
void OnFaviconData(FaviconService::Handle handle,
history::FaviconData favicon);
// Schedules a download for the specified entry. This adds the request to
// download_requests_.
int ScheduleDownload(const GURL& url,
const GURL& image_url,
int image_size,
history::IconType icon_type,
ImageDownloadCallback* callback);
// Sets the image data for the favicon. This is invoked asynchronously after
// we request the TabContents to download the favicon.
void SetFavicon(const GURL& url,
const GURL& icon_url,
const SkBitmap& image,
history::IconType icon_type);
// Converts the FAVICON's image data to an SkBitmap and sets it on the
// NavigationEntry.
// If the TabContents has a delegate, it is notified of the new favicon
// (INVALIDATE_FAVICON).
void UpdateFavicon(NavigationEntry* entry,
scoped_refptr<RefCountedMemory> data);
void UpdateFavicon(NavigationEntry* entry, const SkBitmap& image);
// Scales the image such that either the width and/or height is 16 pixels
// wide. Does nothing if the image is empty.
SkBitmap ConvertToFaviconSize(const SkBitmap& image);
void FetchFaviconInternal();
// Return the current candidate if any.
FaviconURL* current_candidate() {
return (urls_.size() > current_url_index_) ?
&urls_[current_url_index_] : NULL;
}
// Returns the preferred_icon_size according icon_types_, 0 means no
// preference.
int preferred_icon_size() {
return icon_types_ == history::FAVICON ? kFaviconSize : 0;
}
// Used for history requests.
CancelableRequestConsumer cancelable_consumer_;
// URL of the page we're requesting the favicon for.
GURL url_;
// Whether we got the initial response for the favicon back from the renderer.
// See "Favicon Details" in tab_contents.cc for more details.
bool got_favicon_from_history_;
// Whether the favicon is out of date. If true, it means history knows about
// the favicon, but we need to download the favicon because the icon has
// expired.
// See "Favicon Details" in tab_contents.cc for more details.
bool favicon_expired_;
// Requests to the renderer to download favicons.
typedef std::map<int, DownloadRequest> DownloadRequests;
DownloadRequests download_requests_;
// The combination of the supported icon types.
const int icon_types_;
// The prioritized favicon candidates from the page back from the renderer.
std::vector<FaviconURL> urls_;
// The current candidate's index in urls_.
size_t current_url_index_;
// The FaviconData from history.
history::FaviconData history_icon_;
DISALLOW_COPY_AND_ASSIGN(FaviconHelper);
};
#endif // CHROME_BROWSER_FAVICON_HELPER_H__