Home | History | Annotate | Download | only in search
      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 
     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 
     30 SearchTermsTracker::~SearchTermsTracker() {
     31 }
     32 
     33 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 
     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 
     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   TemplateURL* template_url =
     88       TemplateURLServiceFactory::GetForProfile(profile)->
     89           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         // This entry is a search results page. Extract the terms only if this
     96         // isn't the last (i.e. most recent/current) entry as we don't want to
     97         // record the search terms when we're on an SRP.
     98         if (i != controller->GetCurrentEntryIndex()) {
     99           tab_data->srp_navigation_index = i;
    100           template_url->ExtractSearchTermsFromURL(entry->GetURL(),
    101                                                   &tab_data->search_terms);
    102           return true;
    103         }
    104 
    105         // We've found an SRP - stop searching (even if we did not record the
    106         // search terms, as anything before this entry will be unrelated).
    107         break;
    108       }
    109     }
    110 
    111     // Do not consider any navigations that precede a non-web-triggerable
    112     // navigation as they are not related to those terms.
    113     if (!content::PageTransitionIsWebTriggerable(
    114             entry->GetTransitionType())) {
    115       break;
    116     }
    117   }
    118 
    119   return false;
    120 }
    121 
    122 void SearchTermsTracker::RemoveTabData(
    123     const content::WebContents* contents) {
    124   TabState::iterator it = tabs_.find(contents);
    125   if (it != tabs_.end()) {
    126     tabs_.erase(it);
    127   }
    128 }
    129 
    130 }  // namespace chrome
    131