| Index: chrome/browser/favicon_tab_helper.cc
|
| ===================================================================
|
| --- chrome/browser/favicon_tab_helper.cc (revision 80859)
|
| +++ chrome/browser/favicon_tab_helper.cc (working copy)
|
| @@ -1,398 +0,0 @@
|
| -// 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.
|
| -
|
| -#include "chrome/browser/favicon_tab_helper.h"
|
| -
|
| -#include "build/build_config.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/callback.h"
|
| -#include "base/memory/ref_counted_memory.h"
|
| -#include "chrome/browser/bookmarks/bookmark_model.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/common/render_messages.h"
|
| -#include "content/browser/renderer_host/render_view_host.h"
|
| -#include "content/browser/tab_contents/navigation_controller.h"
|
| -#include "content/browser/tab_contents/navigation_entry.h"
|
| -#include "content/browser/tab_contents/tab_contents_delegate.h"
|
| -#include "content/browser/tab_contents/tab_contents.h"
|
| -#include "content/browser/webui/web_ui.h"
|
| -#include "skia/ext/image_operations.h"
|
| -#include "ui/gfx/codec/png_codec.h"
|
| -#include "ui/gfx/favicon_size.h"
|
| -
|
| -FaviconTabHelper::FaviconTabHelper(TabContents* tab_contents)
|
| - : TabContentsObserver(tab_contents),
|
| - got_favicon_url_(false),
|
| - got_favicon_from_history_(false),
|
| - favicon_expired_(false) {
|
| -}
|
| -
|
| -FaviconTabHelper::~FaviconTabHelper() {
|
| - SkBitmap empty_image;
|
| -
|
| - // Call pending download callbacks with error to allow caller to clean up.
|
| - for (DownloadRequests::iterator i = download_requests_.begin();
|
| - i != download_requests_.end(); ++i) {
|
| - if (i->second.callback) {
|
| - i->second.callback->Run(i->first, true, empty_image);
|
| - }
|
| - }
|
| -}
|
| -
|
| -SkBitmap FaviconTabHelper::GetFavicon() const {
|
| - // Like GetTitle(), we also want to use the favicon for the last committed
|
| - // entry rather than a pending navigation entry.
|
| - NavigationEntry* entry = tab_contents()->controller().GetTransientEntry();
|
| - if (entry)
|
| - return entry->favicon().bitmap();
|
| -
|
| - entry = tab_contents()->controller().GetLastCommittedEntry();
|
| - if (entry)
|
| - return entry->favicon().bitmap();
|
| - return SkBitmap();
|
| -}
|
| -
|
| -bool FaviconTabHelper::FaviconIsValid() const {
|
| - const NavigationController& controller = tab_contents()->controller();
|
| - NavigationEntry* entry = controller.GetTransientEntry();
|
| - if (entry)
|
| - return entry->favicon().is_valid();
|
| -
|
| - entry = controller.GetLastCommittedEntry();
|
| - if (entry)
|
| - return entry->favicon().is_valid();
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool FaviconTabHelper::ShouldDisplayFavicon() {
|
| - // Always display a throbber during pending loads.
|
| - const NavigationController& controller = tab_contents()->controller();
|
| - if (controller.GetLastCommittedEntry() && controller.pending_entry())
|
| - return true;
|
| -
|
| - WebUI* web_ui = tab_contents()->GetWebUIForCurrentState();
|
| - if (web_ui)
|
| - return !web_ui->hide_favicon();
|
| - return true;
|
| -}
|
| -
|
| -void FaviconTabHelper::FetchFavicon(const GURL& url) {
|
| - cancelable_consumer_.CancelAllRequests();
|
| -
|
| - url_ = url;
|
| -
|
| - favicon_expired_ = got_favicon_from_history_ = got_favicon_url_ = false;
|
| -
|
| - // Request the favicon from the history service. In parallel to this the
|
| - // renderer is going to notify us (well TabContents) when the favicon url is
|
| - // available.
|
| - if (GetFaviconService()) {
|
| - GetFaviconService()->GetFaviconForURL(url_, history::FAVICON,
|
| - &cancelable_consumer_,
|
| - NewCallback(this, &FaviconTabHelper::OnFaviconDataForInitialURL));
|
| - }
|
| -}
|
| -
|
| -int FaviconTabHelper::DownloadImage(const GURL& image_url,
|
| - int image_size,
|
| - ImageDownloadCallback* callback) {
|
| - DCHECK(callback); // Must provide a callback.
|
| - return ScheduleDownload(GURL(), image_url, image_size, callback);
|
| -}
|
| -
|
| -FaviconService* FaviconTabHelper::GetFaviconService() {
|
| - return tab_contents()->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
|
| -}
|
| -
|
| -void FaviconTabHelper::SetFavicon(
|
| - const GURL& url,
|
| - const GURL& image_url,
|
| - const SkBitmap& image) {
|
| - const SkBitmap& sized_image =
|
| - (image.width() == kFaviconSize && image.height() == kFaviconSize)
|
| - ? image : ConvertToFaviconSize(image);
|
| -
|
| - if (GetFaviconService() && ShouldSaveFavicon(url)) {
|
| - std::vector<unsigned char> image_data;
|
| - gfx::PNGCodec::EncodeBGRASkBitmap(sized_image, false, &image_data);
|
| - GetFaviconService()->SetFavicon(url, image_url, image_data,
|
| - history::FAVICON);
|
| - }
|
| -
|
| - if (url == url_) {
|
| - NavigationEntry* entry = GetEntry();
|
| - if (entry)
|
| - UpdateFavicon(entry, sized_image);
|
| - }
|
| -}
|
| -
|
| -void FaviconTabHelper::SaveFavicon() {
|
| - NavigationEntry* entry = tab_contents()->controller().GetActiveEntry();
|
| - if (!entry || entry->url().is_empty())
|
| - return;
|
| -
|
| - // Make sure the page is in history, otherwise adding the favicon does
|
| - // nothing.
|
| - HistoryService* history =
|
| - tab_contents()->profile()->GetOriginalProfile()->GetHistoryService(
|
| - Profile::IMPLICIT_ACCESS);
|
| - if (!history)
|
| - return;
|
| - history->AddPageNoVisitForBookmark(entry->url());
|
| -
|
| - FaviconService* service = tab_contents()->profile()->
|
| - GetOriginalProfile()->GetFaviconService(Profile::IMPLICIT_ACCESS);
|
| - if (!service)
|
| - return;
|
| - const NavigationEntry::FaviconStatus& favicon(entry->favicon());
|
| - if (!favicon.is_valid() || favicon.url().is_empty() ||
|
| - favicon.bitmap().empty()) {
|
| - return;
|
| - }
|
| - std::vector<unsigned char> image_data;
|
| - gfx::PNGCodec::EncodeBGRASkBitmap(favicon.bitmap(), false, &image_data);
|
| - service->SetFavicon(
|
| - entry->url(), favicon.url(), image_data, history::FAVICON);
|
| -}
|
| -
|
| -void FaviconTabHelper::UpdateFavicon(NavigationEntry* entry,
|
| - scoped_refptr<RefCountedMemory> data) {
|
| - SkBitmap image;
|
| - gfx::PNGCodec::Decode(data->front(), data->size(), &image);
|
| - UpdateFavicon(entry, image);
|
| -}
|
| -
|
| -void FaviconTabHelper::UpdateFavicon(NavigationEntry* entry,
|
| - const SkBitmap& image) {
|
| - // No matter what happens, we need to mark the favicon as being set.
|
| - entry->favicon().set_is_valid(true);
|
| -
|
| - if (image.empty())
|
| - return;
|
| -
|
| - entry->favicon().set_bitmap(image);
|
| - tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB);
|
| -}
|
| -
|
| -void FaviconTabHelper::OnUpdateFaviconURL(int32 page_id, const GURL& icon_url) {
|
| - // TODO(davemoore) Should clear on empty url. Currently we ignore it.
|
| - // This appears to be what FF does as well.
|
| - if (icon_url.is_empty())
|
| - return;
|
| -
|
| - NavigationEntry* entry = GetEntry();
|
| - if (!entry)
|
| - return;
|
| -
|
| - got_favicon_url_ = true;
|
| -
|
| - if (!GetFaviconService())
|
| - return;
|
| -
|
| - if (!favicon_expired_ && entry->favicon().is_valid() &&
|
| - entry->favicon().url() == icon_url) {
|
| - // We already have the icon, no need to proceed.
|
| - return;
|
| - }
|
| -
|
| - entry->favicon().set_url(icon_url);
|
| -
|
| - if (got_favicon_from_history_)
|
| - DownloadFaviconOrAskHistory(entry);
|
| -}
|
| -
|
| -void FaviconTabHelper::NavigateToPendingEntry(
|
| - const GURL& url,
|
| - NavigationController::ReloadType reload_type) {
|
| - if (reload_type != NavigationController::NO_RELOAD &&
|
| - !tab_contents()->profile()->IsOffTheRecord()) {
|
| - FaviconService* favicon_service =
|
| - tab_contents()->profile()->GetFaviconService(Profile::IMPLICIT_ACCESS);
|
| - if (favicon_service)
|
| - favicon_service->SetFaviconOutOfDateForPage(url);
|
| - }
|
| -}
|
| -
|
| -void FaviconTabHelper::DidNavigateMainFramePostCommit(
|
| - const NavigationController::LoadCommittedDetails& details,
|
| - const ViewHostMsg_FrameNavigate_Params& /*params*/) {
|
| - // Get the favicon, either from history or request it from the net.
|
| - FetchFavicon(details.entry->url());
|
| -}
|
| -
|
| -bool FaviconTabHelper::OnMessageReceived(const IPC::Message& message) {
|
| - bool handled = true;
|
| - IPC_BEGIN_MESSAGE_MAP(FaviconTabHelper, message)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
|
| - IPC_MESSAGE_HANDLER(ViewHostMsg_DidDownloadFavicon, OnDidDownloadFavicon)
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP()
|
| - return handled;
|
| -}
|
| -
|
| -void FaviconTabHelper::OnDidDownloadFavicon(int id,
|
| - const GURL& image_url,
|
| - bool errored,
|
| - const SkBitmap& image) {
|
| - DownloadRequests::iterator i = download_requests_.find(id);
|
| - if (i == download_requests_.end()) {
|
| - // Currently TabContents notifies us of ANY downloads so that it is
|
| - // possible to get here.
|
| - return;
|
| - }
|
| -
|
| - if (i->second.callback) {
|
| - i->second.callback->Run(id, errored, image);
|
| - } else if (!errored) {
|
| - SetFavicon(i->second.url, image_url, image);
|
| - }
|
| -
|
| - download_requests_.erase(i);
|
| -}
|
| -
|
| -NavigationEntry* FaviconTabHelper::GetEntry() {
|
| - NavigationEntry* entry = tab_contents()->controller().GetActiveEntry();
|
| - if (entry && entry->url() == url_ &&
|
| - tab_contents()->IsActiveEntry(entry->page_id())) {
|
| - return entry;
|
| - }
|
| - // If the URL has changed out from under us (as will happen with redirects)
|
| - // return NULL.
|
| - return NULL;
|
| -}
|
| -
|
| -void FaviconTabHelper::OnFaviconDataForInitialURL(
|
| - FaviconService::Handle handle,
|
| - history::FaviconData favicon) {
|
| - NavigationEntry* entry = GetEntry();
|
| - if (!entry)
|
| - return;
|
| -
|
| - got_favicon_from_history_ = true;
|
| -
|
| - favicon_expired_ = (favicon.known_icon && favicon.expired);
|
| -
|
| - if (favicon.known_icon && !entry->favicon().is_valid() &&
|
| - (!got_favicon_url_ || entry->favicon().url() == favicon.icon_url)) {
|
| - // The db knows the favicon (although it may be out of date) and the entry
|
| - // doesn't have an icon. Set the favicon now, and if the favicon turns out
|
| - // to be expired (or the wrong url) we'll fetch later on. This way the
|
| - // user doesn't see a flash of the default favicon.
|
| - entry->favicon().set_url(favicon.icon_url);
|
| - if (favicon.is_valid())
|
| - UpdateFavicon(entry, favicon.image_data);
|
| - entry->favicon().set_is_valid(true);
|
| - }
|
| -
|
| - if (favicon.known_icon && !favicon.expired) {
|
| - if (got_favicon_url_ && entry->favicon().url() != favicon.icon_url) {
|
| - // Mapping in the database is wrong. DownloadFaviconOrAskHistory will
|
| - // update the mapping for this url and download the favicon if we don't
|
| - // already have it.
|
| - DownloadFaviconOrAskHistory(entry);
|
| - }
|
| - } else if (got_favicon_url_) {
|
| - // We know the official url for the favicon, by either don't have the
|
| - // favicon or its expired. Continue on to DownloadFaviconOrAskHistory to
|
| - // either download or check history again.
|
| - DownloadFaviconOrAskHistory(entry);
|
| - }
|
| - // else we haven't got the icon url. When we get it we'll ask the
|
| - // renderer to download the icon.
|
| -}
|
| -
|
| -void FaviconTabHelper::DownloadFaviconOrAskHistory(NavigationEntry* entry) {
|
| - DCHECK(entry); // We should only get here if entry is valid.
|
| - if (favicon_expired_) {
|
| - // We have the mapping, but the favicon is out of date. Download it now.
|
| - ScheduleDownload(entry->url(), entry->favicon().url(), kFaviconSize, NULL);
|
| - } else if (GetFaviconService()) {
|
| - // We don't know the favicon, but we may have previously downloaded the
|
| - // favicon for another page that shares the same favicon. Ask for the
|
| - // favicon given the favicon URL.
|
| - if (tab_contents()->profile()->IsOffTheRecord()) {
|
| - GetFaviconService()->GetFavicon(
|
| - entry->favicon().url(),
|
| - history::FAVICON,
|
| - &cancelable_consumer_,
|
| - NewCallback(this, &FaviconTabHelper::OnFaviconData));
|
| - } else {
|
| - // Ask the history service for the icon. This does two things:
|
| - // 1. Attempts to fetch the favicon data from the database.
|
| - // 2. If the favicon exists in the database, this updates the database to
|
| - // include the mapping between the page url and the favicon url.
|
| - // This is asynchronous. The history service will call back when done.
|
| - // Issue the request and associate the current page ID with it.
|
| - GetFaviconService()->UpdateFaviconMappingAndFetch(
|
| - entry->url(),
|
| - entry->favicon().url(),
|
| - history::FAVICON,
|
| - &cancelable_consumer_,
|
| - NewCallback(this, &FaviconTabHelper::OnFaviconData));
|
| - }
|
| - }
|
| -}
|
| -
|
| -void FaviconTabHelper::OnFaviconData(
|
| - FaviconService::Handle handle,
|
| - history::FaviconData favicon) {
|
| - NavigationEntry* entry = GetEntry();
|
| - if (!entry)
|
| - return;
|
| -
|
| - // No need to update the favicon url. By the time we get here
|
| - // UpdateFaviconURL will have set the favicon url.
|
| -
|
| - if (favicon.is_valid()) {
|
| - // There is a favicon, set it now. If expired we'll download the current
|
| - // one again, but at least the user will get some icon instead of the
|
| - // default and most likely the current one is fine anyway.
|
| - UpdateFavicon(entry, favicon.image_data);
|
| - }
|
| -
|
| - if (!favicon.known_icon || favicon.expired) {
|
| - // We don't know the favicon, or it is out of date. Request the current one.
|
| - ScheduleDownload(entry->url(), entry->favicon().url(), kFaviconSize, NULL);
|
| - }
|
| -}
|
| -
|
| -int FaviconTabHelper::ScheduleDownload(const GURL& url,
|
| - const GURL& image_url,
|
| - int image_size,
|
| - ImageDownloadCallback* callback) {
|
| - const int download_id = tab_contents()->render_view_host()->DownloadFavicon(
|
| - image_url, image_size);
|
| -
|
| - if (download_id) {
|
| - // Download ids should be unique.
|
| - DCHECK(download_requests_.find(download_id) == download_requests_.end());
|
| - download_requests_[download_id] = DownloadRequest(url, image_url, callback);
|
| - }
|
| -
|
| - return download_id;
|
| -}
|
| -
|
| -SkBitmap FaviconTabHelper::ConvertToFaviconSize(const SkBitmap& image) {
|
| - int width = image.width();
|
| - int height = image.height();
|
| - if (width > 0 && height > 0) {
|
| - calc_favicon_target_size(&width, &height);
|
| - return skia::ImageOperations::Resize(
|
| - image, skia::ImageOperations::RESIZE_LANCZOS3,
|
| - width, height);
|
| - }
|
| - return image;
|
| -}
|
| -
|
| -bool FaviconTabHelper::ShouldSaveFavicon(const GURL& url) {
|
| - if (!tab_contents()->profile()->IsOffTheRecord())
|
| - return true;
|
| -
|
| - // Otherwise store the favicon if the page is bookmarked.
|
| - BookmarkModel* bookmark_model = tab_contents()->profile()->GetBookmarkModel();
|
| - return bookmark_model && bookmark_model->IsBookmarked(url);
|
| -}
|
|
|