// 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