Home | History | Annotate | Download | only in autocomplete
      1 // Copyright (c) 2011 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 "base/logging.h"
      6 #include "chrome/browser/autocomplete/autocomplete_match.h"
      7 #include "grit/theme_resources.h"
      8 
      9 // AutocompleteMatch ----------------------------------------------------------
     10 
     11 AutocompleteMatch::AutocompleteMatch()
     12     : provider(NULL),
     13       relevance(0),
     14       deletable(false),
     15       inline_autocomplete_offset(string16::npos),
     16       transition(PageTransition::GENERATED),
     17       is_history_what_you_typed_match(false),
     18       type(SEARCH_WHAT_YOU_TYPED),
     19       template_url(NULL),
     20       starred(false),
     21       from_previous(false) {
     22 }
     23 
     24 AutocompleteMatch::AutocompleteMatch(AutocompleteProvider* provider,
     25                                      int relevance,
     26                                      bool deletable,
     27                                      Type type)
     28     : provider(provider),
     29       relevance(relevance),
     30       deletable(deletable),
     31       inline_autocomplete_offset(string16::npos),
     32       transition(PageTransition::TYPED),
     33       is_history_what_you_typed_match(false),
     34       type(type),
     35       template_url(NULL),
     36       starred(false),
     37       from_previous(false) {
     38 }
     39 
     40 AutocompleteMatch::~AutocompleteMatch() {
     41 }
     42 
     43 // static
     44 std::string AutocompleteMatch::TypeToString(Type type) {
     45   const char* strings[NUM_TYPES] = {
     46     "url-what-you-typed",
     47     "history-url",
     48     "history-title",
     49     "history-body",
     50     "history-keyword",
     51     "navsuggest",
     52     "search-what-you-typed",
     53     "search-history",
     54     "search-suggest",
     55     "search-other-engine",
     56     "extension-app",
     57   };
     58   DCHECK(arraysize(strings) == NUM_TYPES);
     59   return strings[type];
     60 }
     61 
     62 // static
     63 int AutocompleteMatch::TypeToIcon(Type type) {
     64   int icons[NUM_TYPES] = {
     65     IDR_OMNIBOX_HTTP,
     66     IDR_OMNIBOX_HTTP,
     67     IDR_OMNIBOX_HISTORY,
     68     IDR_OMNIBOX_HISTORY,
     69     IDR_OMNIBOX_HISTORY,
     70     IDR_OMNIBOX_HTTP,
     71     IDR_OMNIBOX_SEARCH,
     72     IDR_OMNIBOX_SEARCH,
     73     IDR_OMNIBOX_SEARCH,
     74     IDR_OMNIBOX_SEARCH,
     75     IDR_OMNIBOX_EXTENSION_APP,
     76   };
     77   DCHECK(arraysize(icons) == NUM_TYPES);
     78   return icons[type];
     79 }
     80 
     81 // static
     82 bool AutocompleteMatch::MoreRelevant(const AutocompleteMatch& elem1,
     83                                      const AutocompleteMatch& elem2) {
     84   // For equal-relevance matches, we sort alphabetically, so that providers
     85   // who return multiple elements at the same priority get a "stable" sort
     86   // across multiple updates.
     87   if (elem1.relevance == elem2.relevance)
     88     return elem1.contents > elem2.contents;
     89 
     90   return elem1.relevance > elem2.relevance;
     91 }
     92 
     93 // static
     94 bool AutocompleteMatch::DestinationSortFunc(const AutocompleteMatch& elem1,
     95                                             const AutocompleteMatch& elem2) {
     96   // Sort identical destination_urls together.  Place the most relevant matches
     97   // first, so that when we call std::unique(), these are the ones that get
     98   // preserved.
     99   return (elem1.destination_url != elem2.destination_url) ?
    100       (elem1.destination_url < elem2.destination_url) :
    101       MoreRelevant(elem1, elem2);
    102 }
    103 
    104 // static
    105 bool AutocompleteMatch::DestinationsEqual(const AutocompleteMatch& elem1,
    106                                           const AutocompleteMatch& elem2) {
    107   return elem1.destination_url == elem2.destination_url;
    108 }
    109 
    110 // static
    111 void AutocompleteMatch::ClassifyMatchInString(
    112     const string16& find_text,
    113     const string16& text,
    114     int style,
    115     ACMatchClassifications* classification) {
    116   ClassifyLocationInString(text.find(find_text), find_text.length(),
    117                            text.length(), style, classification);
    118 }
    119 
    120 void AutocompleteMatch::ClassifyLocationInString(
    121     size_t match_location,
    122     size_t match_length,
    123     size_t overall_length,
    124     int style,
    125     ACMatchClassifications* classification) {
    126   classification->clear();
    127 
    128   // Don't classify anything about an empty string
    129   // (AutocompleteMatch::Validate() checks this).
    130   if (overall_length == 0)
    131     return;
    132 
    133   // Mark pre-match portion of string (if any).
    134   if (match_location != 0) {
    135     classification->push_back(ACMatchClassification(0, style));
    136   }
    137 
    138   // Mark matching portion of string.
    139   if (match_location == string16::npos) {
    140     // No match, above classification will suffice for whole string.
    141     return;
    142   }
    143   // Classifying an empty match makes no sense and will lead to validation
    144   // errors later.
    145   DCHECK(match_length > 0);
    146   classification->push_back(ACMatchClassification(match_location,
    147       (style | ACMatchClassification::MATCH) & ~ACMatchClassification::DIM));
    148 
    149   // Mark post-match portion of string (if any).
    150   const size_t after_match(match_location + match_length);
    151   if (after_match < overall_length) {
    152     classification->push_back(ACMatchClassification(after_match, style));
    153   }
    154 }
    155 
    156 #ifndef NDEBUG
    157 void AutocompleteMatch::Validate() const {
    158   ValidateClassifications(contents, contents_class);
    159   ValidateClassifications(description, description_class);
    160 }
    161 
    162 void AutocompleteMatch::ValidateClassifications(
    163     const string16& text,
    164     const ACMatchClassifications& classifications) const {
    165   if (text.empty()) {
    166     DCHECK(classifications.size() == 0);
    167     return;
    168   }
    169 
    170   // The classifications should always cover the whole string.
    171   DCHECK(!classifications.empty()) << "No classification for text";
    172   DCHECK(classifications[0].offset == 0) << "Classification misses beginning";
    173   if (classifications.size() == 1)
    174     return;
    175 
    176   // The classifications should always be sorted.
    177   size_t last_offset = classifications[0].offset;
    178   for (ACMatchClassifications::const_iterator i(classifications.begin() + 1);
    179        i != classifications.end(); ++i) {
    180     DCHECK(i->offset > last_offset) << "Classification unsorted";
    181     DCHECK(i->offset < text.length()) << "Classification out of bounds";
    182     last_offset = i->offset;
    183   }
    184 }
    185 #endif
    186