| Index: components/autofill/core/common/autofill_util.cc
|
| diff --git a/components/autofill/core/common/autofill_util.cc b/components/autofill/core/common/autofill_util.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a313fc9477f453bd5fb52cd05c1dc624d92ca7dd
|
| --- /dev/null
|
| +++ b/components/autofill/core/common/autofill_util.cc
|
| @@ -0,0 +1,85 @@
|
| +// Copyright 2015 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/autofill/core/common/autofill_util.h"
|
| +
|
| +#include <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "base/command_line.h"
|
| +#include "base/i18n/case_conversion.h"
|
| +#include "base/strings/string_piece.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "components/autofill/core/common/autofill_switches.h"
|
| +
|
| +namespace autofill {
|
| +
|
| +namespace {
|
| +
|
| +const char kSplitCharacters[] = " .,-_@";
|
| +
|
| +template <typename Char>
|
| +struct Compare : base::CaseInsensitiveCompareASCII<Char> {
|
| + explicit Compare(bool case_sensitive) : case_sensitive_(case_sensitive) {}
|
| + bool operator()(Char x, Char y) const {
|
| + return case_sensitive_ ? (x == y)
|
| + : base::CaseInsensitiveCompareASCII<Char>::
|
| + operator()(x, y);
|
| + }
|
| +
|
| + private:
|
| + bool case_sensitive_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +bool IsFeatureSubstringMatchEnabled() {
|
| + return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableSuggestionsWithSubstringMatch);
|
| +}
|
| +
|
| +bool FieldIsSuggestionSubstringStartingOnTokenBoundary(
|
| + const base::string16& suggestion,
|
| + const base::string16& field_contents,
|
| + bool case_sensitive) {
|
| + if (!IsFeatureSubstringMatchEnabled()) {
|
| + return base::StartsWith(suggestion, field_contents,
|
| + case_sensitive
|
| + ? base::CompareCase::SENSITIVE
|
| + : base::CompareCase::INSENSITIVE_ASCII);
|
| + }
|
| +
|
| + return suggestion.length() >= field_contents.length() &&
|
| + GetTextSelectionStart(suggestion, field_contents, case_sensitive) !=
|
| + base::string16::npos;
|
| +}
|
| +
|
| +size_t GetTextSelectionStart(const base::string16& suggestion,
|
| + const base::string16& field_contents,
|
| + bool case_sensitive) {
|
| + const base::string16 kSplitChars = base::ASCIIToUTF16(kSplitCharacters);
|
| +
|
| + // Loop until we find either the |field_contents| is a prefix of |suggestion|
|
| + // or character right before the match is one of the splitting characters.
|
| + for (base::string16::const_iterator it = suggestion.begin();
|
| + (it = std::search(
|
| + it, suggestion.end(), field_contents.begin(), field_contents.end(),
|
| + Compare<base::string16::value_type>(case_sensitive))) !=
|
| + suggestion.end();
|
| + ++it) {
|
| + if (it == suggestion.begin() ||
|
| + kSplitChars.find(*(it - 1)) != std::string::npos) {
|
| + // Returns the character position right after the |field_contents| within
|
| + // |suggestion| text as a caret position for text selection.
|
| + return it - suggestion.begin() + field_contents.size();
|
| + }
|
| + }
|
| +
|
| + // Unable to find the |field_contents| in |suggestion| text.
|
| + return base::string16::npos;
|
| +}
|
| +
|
| +} // namespace autofill
|
|
|