blob: 22567445123d5b32c5e3d4fcedc4abd3a38660a9 [file] [log] [blame]
// Copyright (c) 2012 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/history/history_tab_helper.h"
#include <utility>
#include "chrome/browser/history/history_service.h"
#include "chrome/browser/history/history_service_factory.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/network_time/navigation_time_helper.h"
#endif
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/render_messages.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/frame_navigate_params.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#endif
using content::NavigationEntry;
using content::WebContents;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper);
HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
: content::WebContentsObserver(web_contents),
received_page_title_(false) {
}
HistoryTabHelper::~HistoryTabHelper() {
}
void HistoryTabHelper::UpdateHistoryForNavigation(
const history::HistoryAddPageArgs& add_page_args) {
HistoryService* hs = GetHistoryService();
if (hs)
GetHistoryService()->AddPage(add_page_args);
}
void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
HistoryService* hs = GetHistoryService();
if (hs)
hs->SetPageTitle(entry.GetVirtualURL(),
entry.GetTitleForDisplay(std::string()));
}
history::HistoryAddPageArgs
HistoryTabHelper::CreateHistoryAddPageArgs(
const GURL& virtual_url,
base::Time timestamp,
bool did_replace_entry,
const content::FrameNavigateParams& params) {
history::HistoryAddPageArgs add_page_args(
params.url, timestamp, web_contents(), params.page_id,
params.referrer.url, params.redirects, params.transition,
history::SOURCE_BROWSED, did_replace_entry);
if (content::PageTransitionIsMainFrame(params.transition) &&
virtual_url != params.url) {
// Hack on the "virtual" URL so that it will appear in history. For some
// types of URLs, we will display a magic URL that is different from where
// the page is actually navigated. We want the user to see in history what
// they saw in the URL bar, so we add the virtual URL as a redirect. This
// only applies to the main frame, as the virtual URL doesn't apply to
// sub-frames.
add_page_args.url = virtual_url;
if (!add_page_args.redirects.empty())
add_page_args.redirects.back() = virtual_url;
}
return add_page_args;
}
void HistoryTabHelper::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
// Allow the new page to set the title again.
received_page_title_ = false;
}
void HistoryTabHelper::DidNavigateAnyFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
// Update history. Note that this needs to happen after the entry is complete,
// which WillNavigate[Main,Sub]Frame will do before this function is called.
if (!params.should_update_history)
return;
#if !defined(OS_ANDROID)
base::Time navigation_time =
NavigationTimeHelper::FromWebContents(web_contents())->GetNavigationTime(
details.entry);
#else
base::Time navigation_time = details.entry->GetTimestamp();
#endif
// Most of the time, the displayURL matches the loaded URL, but for about:
// URLs, we use a data: URL as the real value. We actually want to save the
// about: URL to the history db and keep the data: URL hidden. This is what
// the WebContents' URL getter does.
const history::HistoryAddPageArgs& add_page_args =
CreateHistoryAddPageArgs(
web_contents()->GetURL(), navigation_time,
details.did_replace_entry, params);
prerender::PrerenderManager* prerender_manager =
prerender::PrerenderManagerFactory::GetForProfile(
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
if (prerender_manager) {
prerender::PrerenderContents* prerender_contents =
prerender_manager->GetPrerenderContents(web_contents());
if (prerender_contents) {
prerender_contents->DidNavigate(add_page_args);
return;
}
}
#if !defined(OS_ANDROID)
// Don't update history if this web contents isn't associatd with a tab.
Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
if (!browser || browser->is_app())
return;
#endif
UpdateHistoryForNavigation(add_page_args);
}
void HistoryTabHelper::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
if (received_page_title_)
return;
if (entry) {
UpdateHistoryPageTitle(*entry);
received_page_title_ = explicit_set;
}
}
HistoryService* HistoryTabHelper::GetHistoryService() {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
if (profile->IsOffTheRecord())
return NULL;
return HistoryServiceFactory::GetForProfile(profile,
Profile::IMPLICIT_ACCESS);
}
void HistoryTabHelper::WebContentsDestroyed(WebContents* tab) {
// TODO(sky): nuke this since no one is using visit_duration (and this is all
// wrong).
// We update the history for this URL.
// The content returned from web_contents() has been destroyed by now.
// We need to use tab value directly.
Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
if (profile->IsOffTheRecord())
return;
HistoryService* hs =
HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
if (hs) {
NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
if (entry) {
hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
base::Time::Now());
}
}
}