summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-27 16:15:44 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-27 16:15:44 +0000
commit0bfc29a5e1dc622ef1ca3601296738112a9a9abf (patch)
treec2dc97f51a06d57db01cee5e1164cf0b81f9dc2a
parent930709556e52f09d355aaf0c7b00e90d6042d4d9 (diff)
downloadchromium_src-0bfc29a5e1dc622ef1ca3601296738112a9a9abf.zip
chromium_src-0bfc29a5e1dc622ef1ca3601296738112a9a9abf.tar.gz
chromium_src-0bfc29a5e1dc622ef1ca3601296738112a9a9abf.tar.bz2
Searching by keyword now generates a visit against the site with a
transition type of TAB_TO_SEARCH. This visit increments the typed count and ensures if you use TAB_TO_SEARCH you still get autocompleted to the site. I'll add some tests for this, but want to make sure we're ok with it before I do that. BUG=3633 TEST=will be covered by unit tests. Review URL: http://codereview.chromium.org/93087 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14609 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc3
-rw-r--r--chrome/browser/autocomplete/search_provider.cc3
-rw-r--r--chrome/browser/history/expire_history_backend.cc9
-rw-r--r--chrome/browser/history/history_backend.cc28
-rw-r--r--chrome/browser/history/history_backend.h6
-rw-r--r--chrome/browser/history/history_backend_unittest.cc49
-rw-r--r--chrome/browser/history/history_notifications.h3
-rw-r--r--chrome/browser/history/history_unittest.cc6
-rw-r--r--chrome/browser/history/visit_database.cc4
-rw-r--r--chrome/browser/metrics/metrics_log.cc1
-rw-r--r--chrome/browser/net/url_fixer_upper.h6
-rw-r--r--chrome/browser/search_engines/template_url_model.cc43
-rw-r--r--chrome/browser/search_engines/template_url_model.h8
-rw-r--r--chrome/browser/search_engines/template_url_model_unittest.cc66
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc1
-rw-r--r--chrome/common/page_transition_types.h18
-rw-r--r--chrome/test/testing_profile.cc29
-rw-r--r--chrome/test/testing_profile.h5
18 files changed, 256 insertions, 32 deletions
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index b546c92..b4d5e50 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -303,8 +303,7 @@ AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
ACMatchClassification::DIM,
&result.description_class);
- // Keyword searches don't look like URLs.
- result.transition = PageTransition::GENERATED;
+ result.transition = PageTransition::KEYWORD;
return result;
}
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index 13d393c..2f123d8 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -713,7 +713,8 @@ void SearchProvider::AddMatchToMap(const std::wstring& query_string,
input_text);
// Search results don't look like URLs.
- match.transition = PageTransition::GENERATED;
+ match.transition =
+ is_keyword ? PageTransition::KEYWORD : PageTransition::GENERATED;
// Try to add |match| to |map|. If a match for |query_string| is already in
// |map|, replace it if |match| is more relevant.
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index 145d9b6..070722bc 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -41,6 +41,7 @@ bool ShouldArchiveVisit(const VisitRow& visit) {
// navigation and not part of a redirect chain.
if ((no_qualifier == PageTransition::LINK ||
no_qualifier == PageTransition::FORM_SUBMIT ||
+ no_qualifier == PageTransition::KEYWORD ||
no_qualifier == PageTransition::GENERATED) &&
visit.transition & PageTransition::CHAIN_END)
return true;
@@ -320,9 +321,11 @@ void ExpireHistoryBackend::ExpireURLsForVisits(
// NOTE: This code must stay in sync with HistoryBackend::AddPageVisit().
// TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
// typed, which would eliminate the need for this code.
- const PageTransition::Type transition = visits[i].transition;
- if (PageTransition::StripQualifier(transition) == PageTransition::TYPED &&
- !PageTransition::IsRedirect(transition))
+ PageTransition::Type transition =
+ PageTransition::StripQualifier(visits[i].transition);
+ if ((transition == PageTransition::TYPED &&
+ !PageTransition::IsRedirect(visits[i].transition)) ||
+ transition == PageTransition::KEYWORD_GENERATED)
cur.typed_count++;
}
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index d045dc9..066a757 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -351,6 +351,10 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
if (request->time < first_recorded_time_)
first_recorded_time_ = request->time;
+ PageTransition::Type transition =
+ PageTransition::StripQualifier(request->transition);
+ bool is_keyword_generated = (transition == PageTransition::KEYWORD_GENERATED);
+
if (request->redirects.size() <= 1) {
// The single entry is both a chain start and end.
PageTransition::Type t = request->transition |
@@ -360,13 +364,15 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
last_ids = AddPageVisit(request->url, last_recorded_time_,
last_ids.second, t);
- // Update the segment for this visit.
- UpdateSegments(request->url, from_visit_id, last_ids.second, t,
- last_recorded_time_);
+ // Update the segment for this visit. KEYWORD_GENERATED visits should not
+ // result in changing most visited, so we don't update segments (most
+ // visited db).
+ if (!is_keyword_generated) {
+ UpdateSegments(request->url, from_visit_id, last_ids.second, t,
+ last_recorded_time_);
+ }
} else {
// Redirect case. Add the redirect chain.
- PageTransition::Type transition =
- PageTransition::StripQualifier(request->transition);
PageTransition::Type redirect_info = PageTransition::CHAIN_START;
@@ -445,10 +451,8 @@ void HistoryBackend::AddPage(scoped_refptr<HistoryAddPageArgs> request) {
// TODO(evanm): Due to http://b/1194536 we lose the referrers of a subframe
// navigation anyway, so last_visit_id is always zero for them. But adding
// them here confuses main frame history, so we skip them for now.
- PageTransition::Type transition =
- PageTransition::StripQualifier(request->transition);
if (transition != PageTransition::AUTO_SUBFRAME &&
- transition != PageTransition::MANUAL_SUBFRAME) {
+ transition != PageTransition::MANUAL_SUBFRAME && !is_keyword_generated) {
tracker_.AddVisit(request->id_scope, request->page_id, request->url,
last_ids.second);
}
@@ -586,8 +590,11 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
// TODO(pkasting): http://b/1148304 We shouldn't be marking so many URLs as
// typed, which would eliminate the need for this code.
int typed_increment = 0;
- if (PageTransition::StripQualifier(transition) == PageTransition::TYPED &&
- !PageTransition::IsRedirect(transition))
+ PageTransition::Type transition_type =
+ PageTransition::StripQualifier(transition);
+ if ((transition_type == PageTransition::TYPED &&
+ !PageTransition::IsRedirect(transition)) ||
+ transition_type == PageTransition::KEYWORD_GENERATED)
typed_increment = 1;
// See if this URL is already in the DB.
@@ -639,6 +646,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
// Broadcast a notification of the visit.
if (visit_id) {
URLVisitedDetails* details = new URLVisitedDetails;
+ details->transition = transition;
details->row = url_info;
BroadcastNotifications(NotificationType::HISTORY_URL_VISITED, details);
}
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index 6201ec6..d8af551 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -257,6 +257,12 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// added for each given URL at the last visit time in the URLRow.
void AddPagesWithDetails(const std::vector<URLRow>& info);
+#if defined(UNIT_TEST)
+ HistoryDatabase* db() const { return db_.get(); }
+
+ ExpireHistoryBackend* expire_backend() { return &expirer_; }
+#endif
+
private:
friend class CommitLaterTask; // The commit task needs to call Commit().
friend class HistoryTest; // So the unit tests can poke our innards.
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index f64c109..e6c2879 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -395,4 +395,53 @@ TEST_F(HistoryBackendTest, GetPageThumbnailAfterRedirects) {
EXPECT_TRUE(data.get());
}
+// Tests a handful of assertions for a navigation with a type of
+// KEYWORD_GENERATED.
+TEST_F(HistoryBackendTest, KeywordGenerated) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://google.com");
+
+ Time visit_time = Time::Now() - base::TimeDelta::FromDays(1);
+ scoped_refptr<HistoryAddPageArgs> request(
+ new HistoryAddPageArgs(url, visit_time, NULL, 0, GURL(),
+ HistoryService::RedirectList(),
+ PageTransition::KEYWORD_GENERATED));
+ backend_->AddPage(request);
+
+ // A row should have been added for the url.
+ URLRow row;
+ URLID url_id = backend_->db()->GetRowForURL(url, &row);
+ ASSERT_NE(0, url_id);
+
+ // The typed count should be 1.
+ ASSERT_EQ(1, row.typed_count());
+
+ // KEYWORD_GENERATED urls should not be added to the segment db.
+ std::string segment_name = VisitSegmentDatabase::ComputeSegmentName(url);
+ EXPECT_EQ(0, backend_->db()->GetSegmentNamed(segment_name));
+
+ // One visit should be added.
+ VisitVector visits;
+ EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
+ EXPECT_EQ(1U, visits.size());
+
+ // But no visible visits.
+ visits.clear();
+ backend_->db()->GetVisibleVisitsInRange(
+ base::Time(), base::Time(), false, 1, &visits);
+ EXPECT_TRUE(visits.empty());
+
+ // Expire the visits.
+ backend_->expire_backend()->ExpireHistoryBetween(visit_time, Time::Now());
+
+ // The visit should have been nuked.
+ visits.clear();
+ EXPECT_TRUE(backend_->db()->GetVisitsForURL(url_id, &visits));
+ EXPECT_TRUE(visits.empty());
+
+ // As well as the url.
+ ASSERT_EQ(0, backend_->db()->GetRowForURL(url, &row));
+}
+
} // namespace history
diff --git a/chrome/browser/history/history_notifications.h b/chrome/browser/history/history_notifications.h
index a0ed455..4eb9289 100644
--- a/chrome/browser/history/history_notifications.h
+++ b/chrome/browser/history/history_notifications.h
@@ -23,8 +23,9 @@ struct HistoryDetails {
virtual ~HistoryDetails() {}
};
-// Details for NOTIFY_HISTORY_URL_VISITED.
+// Details for HISTORY_URL_VISITED.
struct URLVisitedDetails : public HistoryDetails {
+ PageTransition::Type transition;
URLRow row;
};
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index e64a09d..ed5e4e9 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -605,7 +605,7 @@ TEST_F(HistoryTest, Segments) {
// Wait for processing.
MessageLoop::current()->Run();
- EXPECT_EQ(page_usage_data_->size(), 1U);
+ ASSERT_EQ(1U, page_usage_data_->size());
EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
EXPECT_DOUBLE_EQ(3.0, page_usage_data_[0]->GetScore());
@@ -624,7 +624,7 @@ TEST_F(HistoryTest, Segments) {
MessageLoop::current()->Run();
// Make sure we still have one segment.
- EXPECT_EQ(page_usage_data_->size(), 1U);
+ ASSERT_EQ(1U, page_usage_data_->size());
EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
// Add a page linked from existing_url.
@@ -641,7 +641,7 @@ TEST_F(HistoryTest, Segments) {
MessageLoop::current()->Run();
// Make sure we still have one segment.
- EXPECT_EQ(page_usage_data_->size(), 1U);
+ ASSERT_EQ(1U, page_usage_data_->size());
EXPECT_TRUE(page_usage_data_[0]->GetURL() == existing_url);
// However, the score should have increased.
diff --git a/chrome/browser/history/visit_database.cc b/chrome/browser/history/visit_database.cc
index 4e796de..c118bf2 100644
--- a/chrome/browser/history/visit_database.cc
+++ b/chrome/browser/history/visit_database.cc
@@ -224,7 +224,8 @@ void VisitDatabase::GetVisibleVisitsInRange(Time begin_time, Time end_time,
"SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits "
"WHERE visit_time >= ? AND visit_time < ? "
"AND (transition & ?) != 0 " // CHAIN_END
- "AND (transition & ?) NOT IN (?, ?) " // NO SUBFRAME
+ "AND (transition & ?) NOT IN (?, ?, ?) " // NO SUBFRAME or
+ // KEYWORD_GENERATED
"ORDER BY visit_time DESC, id DESC");
if (!statement.is_valid())
return;
@@ -239,6 +240,7 @@ void VisitDatabase::GetVisibleVisitsInRange(Time begin_time, Time end_time,
statement->bind_int(3, PageTransition::CORE_MASK);
statement->bind_int(4, PageTransition::AUTO_SUBFRAME);
statement->bind_int(5, PageTransition::MANUAL_SUBFRAME);
+ statement->bind_int(6, PageTransition::KEYWORD_GENERATED);
std::set<URLID> found_urls;
while (statement->step() == SQLITE_ROW) {
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index a504b11..e407946 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -183,6 +183,7 @@ void MetricsLog::RecordLoadEvent(int window_id,
break;
case PageTransition::GENERATED:
+ case PageTransition::KEYWORD:
origin_string = "global-history";
break;
diff --git a/chrome/browser/net/url_fixer_upper.h b/chrome/browser/net/url_fixer_upper.h
index 7b6332d..5bd7fef 100644
--- a/chrome/browser/net/url_fixer_upper.h
+++ b/chrome/browser/net/url_fixer_upper.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_URL_FIXER_UPPER_H__
-#define CHROME_BROWSER_URL_FIXER_UPPER_H__
+#ifndef CHROME_BROWSER_NET_URL_FIXER_UPPER_H_
+#define CHROME_BROWSER_NET_URL_FIXER_UPPER_H_
#include <string>
@@ -63,4 +63,4 @@ namespace URLFixerUpper {
};
-#endif // #ifndef CHROME_BROWSER_URL_FIXER_UPPER_H__
+#endif // #ifndef CHROME_BROWSER_NET_URL_FIXER_UPPER_H_
diff --git a/chrome/browser/search_engines/template_url_model.cc b/chrome/browser/search_engines/template_url_model.cc
index cac5bea..982de9d 100644
--- a/chrome/browser/search_engines/template_url_model.cc
+++ b/chrome/browser/search_engines/template_url_model.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google_url_tracker.h"
#include "chrome/browser/history/history.h"
+#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/browser/search_engines/template_url.h"
@@ -692,9 +693,9 @@ void TemplateURLModel::Observe(NotificationType type,
Details<history::URLVisitedDetails> visit_details(details);
if (!loaded())
- visits_to_add_.push_back(visit_details->row);
+ visits_to_add_.push_back(*visit_details.ptr());
else
- UpdateKeywordSearchTermsForURL(visit_details->row);
+ UpdateKeywordSearchTermsForURL(*visit_details.ptr());
} else if (type == NotificationType::GOOGLE_URL_UPDATED) {
if (loaded_)
GoogleBaseURLChanged();
@@ -877,7 +878,8 @@ PrefService* TemplateURLModel::GetPrefs() {
}
void TemplateURLModel::UpdateKeywordSearchTermsForURL(
- const history::URLRow& row) {
+ const history::URLVisitedDetails& details) {
+ const history::URLRow& row = details.row;
if (!row.url().is_valid() ||
!row.url().parsed_for_possibly_invalid_spec().query.is_nonempty()) {
return;
@@ -918,6 +920,14 @@ void TemplateURLModel::UpdateKeywordSearchTermsForURL(
}
built_terms = true;
+ if (PageTransition::StripQualifier(details.transition) ==
+ PageTransition::KEYWORD) {
+ // The visit is the result of the user entering a keyword, generate a
+ // KEYWORD_GENERATED visit for the KEYWORD so that the keyword typed
+ // count is boosted.
+ AddTabToSearchVisit(**i);
+ }
+
QueryTerms::iterator terms_iterator =
query_terms.find(search_ref->GetSearchTermKey());
if (terms_iterator != query_terms.end() &&
@@ -930,6 +940,33 @@ void TemplateURLModel::UpdateKeywordSearchTermsForURL(
}
}
+void TemplateURLModel::AddTabToSearchVisit(const TemplateURL& t_url) {
+ // Only add visits for entries the user hasn't modified. If the user modified
+ // the entry the keyword may no longer correspond to the host name. It may be
+ // possible to do something more sophisticated here, but it's so rare as to
+ // not be worth it.
+ if (!t_url.safe_for_autoreplace())
+ return;
+
+ if (!profile_)
+ return;
+
+ HistoryService* history =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (!history)
+ return;
+
+ GURL url(URLFixerUpper::FixupURL(WideToUTF8(t_url.keyword()), std::string()));
+ if (!url.is_valid())
+ return;
+
+ // Synthesize a visit for the keyword. This ensures the url for the keyword is
+ // autocompleted even if the user doesn't type the url in directly.
+ history->AddPage(url, NULL, 0, GURL(),
+ PageTransition::KEYWORD_GENERATED,
+ HistoryService::RedirectList());
+}
+
// static
bool TemplateURLModel::BuildQueryTerms(const GURL& url,
QueryTerms* query_terms) {
diff --git a/chrome/browser/search_engines/template_url_model.h b/chrome/browser/search_engines/template_url_model.h
index 2c28d3d..094c506 100644
--- a/chrome/browser/search_engines/template_url_model.h
+++ b/chrome/browser/search_engines/template_url_model.h
@@ -279,7 +279,11 @@ class TemplateURLModel : public WebDataServiceConsumer,
// Iterates through the TemplateURLs to see if one matches the visited url.
// For each TemplateURL whose url matches the visited url
// SetKeywordSearchTermsForURL is invoked.
- void UpdateKeywordSearchTermsForURL(const history::URLRow& row);
+ void UpdateKeywordSearchTermsForURL(
+ const history::URLVisitedDetails& details);
+
+ // If necessary, generates a visit for the site http:// + t_url.keyword().
+ void AddTabToSearchVisit(const TemplateURL& t_url);
// Adds each of the query terms in the specified url whose key and value are
// non-empty to query_terms. If a query key appears multiple times, the value
@@ -329,7 +333,7 @@ class TemplateURLModel : public WebDataServiceConsumer,
// All visits that occurred before we finished loading. Once loaded
// UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
- std::vector<history::URLRow> visits_to_add_;
+ std::vector<history::URLVisitedDetails> visits_to_add_;
const TemplateURL* default_search_provider_;
diff --git a/chrome/browser/search_engines/template_url_model_unittest.cc b/chrome/browser/search_engines/template_url_model_unittest.cc
index d9515fe..8c0ea36 100644
--- a/chrome/browser/search_engines/template_url_model_unittest.cc
+++ b/chrome/browser/search_engines/template_url_model_unittest.cc
@@ -582,7 +582,10 @@ TEST_F(TemplateURLModelTest, UpdateKeywordSearchTermsForURL) {
false, Time());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url)));
+ history::URLVisitedDetails details;
+ details.row = history::URLRow(GURL(data[i].url));
+ details.transition = 0;
+ model_->UpdateKeywordSearchTermsForURL(details);
EXPECT_EQ(data[i].term, GetAndClearSearchTerm());
}
}
@@ -599,7 +602,10 @@ TEST_F(TemplateURLModelTest, DontUpdateKeywordSearchForNonReplaceable) {
AddKeywordWithDate(L"x", false, L"http://x/foo", L"name", false, Time());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
- model_->UpdateKeywordSearchTermsForURL(history::URLRow(GURL(data[i].url)));
+ history::URLVisitedDetails details;
+ details.row = history::URLRow(GURL(data[i].url));
+ details.transition = 0;
+ model_->UpdateKeywordSearchTermsForURL(details);
ASSERT_EQ(std::wstring(), GetAndClearSearchTerm());
}
}
@@ -630,3 +636,59 @@ TEST_F(TemplateURLModelTest, ChangeGoogleBaseValue) {
EXPECT_EQ("http://foo.com/?q=x", t_url->url()->ReplaceSearchTerms(*t_url,
L"x", TemplateURLRef::NO_SUGGESTIONS_AVAILABLE, std::wstring()).spec());
}
+
+struct QueryHistoryCallbackImpl {
+ QueryHistoryCallbackImpl() : success(false) {}
+
+ void Callback(HistoryService::Handle handle,
+ bool success, const history::URLRow* row,
+ history::VisitVector* visits) {
+ this->success = success;
+ if (row)
+ this->row = *row;
+ if (visits)
+ this->visits = *visits;
+ }
+
+ bool success;
+ history::URLRow row;
+ history::VisitVector visits;
+};
+
+// Make sure TemplateURLModel generates a KEYWORD_GENERATED visit for
+// KEYWORD visits.
+TEST_F(TemplateURLModelTest, GenerateVisitOnKeyword) {
+ VerifyLoad();
+ profile_->CreateHistoryService(true);
+
+ // Create a keyword.
+ TemplateURL* t_url = AddKeywordWithDate(
+ L"keyword", false, L"http://foo.com/foo?query={searchTerms}",
+ L"keyword", true, base::Time::Now());
+
+ // Add a visit that matches the url of the keyword.
+ HistoryService* history =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ history->AddPage(
+ t_url->url()->ReplaceSearchTerms(*t_url, L"blah", 0, std::wstring()),
+ NULL, 0, GURL(), PageTransition::KEYWORD, HistoryService::RedirectList());
+
+ // Wait for history to finish processing the request.
+ profile_->BlockUntilHistoryProcessesPendingRequests();
+
+ // Query history for the generated url.
+ CancelableRequestConsumer consumer;
+ QueryHistoryCallbackImpl callback;
+ history->QueryURL(GURL("http://keyword"), true, &consumer,
+ NewCallback(&callback, &QueryHistoryCallbackImpl::Callback));
+
+ // Wait for the request to be processed.
+ profile_->BlockUntilHistoryProcessesPendingRequests();
+
+ // And make sure the url and visit were added.
+ EXPECT_TRUE(callback.success);
+ EXPECT_NE(0, callback.row.id());
+ ASSERT_EQ(1U, callback.visits.size());
+ EXPECT_EQ(PageTransition::KEYWORD_GENERATED,
+ PageTransition::StripQualifier(callback.visits[0].transition));
+}
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 0470efa..3815232 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -28,6 +28,7 @@ bool ShouldForgetOpenersForTransition(PageTransition::Type transition) {
return transition == PageTransition::TYPED ||
transition == PageTransition::AUTO_BOOKMARK ||
transition == PageTransition::GENERATED ||
+ transition == PageTransition::KEYWORD ||
transition == PageTransition::START_PAGE;
}
diff --git a/chrome/common/page_transition_types.h b/chrome/common/page_transition_types.h
index 1e3c0e8..bdf97bc 100644
--- a/chrome/common/page_transition_types.h
+++ b/chrome/common/page_transition_types.h
@@ -55,6 +55,7 @@ class PageTransition {
// of a Google search result page, but appear like "Search Google for ...".
// These are not quite the same as TYPED navigations because the user
// didn't type or see the destination URL.
+ // See also KEYWORD.
GENERATED = 5,
// The page was specified in the command line or is the start page.
@@ -77,9 +78,24 @@ class PageTransition {
// SessionRestore and undo tab close use this transition type too.
RELOAD = 8,
+ // The url was generated from a replaceable keyword other than the default
+ // search provider. If the user types a keyword (which also applies to
+ // tab-to-search) in the omnibox this qualifier is applied to the transition
+ // type of the generated url. TemplateURLModel then may generate an
+ // additional visit with a transition type of KEYWORD_GENERATED against the
+ // url 'http://' + keyword. For example, if you do a tab-to-search against
+ // wikipedia the generated url has a transition qualifer of KEYWORD, and
+ // TemplateURLModel generates a visit for 'wikipedia.org' with a transition
+ // type of KEYWORD_GENERATED.
+ KEYWORD = 9,
+
+ // Corresponds to a visit generated for a keyword. See description of
+ // KEYWORD for more details.
+ KEYWORD_GENERATED = 10,
+
// ADDING NEW CORE VALUE? Be sure to update the LAST_CORE and CORE_MASK
// values below.
- LAST_CORE = RELOAD,
+ LAST_CORE = KEYWORD_GENERATED,
CORE_MASK = 0xFF,
// Qualifiers
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index 191e737..08fe09e9 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -13,6 +13,26 @@ using base::Time;
namespace {
+// Task used to make sure history has finished processing a request. Intended
+// for use with BlockUntilHistoryProcessesPendingRequests.
+
+class QuittingHistoryDBTask : public HistoryDBTask {
+ public:
+ QuittingHistoryDBTask() {}
+
+ virtual bool RunOnDBThread(history::HistoryBackend* backend,
+ history::HistoryDatabase* db) {
+ return true;
+ }
+
+ virtual void DoneRunOnMainThread() {
+ MessageLoop::current()->Quit();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuittingHistoryDBTask);
+};
+
// BookmarkLoadObserver is used when blocking until the BookmarkModel
// finishes loading. As soon as the BookmarkModel finishes loading the message
// loop is quit.
@@ -144,3 +164,12 @@ void TestingProfile::BlockUntilBookmarkModelLoaded() {
void TestingProfile::CreateTemplateURLModel() {
template_url_model_.reset(new TemplateURLModel(this));
}
+
+void TestingProfile::BlockUntilHistoryProcessesPendingRequests() {
+ DCHECK(history_service_.get());
+ DCHECK(MessageLoop::current());
+
+ CancelableRequestConsumer consumer;
+ history_service_->ScheduleDBTask(new QuittingHistoryDBTask(), &consumer);
+ MessageLoop::current()->Run();
+}
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 416d0db..792402a 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -181,6 +181,11 @@ class TestingProfile : public Profile {
virtual void InitExtensions() {
}
+ // Schedules a task on the history backend and runs a nested loop until the
+ // task is processed. This has the effect of blocking the caller until the
+ // history service processes all pending requests.
+ void BlockUntilHistoryProcessesPendingRequests();
+
#ifdef CHROME_PERSONALIZATION
virtual ProfilePersonalization* GetProfilePersonalization() {
return NULL;