• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/search/search_terms_tracker.h"
6 
7 #include "chrome/browser/profiles/profile.h"
8 #include "chrome/browser/search_engines/template_url.h"
9 #include "chrome/browser/search_engines/template_url_service.h"
10 #include "chrome/browser/search_engines/template_url_service_factory.h"
11 #include "content/public/browser/navigation_controller.h"
12 #include "content/public/browser/navigation_entry.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/web_contents.h"
18 
19 namespace chrome {
20 
SearchTermsTracker()21 SearchTermsTracker::SearchTermsTracker() {
22   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
23                  content::NotificationService::AllSources());
24   registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
25                  content::NotificationService::AllSources());
26   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
27                  content::NotificationService::AllSources());
28 }
29 
~SearchTermsTracker()30 SearchTermsTracker::~SearchTermsTracker() {
31 }
32 
GetSearchTerms(const content::WebContents * contents,base::string16 * search_terms,int * navigation_index) const33 bool SearchTermsTracker::GetSearchTerms(
34     const content::WebContents* contents,
35     base::string16* search_terms,
36     int* navigation_index) const {
37   if (contents) {
38     TabState::const_iterator it = tabs_.find(contents);
39     if (it != tabs_.end() && !it->second.search_terms.empty()) {
40       if (search_terms)
41         *search_terms = it->second.search_terms;
42       if (navigation_index)
43         *navigation_index = it->second.srp_navigation_index;
44       return true;
45     }
46   }
47   return false;
48 }
49 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)50 void SearchTermsTracker::Observe(
51     int type,
52     const content::NotificationSource& source,
53     const content::NotificationDetails& details) {
54   switch (type) {
55     case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
56     case content::NOTIFICATION_NAV_ENTRY_CHANGED: {
57       content::NavigationController* controller =
58           content::Source<content::NavigationController>(source).ptr();
59       TabData search;
60       if (FindMostRecentSearch(controller, &search))
61         tabs_[controller->GetWebContents()] = search;
62       else
63         RemoveTabData(controller->GetWebContents());
64       break;
65     }
66 
67     case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
68       RemoveTabData(content::Source<content::WebContents>(source).ptr());
69       break;
70     }
71 
72     default:
73       NOTREACHED();
74       return;
75   }
76 }
77 
FindMostRecentSearch(const content::NavigationController * controller,SearchTermsTracker::TabData * tab_data)78 bool SearchTermsTracker::FindMostRecentSearch(
79     const content::NavigationController* controller,
80     SearchTermsTracker::TabData* tab_data) {
81   Profile* profile =
82       Profile::FromBrowserContext(controller->GetBrowserContext());
83   DCHECK(profile);
84   if (!profile)
85     return false;
86 
87   TemplateURLService* service =
88       TemplateURLServiceFactory::GetForProfile(profile);
89   TemplateURL* template_url = service->GetDefaultSearchProvider();
90 
91   for (int i = controller->GetCurrentEntryIndex(); i >= 0; --i) {
92     content::NavigationEntry* entry = controller->GetEntryAtIndex(i);
93     if (entry->GetPageType() == content::PAGE_TYPE_NORMAL) {
94       if (template_url->IsSearchURL(entry->GetURL(),
95                                     service->search_terms_data())) {
96         // This entry is a search results page. Extract the terms only if this
97         // isn't the last (i.e. most recent/current) entry as we don't want to
98         // record the search terms when we're on an SRP.
99         if (i != controller->GetCurrentEntryIndex()) {
100           tab_data->srp_navigation_index = i;
101           template_url->ExtractSearchTermsFromURL(entry->GetURL(),
102                                                   service->search_terms_data(),
103                                                   &tab_data->search_terms);
104           return true;
105         }
106 
107         // We've found an SRP - stop searching (even if we did not record the
108         // search terms, as anything before this entry will be unrelated).
109         break;
110       }
111     }
112 
113     // Do not consider any navigations that precede a non-web-triggerable
114     // navigation as they are not related to those terms.
115     if (!content::PageTransitionIsWebTriggerable(
116             entry->GetTransitionType())) {
117       break;
118     }
119   }
120 
121   return false;
122 }
123 
RemoveTabData(const content::WebContents * contents)124 void SearchTermsTracker::RemoveTabData(
125     const content::WebContents* contents) {
126   TabState::iterator it = tabs_.find(contents);
127   if (it != tabs_.end()) {
128     tabs_.erase(it);
129   }
130 }
131 
132 }  // namespace chrome
133