blob: 4df739c82870dcd7d6eb33bed19fa53d21020fad [file] [log] [blame]
// Copyright 2017 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/ui/tab_ui_helper.h"
#include "build/build_config.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/favicon/favicon_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/grit/generated_resources.h"
#include "components/favicon/core/favicon_service.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/url_formatter/url_formatter.h"
#include "content/public/browser/invalidate_type.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/resources/grit/ui_resources.h"
namespace {
base::string16 FormatUrlToSubdomain(const GURL& url) {
base::string16 formated_url = url_formatter::FormatUrl(
url, url_formatter::kFormatUrlOmitTrivialSubdomains,
net::UnescapeRule::SPACES, nullptr, nullptr, nullptr);
return base::UTF8ToUTF16(GURL(formated_url).host());
}
} // namespace
TabUIHelper::TabUIData::TabUIData(const GURL& url)
: title(FormatUrlToSubdomain(url)),
favicon(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_DEFAULT_FAVICON)) {}
TabUIHelper::TabUIHelper(content::WebContents* contents)
: WebContentsObserver(contents), weak_ptr_factory_(this) {}
TabUIHelper::~TabUIHelper() {}
base::string16 TabUIHelper::GetTitle() const {
const base::string16& contents_title = web_contents()->GetTitle();
if (!contents_title.empty())
return contents_title;
if (tab_ui_data_)
return tab_ui_data_->title;
#if defined(OS_MACOSX)
return l10n_util::GetStringUTF16(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
#else
return base::string16();
#endif
}
gfx::Image TabUIHelper::GetFavicon() const {
if (ShouldUseFaviconFromHistory() && tab_ui_data_)
return tab_ui_data_->favicon;
return favicon::TabFaviconFromWebContents(web_contents());
}
bool TabUIHelper::ShouldHideThrobber() const {
// Hiding throbber and using favicon from history is desired when a new
// background tab's initial navigation is delayed, so the user has a way to
// see what the tab is.
if (ShouldUseFaviconFromHistory())
return true;
// We also want to hide a background tab's throbber during page load if it is
// created by session restore. A restored tab's favicon is already fetched
// by |SessionRestoreDelegate|.
if (created_by_session_restore_ && !was_active_at_least_once_)
return true;
return false;
}
void TabUIHelper::NotifyInitialNavigationDelayed(bool is_navigation_delayed) {
DCHECK(web_contents()->GetController().IsInitialNavigation());
is_navigation_delayed_ = is_navigation_delayed;
if (!is_navigation_delayed_)
return;
tab_ui_data_ = std::make_unique<TabUIData>(web_contents()->GetVisibleURL());
web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
// When fetching favicon from history, we first try the exact URL, and then
// fall back to the host.
FetchFaviconFromHistory(web_contents()->GetVisibleURL(),
base::Bind(&TabUIHelper::OnURLFaviconFetched,
weak_ptr_factory_.GetWeakPtr()));
}
void TabUIHelper::DidStopLoading() {
// Reset the properties after the initial navigation finishes loading, so that
// latter navigations are not affected.
is_navigation_delayed_ = false;
created_by_session_restore_ = false;
tab_ui_data_.reset();
}
bool TabUIHelper::ShouldUseFaviconFromHistory() const {
return web_contents()->GetController().IsInitialNavigation() &&
is_navigation_delayed_ && !was_active_at_least_once_;
}
void TabUIHelper::FetchFaviconFromHistory(
const GURL& url,
const favicon_base::FaviconImageCallback& callback) {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
favicon::FaviconService* favicon_service =
FaviconServiceFactory::GetForProfile(profile,
ServiceAccessType::EXPLICIT_ACCESS);
// |favicon_service| might be null when testing.
if (favicon_service) {
favicon_service->GetFaviconImageForPageURL(url, callback,
&favicon_tracker_);
}
}
void TabUIHelper::OnURLFaviconFetched(
const favicon_base::FaviconImageResult& favicon) {
if (!ShouldUseFaviconFromHistory())
return;
if (!favicon.image.IsEmpty()) {
UpdateFavicon(favicon);
return;
}
FetchFaviconFromHistory(web_contents()->GetVisibleURL().GetWithEmptyPath(),
base::Bind(&TabUIHelper::OnHostFaviconFetched,
weak_ptr_factory_.GetWeakPtr()));
}
void TabUIHelper::OnHostFaviconFetched(
const favicon_base::FaviconImageResult& favicon) {
if (!ShouldUseFaviconFromHistory())
return;
if (!favicon.image.IsEmpty())
UpdateFavicon(favicon);
}
void TabUIHelper::UpdateFavicon(
const favicon_base::FaviconImageResult& favicon) {
if (tab_ui_data_) {
tab_ui_data_->favicon = favicon.image;
web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
}
}