blob: b68b5148bf77725a9ee13fed724448f0eb7adf70 [file] [log] [blame]
// Copyright (c) 2011 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 "base/logging.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "grit/theme_resources.h"
// AutocompleteMatch ----------------------------------------------------------
AutocompleteMatch::AutocompleteMatch()
: provider(NULL),
relevance(0),
deletable(false),
inline_autocomplete_offset(string16::npos),
transition(PageTransition::GENERATED),
is_history_what_you_typed_match(false),
type(SEARCH_WHAT_YOU_TYPED),
template_url(NULL),
starred(false),
from_previous(false) {
}
AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider,
int relevance,
bool deletable,
Type type)
: provider(provider),
relevance(relevance),
deletable(deletable),
inline_autocomplete_offset(string16::npos),
transition(PageTransition::TYPED),
is_history_what_you_typed_match(false),
type(type),
template_url(NULL),
starred(false),
from_previous(false) {
}
AutocompleteMatch::~AutocompleteMatch() {
}
// static
std::string AutocompleteMatch::TypeToString(Type type) {
const char* strings[NUM_TYPES] = {
"url-what-you-typed",
"history-url",
"history-title",
"history-body",
"history-keyword",
"navsuggest",
"search-what-you-typed",
"search-history",
"search-suggest",
"search-other-engine",
"extension-app",
};
DCHECK(arraysize(strings) == NUM_TYPES);
return strings[type];
}
// static
int AutocompleteMatch::TypeToIcon(Type type) {
int icons[NUM_TYPES] = {
IDR_OMNIBOX_HTTP,
IDR_OMNIBOX_HTTP,
IDR_OMNIBOX_HISTORY,
IDR_OMNIBOX_HISTORY,
IDR_OMNIBOX_HISTORY,
IDR_OMNIBOX_HTTP,
IDR_OMNIBOX_SEARCH,
IDR_OMNIBOX_SEARCH,
IDR_OMNIBOX_SEARCH,
IDR_OMNIBOX_SEARCH,
IDR_OMNIBOX_EXTENSION_APP,
};
DCHECK(arraysize(icons) == NUM_TYPES);
return icons[type];
}
// static
bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2) {
// For equal-relevance matches, we sort alphabetically, so that providers
// who return multiple elements at the same priority get a "stable" sort
// across multiple updates.
if (elem1.relevance == elem2.relevance)
return elem1.contents > elem2.contents;
return elem1.relevance > elem2.relevance;
}
// static
bool AutocompleteMatch::DestinationSortFunc(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2) {
// Sort identical destination_urls together. Place the most relevant matches
// first, so that when we call std::unique(), these are the ones that get
// preserved.
return (elem1.destination_url != elem2.destination_url) ?
(elem1.destination_url < elem2.destination_url) :
MoreRelevant(elem1, elem2);
}
// static
bool AutocompleteMatch::DestinationsEqual(const AutocompleteMatch& elem1,
const AutocompleteMatch& elem2) {
return elem1.destination_url == elem2.destination_url;
}
// static
void AutocompleteMatch::ClassifyMatchInString(
const string16& find_text,
const string16& text,
int style,
ACMatchClassifications* classification) {
ClassifyLocationInString(text.find(find_text), find_text.length(),
text.length(), style, classification);
}
void AutocompleteMatch::ClassifyLocationInString(
size_t match_location,
size_t match_length,
size_t overall_length,
int style,
ACMatchClassifications* classification) {
classification->clear();
// Don't classify anything about an empty string
// (AutocompleteMatch::Validate() checks this).
if (overall_length == 0)
return;
// Mark pre-match portion of string (if any).
if (match_location != 0) {
classification->push_back(ACMatchClassification(0, style));
}
// Mark matching portion of string.
if (match_location == string16::npos) {
// No match, above classification will suffice for whole string.
return;
}
// Classifying an empty match makes no sense and will lead to validation
// errors later.
DCHECK(match_length > 0);
classification->push_back(ACMatchClassification(match_location,
(style | ACMatchClassification::MATCH) & ~ACMatchClassification::DIM));
// Mark post-match portion of string (if any).
const size_t after_match(match_location + match_length);
if (after_match < overall_length) {
classification->push_back(ACMatchClassification(after_match, style));
}
}
#ifndef NDEBUG
void AutocompleteMatch::Validate() const {
ValidateClassifications(contents, contents_class);
ValidateClassifications(description, description_class);
}
void AutocompleteMatch::ValidateClassifications(
const string16& text,
const ACMatchClassifications& classifications) const {
if (text.empty()) {
DCHECK(classifications.size() == 0);
return;
}
// The classifications should always cover the whole string.
DCHECK(!classifications.empty()) << "No classification for text";
DCHECK(classifications[0].offset == 0) << "Classification misses beginning";
if (classifications.size() == 1)
return;
// The classifications should always be sorted.
size_t last_offset = classifications[0].offset;
for (ACMatchClassifications::const_iterator i(classifications.begin() + 1);
i != classifications.end(); ++i) {
DCHECK(i->offset > last_offset) << "Classification unsorted";
DCHECK(i->offset < text.length()) << "Classification out of bounds";
last_offset = i->offset;
}
}
#endif