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. 4 5 #include "chrome/browser/history/history_tab_helper.h" 6 7 #include <utility> 8 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" 21 22 #if !defined(OS_ANDROID) 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser_finder.h" 25 #endif 26 27 using content::NavigationEntry; 28 using content::WebContents; 29 30 DEFINE_WEB_CONTENTS_USER_DATA_KEY(HistoryTabHelper); 31 32 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents) 33 : content::WebContentsObserver(web_contents), 34 received_page_title_(false) { 35 } 36 37 HistoryTabHelper::~HistoryTabHelper() { 38 } 39 40 void HistoryTabHelper::UpdateHistoryForNavigation( 41 const history::HistoryAddPageArgs& add_page_args) { 42 HistoryService* hs = GetHistoryService(); 43 if (hs) 44 GetHistoryService()->AddPage(add_page_args); 45 } 46 47 void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) { 48 HistoryService* hs = GetHistoryService(); 49 if (hs) 50 hs->SetPageTitle(entry.GetVirtualURL(), 51 entry.GetTitleForDisplay(std::string())); 52 } 53 54 history::HistoryAddPageArgs 55 HistoryTabHelper::CreateHistoryAddPageArgs( 56 const GURL& virtual_url, 57 base::Time timestamp, 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 (content::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 71 // sub-frames. 72 add_page_args.url = virtual_url; 73 if (!add_page_args.redirects.empty()) 74 add_page_args.redirects.back() = virtual_url; 75 } 76 return add_page_args; 77 } 78 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; 84 } 85 86 void HistoryTabHelper::DidNavigateAnyFrame( 87 const content::LoadCommittedDetails& details, 88 const content::FrameNavigateParams& params) { 89 // Update history. Note that this needs to happen after the entry is complete, 90 // which WillNavigate[Main,Sub]Frame will do before this function is called. 91 if (!params.should_update_history) 92 return; 93 94 // Most of the time, the displayURL matches the loaded URL, but for about: 95 // URLs, we use a data: URL as the real value. We actually want to save the 96 // about: URL to the history db and keep the data: URL hidden. This is what 97 // the WebContents' URL getter does. 98 const history::HistoryAddPageArgs& add_page_args = 99 CreateHistoryAddPageArgs( 100 web_contents()->GetURL(), details.entry->GetTimestamp(), 101 details.did_replace_entry, params); 102 103 prerender::PrerenderManager* prerender_manager = 104 prerender::PrerenderManagerFactory::GetForProfile( 105 Profile::FromBrowserContext(web_contents()->GetBrowserContext())); 106 if (prerender_manager) { 107 prerender::PrerenderContents* prerender_contents = 108 prerender_manager->GetPrerenderContents(web_contents()); 109 if (prerender_contents) { 110 prerender_contents->DidNavigate(add_page_args); 111 return; 112 } 113 } 114 115 #if !defined(OS_ANDROID) 116 // Don't update history if this web contents isn't associatd with a tab. 117 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); 118 if (!browser || browser->is_app()) 119 return; 120 #endif 121 122 UpdateHistoryForNavigation(add_page_args); 123 } 124 125 void HistoryTabHelper::TitleWasSet(NavigationEntry* entry, bool explicit_set) { 126 if (received_page_title_) 127 return; 128 129 if (entry) { 130 UpdateHistoryPageTitle(*entry); 131 received_page_title_ = explicit_set; 132 } 133 } 134 135 HistoryService* HistoryTabHelper::GetHistoryService() { 136 Profile* profile = 137 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 138 if (profile->IsOffTheRecord()) 139 return NULL; 140 141 return HistoryServiceFactory::GetForProfile(profile, 142 Profile::IMPLICIT_ACCESS); 143 } 144 145 void HistoryTabHelper::WebContentsDestroyed() { 146 // We update the history for this URL. 147 WebContents* tab = web_contents(); 148 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext()); 149 if (profile->IsOffTheRecord()) 150 return; 151 152 HistoryService* hs = 153 HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS); 154 if (hs) { 155 NavigationEntry* entry = tab->GetController().GetLastCommittedEntry(); 156 if (entry) { 157 hs->UpdateWithPageEndTime(tab, entry->GetPageID(), tab->GetURL(), 158 base::Time::Now()); 159 } 160 } 161 } 162