1// Copyright (c) 2012 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 "chrome/browser/autocomplete/history_provider.h"
6
7#include <string>
8
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "chrome/browser/bookmarks/bookmark_model_factory.h"
12#include "chrome/browser/history/history_service.h"
13#include "chrome/browser/history/history_service_factory.h"
14#include "chrome/browser/history/in_memory_url_index_types.h"
15#include "chrome/browser/profiles/profile.h"
16#include "chrome/common/url_constants.h"
17#include "components/bookmarks/browser/bookmark_model.h"
18#include "components/omnibox/autocomplete_input.h"
19#include "components/omnibox/autocomplete_match.h"
20#include "url/url_util.h"
21
22void HistoryProvider::DeleteMatch(const AutocompleteMatch& match) {
23  DCHECK(done_);
24  DCHECK(profile_);
25  DCHECK(match.deletable);
26
27  HistoryService* const history_service =
28      HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
29
30  // Delete the underlying URL along with all its visits from the history DB.
31  // The resulting HISTORY_URLS_DELETED notification will also cause all caches
32  // and indices to drop any data they might have stored pertaining to the URL.
33  DCHECK(history_service);
34  DCHECK(match.destination_url.is_valid());
35  history_service->DeleteURL(match.destination_url);
36
37  DeleteMatchFromMatches(match);
38}
39
40// static
41bool HistoryProvider::PreventInlineAutocomplete(
42    const AutocompleteInput& input) {
43  return input.prevent_inline_autocomplete() ||
44      (!input.text().empty() &&
45       IsWhitespace(input.text()[input.text().length() - 1]));
46}
47
48HistoryProvider::HistoryProvider(Profile* profile,
49                                 AutocompleteProvider::Type type)
50    : AutocompleteProvider(type),
51      profile_(profile) {
52}
53
54HistoryProvider::~HistoryProvider() {}
55
56void HistoryProvider::DeleteMatchFromMatches(const AutocompleteMatch& match) {
57  bool found = false;
58  BookmarkModel* bookmark_model = BookmarkModelFactory::GetForProfile(profile_);
59  for (ACMatches::iterator i(matches_.begin()); i != matches_.end(); ++i) {
60    if (i->destination_url == match.destination_url && i->type == match.type) {
61      found = true;
62      if (i->is_history_what_you_typed_match ||
63          (bookmark_model &&
64           bookmark_model->IsBookmarked(i->destination_url))) {
65        // We can't get rid of What-You-Typed or Bookmarked matches,
66        // but we can make them look like they have no backing data.
67        i->deletable = false;
68        i->description.clear();
69        i->description_class.clear();
70      } else {
71        matches_.erase(i);
72      }
73      break;
74    }
75  }
76  DCHECK(found) << "Asked to delete a URL that isn't in our set of matches";
77}
78
79// static
80ACMatchClassifications HistoryProvider::SpansFromTermMatch(
81    const history::TermMatches& matches,
82    size_t text_length,
83    bool is_url) {
84  ACMatchClassification::Style url_style =
85      is_url ? ACMatchClassification::URL : ACMatchClassification::NONE;
86  ACMatchClassifications spans;
87  if (matches.empty()) {
88    if (text_length)
89      spans.push_back(ACMatchClassification(0, url_style));
90    return spans;
91  }
92  if (matches[0].offset)
93    spans.push_back(ACMatchClassification(0, url_style));
94  size_t match_count = matches.size();
95  for (size_t i = 0; i < match_count;) {
96    size_t offset = matches[i].offset;
97    spans.push_back(ACMatchClassification(offset,
98        ACMatchClassification::MATCH | url_style));
99    // Skip all adjacent matches.
100    do {
101      offset += matches[i].length;
102      ++i;
103    } while ((i < match_count) && (offset == matches[i].offset));
104    if (offset < text_length)
105      spans.push_back(ACMatchClassification(offset, url_style));
106  }
107
108  return spans;
109}
110