Commit 80dc1ec7 authored by mattreynolds's avatar mattreynolds Committed by Commit bot

Factor out AutocompleteMatch creation from BookmarkProvider

Move the logic for converting from TitledUrlMatch items to
AutocompleteMatch items out of BookmarkProvider into places where it can
be shared with other AutocompleteProviders.

BUG=630769

Review-Url: https://codereview.chromium.org/2583763003
Cr-Commit-Position: refs/heads/master@{#442009}
parent ba3bd9c5
...@@ -100,6 +100,7 @@ source_set("unit_tests") { ...@@ -100,6 +100,7 @@ source_set("unit_tests") {
"bookmark_index_unittest.cc", "bookmark_index_unittest.cc",
"bookmark_model_unittest.cc", "bookmark_model_unittest.cc",
"bookmark_utils_unittest.cc", "bookmark_utils_unittest.cc",
"titled_url_match_unittest.cc",
] ]
if (toolkit_views) { if (toolkit_views) {
......
...@@ -29,6 +29,9 @@ struct TitledUrlMatch; ...@@ -29,6 +29,9 @@ struct TitledUrlMatch;
// TitledUrlNodes that contain that string in their title or URL. // TitledUrlNodes that contain that string in their title or URL.
class TitledUrlIndex { class TitledUrlIndex {
public: public:
// Constructs a TitledUrlIndex. |sorter| is used to construct a sorted list
// of matches when matches are returned from the index. If null, matches are
// returned unsorted.
TitledUrlIndex(std::unique_ptr<TitledUrlNodeSorter> sorter); TitledUrlIndex(std::unique_ptr<TitledUrlNodeSorter> sorter);
~TitledUrlIndex(); ~TitledUrlIndex();
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/bookmarks/browser/titled_url_match.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace bookmarks {
using MatchPositions = TitledUrlMatch::MatchPositions;
TEST(TitledUrlMatchTest, EmptyOffsetsForEmptyMatchPositions) {
auto offsets = TitledUrlMatch::OffsetsFromMatchPositions(MatchPositions());
EXPECT_TRUE(offsets.empty());
}
TEST(TitledUrlMatchTest, OffsetsFromMatchPositions) {
MatchPositions match_positions = {{1, 3}, {4, 5}, {10, 15}};
std::vector<size_t> expected_offsets = {1, 3, 4, 5, 10, 15};
auto offsets = TitledUrlMatch::OffsetsFromMatchPositions(match_positions);
EXPECT_TRUE(
std::equal(offsets.begin(), offsets.end(), expected_offsets.begin()));
}
TEST(TitledUrlMatchTest, ReplaceOffsetsInEmptyMatchPositions) {
auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions(
MatchPositions(), std::vector<size_t>());
EXPECT_TRUE(match_positions.empty());
}
TEST(TitledUrlMatchTest, ReplaceOffsetsInMatchPositions) {
MatchPositions orig_match_positions = {{1, 3}, {4, 5}, {10, 15}};
std::vector<size_t> offsets = {0, 2, 3, 4, 9, 14};
MatchPositions expected_match_positions = {{0, 2}, {3, 4}, {9, 14}};
auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions(
orig_match_positions, offsets);
EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(),
expected_match_positions.begin()));
}
TEST(TitledUrlMatchTest, ReplaceOffsetsRemovesItemsWithNposOffsets) {
MatchPositions orig_match_positions = {{1, 3}, {4, 5}, {10, 15}, {17, 20}};
std::vector<size_t> offsets = {0,
base::string16::npos,
base::string16::npos,
4,
base::string16::npos,
base::string16::npos,
17,
20};
MatchPositions expected_match_positions = {{17, 20}};
auto match_positions = TitledUrlMatch::ReplaceOffsetsInMatchPositions(
orig_match_positions, offsets);
EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(),
expected_match_positions.begin()));
}
}
...@@ -95,6 +95,8 @@ static_library("browser") { ...@@ -95,6 +95,8 @@ static_library("browser") {
"shortcuts_provider.h", "shortcuts_provider.h",
"suggestion_answer.cc", "suggestion_answer.cc",
"suggestion_answer.h", "suggestion_answer.h",
"titled_url_match_utils.cc",
"titled_url_match_utils.h",
"url_index_private_data.cc", "url_index_private_data.cc",
"url_index_private_data.h", "url_index_private_data.h",
"url_prefix.cc", "url_prefix.cc",
...@@ -243,6 +245,7 @@ source_set("unit_tests") { ...@@ -243,6 +245,7 @@ source_set("unit_tests") {
"shortcuts_database_unittest.cc", "shortcuts_database_unittest.cc",
"shortcuts_provider_unittest.cc", "shortcuts_provider_unittest.cc",
"suggestion_answer_unittest.cc", "suggestion_answer_unittest.cc",
"titled_url_match_utils_unittest.cc",
"url_prefix_unittest.cc", "url_prefix_unittest.cc",
"zero_suggest_provider_unittest.cc", "zero_suggest_provider_unittest.cc",
] ]
......
...@@ -17,40 +17,14 @@ ...@@ -17,40 +17,14 @@
#include "components/metrics/proto/omnibox_input_type.pb.h" #include "components/metrics/proto/omnibox_input_type.pb.h"
#include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/omnibox/browser/autocomplete_provider_client.h"
#include "components/omnibox/browser/autocomplete_result.h" #include "components/omnibox/browser/autocomplete_result.h"
#include "components/omnibox/browser/history_provider.h" #include "components/omnibox/browser/titled_url_match_utils.h"
#include "components/omnibox/browser/url_prefix.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/url_formatter/url_formatter.h"
#include "url/url_constants.h" #include "url/url_constants.h"
using bookmarks::BookmarkNode; using bookmarks::BookmarkNode;
using bookmarks::TitledUrlMatch; using bookmarks::TitledUrlMatch;
using TitledUrlMatches = std::vector<TitledUrlMatch>; using TitledUrlMatches = std::vector<TitledUrlMatch>;
namespace {
// Removes leading spaces from |title| before displaying, otherwise it looks
// funny. In the process, corrects |title_match_positions| so the correct
// characters are highlighted.
void CorrectTitleAndMatchPositions(
base::string16* title,
TitledUrlMatch::MatchPositions* title_match_positions) {
size_t leading_whitespace_chars = title->length();
base::TrimWhitespace(*title, base::TRIM_LEADING, title);
leading_whitespace_chars-= title->length();
if (leading_whitespace_chars == 0)
return;
for (query_parser::Snippet::MatchPositions::iterator it =
title_match_positions->begin();
it != title_match_positions->end(); ++it) {
(*it) = query_parser::Snippet::MatchPosition(
it->first - leading_whitespace_chars,
it->second - leading_whitespace_chars);
}
}
} // namespace
// BookmarkProvider ------------------------------------------------------------ // BookmarkProvider ------------------------------------------------------------
BookmarkProvider::BookmarkProvider(AutocompleteProviderClient* client) BookmarkProvider::BookmarkProvider(AutocompleteProviderClient* client)
...@@ -107,13 +81,15 @@ void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) { ...@@ -107,13 +81,15 @@ void BookmarkProvider::DoAutocomplete(const AutocompleteInput& input) {
if (matches.empty()) if (matches.empty())
return; // There were no matches. return; // There were no matches.
const base::string16 fixed_up_input(FixupUserInput(input).second); const base::string16 fixed_up_input(FixupUserInput(input).second);
for (TitledUrlMatches::const_iterator i = matches.begin(); i != matches.end(); for (const auto& bookmark_match : matches) {
++i) { // Score the TitledUrlMatch. If its score is greater than 0 then the
// Create and score the AutocompleteMatch. If its score is 0 then the // AutocompleteMatch is created and added to matches_.
// match is discarded. int relevance = CalculateBookmarkMatchRelevance(bookmark_match);
AutocompleteMatch match(TitledUrlMatchToACMatch(input, fixed_up_input, *i)); if (relevance > 0) {
if (match.relevance > 0) matches_.push_back(TitledUrlMatchToAutocompleteMatch(
matches_.push_back(match); bookmark_match, AutocompleteMatchType::BOOKMARK_TITLE, relevance,
this, client_->GetSchemeClassifier(), input, fixed_up_input));
}
} }
// Sort and clip the resulting matches. // Sort and clip the resulting matches.
...@@ -155,69 +131,8 @@ class ScoringFunctor { ...@@ -155,69 +131,8 @@ class ScoringFunctor {
} // namespace } // namespace
AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( int BookmarkProvider::CalculateBookmarkMatchRelevance(
const AutocompleteInput& input, const TitledUrlMatch& bookmark_match) const {
const base::string16& fixed_up_input_text,
const TitledUrlMatch& bookmark_match) {
// The AutocompleteMatch we construct is non-deletable because the only
// way to support this would be to delete the underlying bookmark, which is
// unlikely to be what the user intends.
AutocompleteMatch match(this, 0, false,
AutocompleteMatchType::BOOKMARK_TITLE);
base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle());
TitledUrlMatch::MatchPositions new_title_match_positions =
bookmark_match.title_match_positions;
CorrectTitleAndMatchPositions(&title, &new_title_match_positions);
const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl());
const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec());
size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset(
input.text(), fixed_up_input_text, false, url_utf16);
match.destination_url = url;
const size_t match_start = bookmark_match.url_match_positions.empty() ?
0 : bookmark_match.url_match_positions[0].first;
const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text()) &&
((match_start == base::string16::npos) || (match_start != 0));
std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions(
bookmark_match.url_match_positions);
// In addition to knowing how |offsets| is transformed, we need to know how
// |inline_autocomplete_offset| is transformed. We add it to the end of
// |offsets|, compute how everything is transformed, then remove it from the
// end.
offsets.push_back(inline_autocomplete_offset);
match.contents = url_formatter::FormatUrlWithOffsets(
url, url_formatter::kFormatUrlOmitAll &
~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP),
net::UnescapeRule::SPACES, nullptr, nullptr, &offsets);
inline_autocomplete_offset = offsets.back();
offsets.pop_back();
TitledUrlMatch::MatchPositions new_url_match_positions =
TitledUrlMatch::ReplaceOffsetsInMatchPositions(
bookmark_match.url_match_positions, offsets);
match.contents_class =
ClassificationsFromMatch(new_url_match_positions,
match.contents.size(),
true);
match.fill_into_edit =
AutocompleteInput::FormattedStringWithEquivalentMeaning(
url, match.contents, client_->GetSchemeClassifier());
if (inline_autocomplete_offset != base::string16::npos) {
// |inline_autocomplete_offset| may be beyond the end of the
// |fill_into_edit| if the user has typed an URL with a scheme and the
// last character typed is a slash. That slash is removed by the
// FormatURLWithOffsets call above.
if (inline_autocomplete_offset < match.fill_into_edit.length()) {
match.inline_autocompletion =
match.fill_into_edit.substr(inline_autocomplete_offset);
}
match.allowed_to_be_default_match = match.inline_autocompletion.empty() ||
!HistoryProvider::PreventInlineAutocomplete(input);
}
match.description = title;
match.description_class =
ClassificationsFromMatch(bookmark_match.title_match_positions,
match.description.size(),
false);
// Summary on how a relevance score is determined for the match: // Summary on how a relevance score is determined for the match:
// //
// For each match within the bookmark's title or URL (or both), calculate a // For each match within the bookmark's title or URL (or both), calculate a
...@@ -268,7 +183,9 @@ AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( ...@@ -268,7 +183,9 @@ AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch(
// and, for each additional reference beyond the one for the bookmark being // and, for each additional reference beyond the one for the bookmark being
// scored up to a maximum of three, the score is boosted by a fixed amount // scored up to a maximum of three, the score is boosted by a fixed amount
// given by |kURLCountBoost|, below. // given by |kURLCountBoost|, below.
//
base::string16 title(bookmark_match.node->GetTitledUrlNodeTitle());
const GURL& url(bookmark_match.node->GetTitledUrlNodeUrl());
// Pretend empty titles are identical to the URL. // Pretend empty titles are identical to the URL.
if (title.empty()) if (title.empty())
...@@ -297,46 +214,19 @@ AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch( ...@@ -297,46 +214,19 @@ AutocompleteMatch BookmarkProvider::TitledUrlMatchToACMatch(
const int kMaxBookmarkScore = bookmarklet_without_title_match ? 799 : 1199; const int kMaxBookmarkScore = bookmarklet_without_title_match ? 799 : 1199;
const double kBookmarkScoreRange = const double kBookmarkScoreRange =
static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore); static_cast<double>(kMaxBookmarkScore - kBaseBookmarkScore);
match.relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) + int relevance = static_cast<int>(normalized_sum * kBookmarkScoreRange) +
kBaseBookmarkScore; kBaseBookmarkScore;
// Don't waste any time searching for additional referenced URLs if we // Don't waste any time searching for additional referenced URLs if we
// already have a perfect title match. // already have a perfect title match.
if (match.relevance >= kMaxBookmarkScore) if (relevance >= kMaxBookmarkScore)
return match; return relevance;
// Boost the score if the bookmark's URL is referenced by other bookmarks. // Boost the score if the bookmark's URL is referenced by other bookmarks.
const int kURLCountBoost[4] = { 0, 75, 125, 150 }; const int kURLCountBoost[4] = { 0, 75, 125, 150 };
std::vector<const BookmarkNode*> nodes; std::vector<const BookmarkNode*> nodes;
bookmark_model_->GetNodesByURL(url, &nodes); bookmark_model_->GetNodesByURL(url, &nodes);
DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U); DCHECK_GE(std::min(arraysize(kURLCountBoost), nodes.size()), 1U);
match.relevance += relevance +=
kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1]; kURLCountBoost[std::min(arraysize(kURLCountBoost), nodes.size()) - 1];
match.relevance = std::min(kMaxBookmarkScore, match.relevance); relevance = std::min(kMaxBookmarkScore, relevance);
return match; return relevance;
}
// static
ACMatchClassifications BookmarkProvider::ClassificationsFromMatch(
const query_parser::Snippet::MatchPositions& positions,
size_t text_length,
bool is_url) {
ACMatchClassification::Style url_style =
is_url ? ACMatchClassification::URL : ACMatchClassification::NONE;
ACMatchClassifications classifications;
if (positions.empty()) {
if (text_length > 0)
classifications.push_back(ACMatchClassification(0, url_style));
return classifications;
}
for (query_parser::Snippet::MatchPositions::const_iterator i =
positions.begin();
i != positions.end();
++i) {
AutocompleteMatch::ACMatchClassifications new_class;
AutocompleteMatch::ClassifyLocationInString(i->first, i->second - i->first,
text_length, url_style, &new_class);
classifications = AutocompleteMatch::MergeClassifications(
classifications, new_class);
}
return classifications;
} }
...@@ -12,9 +12,7 @@ ...@@ -12,9 +12,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "components/omnibox/browser/autocomplete_input.h" #include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/autocomplete_provider.h"
#include "components/query_parser/snippet.h"
class AutocompleteProviderClient; class AutocompleteProviderClient;
...@@ -55,24 +53,9 @@ class BookmarkProvider : public AutocompleteProvider { ...@@ -55,24 +53,9 @@ class BookmarkProvider : public AutocompleteProvider {
// |matches_|. // |matches_|.
void DoAutocomplete(const AutocompleteInput& input); void DoAutocomplete(const AutocompleteInput& input);
// Compose an AutocompleteMatch based on |match| that has 1) the URL of // Calculates the relevance score for |match|.
// |match|'s bookmark, and 2) the bookmark's title, not the URL's page int CalculateBookmarkMatchRelevance(
// title, as the description. |input| is used to compute the match's const bookmarks::TitledUrlMatch& match) const;
// inline_autocompletion. |fixed_up_input_text| is used in that way as well;
// it's passed separately so this function doesn't have to compute it.
AutocompleteMatch TitledUrlMatchToACMatch(
const AutocompleteInput& input,
const base::string16& fixed_up_input_text,
const bookmarks::TitledUrlMatch& match);
// Converts |positions| into ACMatchClassifications and returns the
// classifications. |text_length| is used to determine the need to add an
// 'unhighlighted' classification span so the tail of the source string
// properly highlighted.
static ACMatchClassifications ClassificationsFromMatch(
const query_parser::Snippet::MatchPositions& positions,
size_t text_length,
bool is_url);
AutocompleteProviderClient* client_; AutocompleteProviderClient* client_;
bookmarks::BookmarkModel* bookmark_model_; bookmarks::BookmarkModel* bookmark_model_;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "components/omnibox/browser/autocomplete_provider.h" #include "components/omnibox/browser/autocomplete_provider.h"
#include "components/omnibox/browser/mock_autocomplete_provider_client.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h"
#include "components/omnibox/browser/test_scheme_classifier.h" #include "components/omnibox/browser/test_scheme_classifier.h"
#include "components/omnibox/browser/titled_url_match_utils.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -422,8 +423,10 @@ TEST_F(BookmarkProviderTest, InlineAutocompletion) { ...@@ -422,8 +423,10 @@ TEST_F(BookmarkProviderTest, InlineAutocompletion) {
node.SetTitle(base::ASCIIToUTF16(query_data[i].url)); node.SetTitle(base::ASCIIToUTF16(query_data[i].url));
TitledUrlMatch bookmark_match; TitledUrlMatch bookmark_match;
bookmark_match.node = &node; bookmark_match.node = &node;
const AutocompleteMatch& ac_match = provider_->TitledUrlMatchToACMatch( int relevance = provider_->CalculateBookmarkMatchRelevance(bookmark_match);
input, fixed_up_input, bookmark_match); const AutocompleteMatch& ac_match = TitledUrlMatchToAutocompleteMatch(
bookmark_match, AutocompleteMatchType::BOOKMARK_TITLE, relevance,
provider_.get(), classifier_, input, fixed_up_input);
EXPECT_EQ(query_data[i].allowed_to_be_default_match, EXPECT_EQ(query_data[i].allowed_to_be_default_match,
ac_match.allowed_to_be_default_match) << description; ac_match.allowed_to_be_default_match) << description;
EXPECT_EQ(base::ASCIIToUTF16(query_data[i].inline_autocompletion), EXPECT_EQ(base::ASCIIToUTF16(query_data[i].inline_autocompletion),
......
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/omnibox/browser/titled_url_match_utils.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/bookmarks/browser/titled_url_node.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/history_provider.h"
#include "components/omnibox/browser/url_prefix.h"
#include "components/url_formatter/url_formatter.h"
namespace {
// Converts |positions| into ACMatchClassifications and returns the
// classifications. |text_length| is used to determine the need to add an
// 'unhighlighted' classification span so the tail of the source string
// properly highlighted.
ACMatchClassifications ClassificationsFromMatchPositions(
const bookmarks::TitledUrlMatch::MatchPositions& positions,
size_t text_length,
bool is_url) {
ACMatchClassification::Style url_style =
is_url ? ACMatchClassification::URL : ACMatchClassification::NONE;
ACMatchClassifications classifications;
if (positions.empty()) {
if (text_length > 0) {
classifications.push_back(ACMatchClassification(0, url_style));
}
return classifications;
}
for (bookmarks::TitledUrlMatch::MatchPositions::const_iterator i =
positions.begin();
i != positions.end(); ++i) {
AutocompleteMatch::ACMatchClassifications new_class;
AutocompleteMatch::ClassifyLocationInString(
i->first, i->second - i->first, text_length, url_style, &new_class);
classifications =
AutocompleteMatch::MergeClassifications(classifications, new_class);
}
return classifications;
}
} // namespace
namespace bookmarks {
AutocompleteMatch TitledUrlMatchToAutocompleteMatch(
const TitledUrlMatch& titled_url_match,
AutocompleteMatchType::Type type,
int relevance,
AutocompleteProvider* provider,
const AutocompleteSchemeClassifier& scheme_classifier,
const AutocompleteInput& input,
const base::string16& fixed_up_input_text) {
const GURL& url = titled_url_match.node->GetTitledUrlNodeUrl();
base::string16 title = titled_url_match.node->GetTitledUrlNodeTitle();
// The AutocompleteMatch we construct is non-deletable because the only way to
// support this would be to delete the underlying object that created the
// titled_url_match. E.g., for the bookmark provider this would mean deleting
// the underlying bookmark, which is unlikely to be what the user intends.
AutocompleteMatch match(provider, relevance, false, type);
TitledUrlMatch::MatchPositions new_title_match_positions =
titled_url_match.title_match_positions;
CorrectTitleAndMatchPositions(&title, &new_title_match_positions);
const base::string16& url_utf16 = base::UTF8ToUTF16(url.spec());
size_t inline_autocomplete_offset = URLPrefix::GetInlineAutocompleteOffset(
input.text(), fixed_up_input_text, false, url_utf16);
match.destination_url = url;
const size_t match_start =
titled_url_match.url_match_positions.empty()
? 0
: titled_url_match.url_match_positions[0].first;
const bool trim_http =
!AutocompleteInput::HasHTTPScheme(input.text()) &&
((match_start == base::string16::npos) || (match_start != 0));
std::vector<size_t> offsets = TitledUrlMatch::OffsetsFromMatchPositions(
titled_url_match.url_match_positions);
// In addition to knowing how |offsets| is transformed, we need to know how
// |inline_autocomplete_offset| is transformed. We add it to the end of
// |offsets|, compute how everything is transformed, then remove it from the
// end.
offsets.push_back(inline_autocomplete_offset);
match.contents = url_formatter::FormatUrlWithOffsets(
url, url_formatter::kFormatUrlOmitAll &
~(trim_http ? 0 : url_formatter::kFormatUrlOmitHTTP),
net::UnescapeRule::SPACES, nullptr, nullptr, &offsets);
inline_autocomplete_offset = offsets.back();
offsets.pop_back();
TitledUrlMatch::MatchPositions new_url_match_positions =
TitledUrlMatch::ReplaceOffsetsInMatchPositions(
titled_url_match.url_match_positions, offsets);
match.contents_class = ClassificationsFromMatchPositions(
new_url_match_positions, match.contents.size(), true);
match.fill_into_edit =
AutocompleteInput::FormattedStringWithEquivalentMeaning(
url, match.contents, scheme_classifier);
if (inline_autocomplete_offset != base::string16::npos) {
// |inline_autocomplete_offset| may be beyond the end of the
// |fill_into_edit| if the user has typed an URL with a scheme and the
// last character typed is a slash. That slash is removed by the
// FormatURLWithOffsets call above.
if (inline_autocomplete_offset < match.fill_into_edit.length()) {
match.inline_autocompletion =
match.fill_into_edit.substr(inline_autocomplete_offset);
}
match.allowed_to_be_default_match =
match.inline_autocompletion.empty() ||
!HistoryProvider::PreventInlineAutocomplete(input);
}
match.description = title;
match.description_class = ClassificationsFromMatchPositions(
titled_url_match.title_match_positions, match.description.size(), false);
return match;
}
void CorrectTitleAndMatchPositions(
base::string16* title,
TitledUrlMatch::MatchPositions* title_match_positions) {
size_t leading_whitespace_chars = title->length();
base::TrimWhitespace(*title, base::TRIM_LEADING, title);
leading_whitespace_chars -= title->length();
if (leading_whitespace_chars == 0)
return;
for (TitledUrlMatch::MatchPositions::iterator it =
title_match_positions->begin();
it != title_match_positions->end(); ++it) {
it->first -= leading_whitespace_chars;
it->second -= leading_whitespace_chars;
}
}
} // namespace bookmarks
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_
#define COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_
#include "base/strings/string16.h"
#include "components/bookmarks/browser/titled_url_match.h"
#include "components/omnibox/browser/autocomplete_match_type.h"
class AutocompleteInput;
class AutocompleteProvider;
class AutocompleteSchemeClassifier;
struct AutocompleteMatch;
namespace bookmarks {
// Compose an AutocompleteMatch based on |match| that has the match's URL and
// page title, type |type|, and relevance score |relevance|. |input| is used to
// compute the match's inline_autocompletion. |fixed_up_input_text| is used in
// that way as well; it's passed separately so this function doesn't have to
// compute it.
AutocompleteMatch TitledUrlMatchToAutocompleteMatch(
const TitledUrlMatch& match,
AutocompleteMatchType::Type type,
int relevance,
AutocompleteProvider* provider,
const AutocompleteSchemeClassifier& scheme_classifier,
const AutocompleteInput& input,
const base::string16& fixed_up_input_text);
// Removes leading spaces from |title| before displaying, otherwise it looks
// funny. In the process, corrects |title_match_positions| so the correct
// characters are highlighted.
void CorrectTitleAndMatchPositions(
base::string16* title,
TitledUrlMatch::MatchPositions* title_match_positions);
} // namespace bookmarks
#endif // COMPONENTS_OMNIBOX_BROWSER_TITLED_URL_MATCH_UTILS_H_
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/omnibox/browser/titled_url_match_utils.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/bookmarks/browser/titled_url_match.h"
#include "components/bookmarks/browser/titled_url_node.h"
#include "components/metrics/proto/omnibox_event.pb.h"
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_provider.h"
#include "components/omnibox/browser/test_scheme_classifier.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using bookmarks::TitledUrlMatchToAutocompleteMatch;
using bookmarks::CorrectTitleAndMatchPositions;
namespace {
// A simple AutocompleteProvider that does nothing.
class MockAutocompleteProvider : public AutocompleteProvider {
public:
MockAutocompleteProvider(Type type) : AutocompleteProvider(type) {}
void Start(const AutocompleteInput& input, bool minimal_changes) override {}
private:
~MockAutocompleteProvider() override {}
};
class MockTitledUrlNode : public bookmarks::TitledUrlNode {
public:
MockTitledUrlNode(const base::string16& title, const GURL& url)
: title_(title), url_(url) {}
// TitledUrlNode
const base::string16& GetTitledUrlNodeTitle() const override {
return title_;
}
const GURL& GetTitledUrlNodeUrl() const override { return url_; }
private:
base::string16 title_;
GURL url_;
};
} // namespace
bool operator==(const ACMatchClassification& lhs,
const ACMatchClassification& rhs) {
return (lhs.offset == rhs.offset) && (lhs.style == rhs.style);
}
TEST(TitledUrlMatchUtilsTest, TitledUrlMatchToAutocompleteMatch) {
base::string16 input_text(base::ASCIIToUTF16("goo"));
base::string16 match_title(base::ASCIIToUTF16("Google Search"));
base::string16 match_url_string(
base::ASCIIToUTF16("https://www.google.com/"));
GURL match_url(match_url_string);
bookmarks::TitledUrlMatch::MatchPositions title_match_positions = {{0, 3}};
bookmarks::TitledUrlMatch::MatchPositions url_match_positions = {{12, 15}};
AutocompleteMatchType::Type type = AutocompleteMatchType::BOOKMARK_TITLE;
int relevance = 123;
MockTitledUrlNode node(match_title, match_url);
bookmarks::TitledUrlMatch titled_url_match;
titled_url_match.node = &node;
titled_url_match.title_match_positions = title_match_positions;
titled_url_match.url_match_positions = url_match_positions;
scoped_refptr<MockAutocompleteProvider> provider =
new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK);
TestSchemeClassifier classifier;
AutocompleteInput input(input_text, base::string16::npos, std::string(),
GURL(), metrics::OmniboxEventProto::NTP, false, false,
true, true, false, classifier);
const base::string16 fixed_up_input(input_text);
AutocompleteMatch autocomplete_match = TitledUrlMatchToAutocompleteMatch(
titled_url_match, type, relevance, provider.get(), classifier, input,
fixed_up_input);
ACMatchClassifications expected_contents_class = {
{0, ACMatchClassification::URL},
{12, ACMatchClassification::URL | ACMatchClassification::MATCH},
{15, ACMatchClassification::URL},
};
ACMatchClassifications expected_description_class = {
{0, ACMatchClassification::MATCH}, {3, ACMatchClassification::NONE},
};
base::string16 expected_inline_autocompletion(base::ASCIIToUTF16("gle.com"));
base::string16 expected_contents(
base::ASCIIToUTF16("https://www.google.com"));
EXPECT_EQ(provider.get(), autocomplete_match.provider);
EXPECT_EQ(type, autocomplete_match.type);
EXPECT_EQ(relevance, autocomplete_match.relevance);
EXPECT_EQ(match_url, autocomplete_match.destination_url);
EXPECT_EQ(expected_contents, autocomplete_match.contents);
EXPECT_TRUE(std::equal(expected_contents_class.begin(),
expected_contents_class.end(),
autocomplete_match.contents_class.begin()));
EXPECT_EQ(match_title, autocomplete_match.description);
EXPECT_TRUE(std::equal(expected_description_class.begin(),
expected_description_class.end(),
autocomplete_match.description_class.begin()));
EXPECT_EQ(expected_contents, autocomplete_match.fill_into_edit);
EXPECT_TRUE(autocomplete_match.allowed_to_be_default_match);
EXPECT_EQ(expected_inline_autocompletion,
autocomplete_match.inline_autocompletion);
}
TEST(TitledUrlMatchUtilsTest, EmptyInlineAutocompletion) {
// The search term matches the title but not the URL. Since there is no URL
// match, the inline autocompletion string will be empty.
base::string16 input_text(base::ASCIIToUTF16("goo"));
base::string16 match_title(base::ASCIIToUTF16("Email by Google"));
base::string16 match_url_string(base::ASCIIToUTF16("https://www.gmail.com/"));
GURL match_url(match_url_string);
bookmarks::TitledUrlMatch::MatchPositions title_match_positions = {{9, 12}};
bookmarks::TitledUrlMatch::MatchPositions url_match_positions;
AutocompleteMatchType::Type type = AutocompleteMatchType::BOOKMARK_TITLE;
int relevance = 123;
MockTitledUrlNode node(match_title, match_url);
bookmarks::TitledUrlMatch titled_url_match;
titled_url_match.node = &node;
titled_url_match.title_match_positions = title_match_positions;
titled_url_match.url_match_positions = url_match_positions;
scoped_refptr<MockAutocompleteProvider> provider =
new MockAutocompleteProvider(AutocompleteProvider::Type::TYPE_BOOKMARK);
TestSchemeClassifier classifier;
AutocompleteInput input(input_text, base::string16::npos, std::string(),
GURL(), metrics::OmniboxEventProto::NTP, false, false,
true, true, false, classifier);
const base::string16 fixed_up_input(input_text);
AutocompleteMatch autocomplete_match = TitledUrlMatchToAutocompleteMatch(
titled_url_match, type, relevance, provider.get(), classifier, input,
fixed_up_input);
ACMatchClassifications expected_contents_class = {
{0, ACMatchClassification::URL},
};
ACMatchClassifications expected_description_class = {
{0, ACMatchClassification::NONE},
{9, ACMatchClassification::MATCH},
{12, ACMatchClassification::NONE},
};
base::string16 expected_contents(base::ASCIIToUTF16("https://www.gmail.com"));
EXPECT_EQ(provider.get(), autocomplete_match.provider);
EXPECT_EQ(type, autocomplete_match.type);
EXPECT_EQ(relevance, autocomplete_match.relevance);
EXPECT_EQ(match_url, autocomplete_match.destination_url);
EXPECT_EQ(expected_contents, autocomplete_match.contents);
EXPECT_TRUE(std::equal(expected_contents_class.begin(),
expected_contents_class.end(),
autocomplete_match.contents_class.begin()));
EXPECT_EQ(match_title, autocomplete_match.description);
EXPECT_TRUE(std::equal(expected_description_class.begin(),
expected_description_class.end(),
autocomplete_match.description_class.begin()));
EXPECT_EQ(expected_contents, autocomplete_match.fill_into_edit);
EXPECT_FALSE(autocomplete_match.allowed_to_be_default_match);
EXPECT_TRUE(autocomplete_match.inline_autocompletion.empty());
}
TEST(TitledUrlMatchUtilsTest, CorrectTitleAndMatchPositions) {
bookmarks::TitledUrlMatch::MatchPositions match_positions = {{2, 6},
{10, 15}};
base::string16 title = base::ASCIIToUTF16(" Leading whitespace");
bookmarks::TitledUrlMatch::MatchPositions expected_match_positions = {
{0, 4}, {8, 13}};
base::string16 expected_title = base::ASCIIToUTF16("Leading whitespace");
CorrectTitleAndMatchPositions(&title, &match_positions);
EXPECT_EQ(expected_title, title);
EXPECT_TRUE(std::equal(match_positions.begin(), match_positions.end(),
expected_match_positions.begin()));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment