1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/history/history_tab_helper.h"
9 #include "chrome/browser/history/history_service.h"
10 #include "chrome/browser/history/history_service_factory.h"
11 #include "chrome/browser/prerender/prerender_contents.h"
12 #include "chrome/browser/prerender/prerender_manager.h"
13 #include "chrome/browser/prerender/prerender_manager_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/render_messages.h"
16 #include "content/public/browser/navigation_details.h"
17 #include "content/public/browser/navigation_entry.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_delegate.h"
20 #include "content/public/common/frame_navigate_params.h"
22 #if !defined(OS_ANDROID)
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_finder.h"
27 using content::NavigationEntry;
28 using content::WebContents;
30 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper);
32 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
33 : content::WebContentsObserver(web_contents),
34 received_page_title_(false) {
37 HistoryTabHelper::~HistoryTabHelper() {
40 void HistoryTabHelper::UpdateHistoryForNavigation(
41 const history::HistoryAddPageArgs& add_page_args) {
42 HistoryService* hs = GetHistoryService();
44 GetHistoryService()->AddPage(add_page_args);
47 void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
48 HistoryService* hs = GetHistoryService();
50 hs->SetPageTitle(entry.GetVirtualURL(),
51 entry.GetTitleForDisplay(std::string()));
54 history::HistoryAddPageArgs
55 HistoryTabHelper::CreateHistoryAddPageArgs(
56 const GURL& virtual_url,
58 bool did_replace_entry,
59 const content::FrameNavigateParams& params) {
60 history::HistoryAddPageArgs add_page_args(
61 params.url, timestamp, web_contents(), params.page_id,
62 params.referrer.url, params.redirects, params.transition,
63 history::SOURCE_BROWSED, did_replace_entry);
64 if (ui::PageTransitionIsMainFrame(params.transition) &&
65 virtual_url != params.url) {
66 // Hack on the "virtual" URL so that it will appear in history. For some
67 // types of URLs, we will display a magic URL that is different from where
68 // the page is actually navigated. We want the user to see in history what
69 // they saw in the URL bar, so we add the virtual URL as a redirect. This
70 // only applies to the main frame, as the virtual URL doesn't apply to
72 add_page_args.url = virtual_url;
73 if (!add_page_args.redirects.empty())
74 add_page_args.redirects.back() = virtual_url;
79 void HistoryTabHelper::DidNavigateMainFrame(
80 const content::LoadCommittedDetails& details,
81 const content::FrameNavigateParams& params) {
82 // Allow the new page to set the title again.
83 received_page_title_ = false;
86 void HistoryTabHelper::DidNavigateAnyFrame(
87 content::RenderFrameHost* render_frame_host,
88 const content::LoadCommittedDetails& details,
89 const content::FrameNavigateParams& params) {
90 // Update history. Note that this needs to happen after the entry is complete,
91 // which WillNavigate[Main,Sub]Frame will do before this function is called.
92 if (!params.should_update_history)
95 // Most of the time, the displayURL matches the loaded URL, but for about:
96 // URLs, we use a data: URL as the real value. We actually want to save the
97 // about: URL to the history db and keep the data: URL hidden. This is what
98 // the WebContents' URL getter does.
99 const history::HistoryAddPageArgs& add_page_args =
100 CreateHistoryAddPageArgs(
101 web_contents()->GetURL(), details.entry->GetTimestamp(),
102 details.did_replace_entry, params);
104 prerender::PrerenderManager* prerender_manager =
105 prerender::PrerenderManagerFactory::GetForProfile(
106 Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
107 if (prerender_manager) {
108 prerender::PrerenderContents* prerender_contents =
109 prerender_manager->GetPrerenderContents(web_contents());
110 if (prerender_contents) {
111 prerender_contents->DidNavigate(add_page_args);
116 #if !defined(OS_ANDROID)
117 // Don't update history if this web contents isn't associatd with a tab.
118 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
119 if (!browser || browser->is_app())
123 UpdateHistoryForNavigation(add_page_args);
126 void HistoryTabHelper::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
127 if (received_page_title_)
131 UpdateHistoryPageTitle(*entry);
132 received_page_title_ = explicit_set;
136 HistoryService* HistoryTabHelper::GetHistoryService() {
138 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
139 if (profile->IsOffTheRecord())
142 return HistoryServiceFactory::GetForProfile(profile,
143 Profile::IMPLICIT_ACCESS);
146 void HistoryTabHelper::WebContentsDestroyed() {
147 // We update the history for this URL.
148 WebContents* tab = web_contents();
149 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
150 if (profile->IsOffTheRecord())
154 HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS);
156 NavigationEntry* entry = tab->GetController().GetLastCommittedEntry();
158 hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(),
161 hs->ClearCachedDataForContextID(tab);