| Index: components/autofill/core/browser/webdata/autofill_table.cc | 
| diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc | 
| index c337f60223f165cecc20a75e0ae7808ddaf7f800..2ee8455b1ad28d875ce0756145de7afd5be54dd8 100644 | 
| --- a/components/autofill/core/browser/webdata/autofill_table.cc | 
| +++ b/components/autofill/core/browser/webdata/autofill_table.cc | 
| @@ -18,6 +18,7 @@ | 
| #include "base/logging.h" | 
| #include "base/numerics/safe_conversions.h" | 
| #include "base/strings/string_number_conversions.h" | 
| +#include "base/strings/string_util.h" | 
| #include "base/strings/utf_string_conversions.h" | 
| #include "base/time/time.h" | 
| #include "components/autofill/core/browser/autofill_country.h" | 
| @@ -28,6 +29,7 @@ | 
| #include "components/autofill/core/browser/webdata/autofill_change.h" | 
| #include "components/autofill/core/browser/webdata/autofill_entry.h" | 
| #include "components/autofill/core/common/autofill_switches.h" | 
| +#include "components/autofill/core/common/autofill_util.h" | 
| #include "components/autofill/core/common/form_field_data.h" | 
| #include "components/os_crypt/os_crypt.h" | 
| #include "components/webdata/common/web_database.h" | 
| @@ -368,6 +370,28 @@ CreditCard::ServerStatus ServerStatusStringToEnum(const std::string& status) { | 
| return CreditCard::OK; | 
| } | 
|  | 
| +// Returns |s| with |escaper| in front of each of occurrence of a character from | 
| +// |special_chars|. Any occurrence of |escaper| in |s| is doubled. For example, | 
| +// Substitute("hello_world!", "_%", '!'') returns "hello!_world!!". | 
| +base::string16 Substitute(const base::string16& s, | 
| +                          const base::string16& special_chars, | 
| +                          const base::char16& escaper) { | 
| +  // Prepend |escaper| to the list of |special_chars|. | 
| +  base::string16 escape_wildcards(special_chars); | 
| +  escape_wildcards.insert(escape_wildcards.begin(), escaper); | 
| + | 
| +  // Prepend the |escaper| just before |special_chars| in |s|. | 
| +  base::string16 result(s); | 
| +  for (base::char16 c : escape_wildcards) { | 
| +    for (size_t pos = 0; (pos = result.find(c, pos)) != base::string16::npos; | 
| +         pos += 2) { | 
| +      result.insert(result.begin() + pos, escaper); | 
| +    } | 
| +  } | 
| + | 
| +  return result; | 
| +} | 
| + | 
| }  // namespace | 
|  | 
| // The maximum length allowed for form data. | 
| @@ -456,9 +480,10 @@ bool AutofillTable::GetFormValuesForElementName( | 
| std::vector<base::string16>* values, | 
| int limit) { | 
| DCHECK(values); | 
| -  sql::Statement s; | 
| +  bool succeeded = false; | 
|  | 
| if (prefix.empty()) { | 
| +    sql::Statement s; | 
| s.Assign(db_->GetUniqueStatement( | 
| "SELECT value FROM autofill " | 
| "WHERE name = ? " | 
| @@ -466,28 +491,62 @@ bool AutofillTable::GetFormValuesForElementName( | 
| "LIMIT ?")); | 
| s.BindString16(0, name); | 
| s.BindInt(1, limit); | 
| + | 
| +    values->clear(); | 
| +    while (s.Step()) | 
| +      values->push_back(s.ColumnString16(0)); | 
| + | 
| +    succeeded = s.Succeeded(); | 
| } else { | 
| base::string16 prefix_lower = base::i18n::ToLower(prefix); | 
| base::string16 next_prefix = prefix_lower; | 
| next_prefix[next_prefix.length() - 1]++; | 
|  | 
| -    s.Assign(db_->GetUniqueStatement( | 
| +    sql::Statement s1; | 
| +    s1.Assign(db_->GetUniqueStatement( | 
| "SELECT value FROM autofill " | 
| "WHERE name = ? AND " | 
| "value_lower >= ? AND " | 
| "value_lower < ? " | 
| "ORDER BY count DESC " | 
| "LIMIT ?")); | 
| -    s.BindString16(0, name); | 
| -    s.BindString16(1, prefix_lower); | 
| -    s.BindString16(2, next_prefix); | 
| -    s.BindInt(3, limit); | 
| +    s1.BindString16(0, name); | 
| +    s1.BindString16(1, prefix_lower); | 
| +    s1.BindString16(2, next_prefix); | 
| +    s1.BindInt(3, limit); | 
| + | 
| +    values->clear(); | 
| +    while (s1.Step()) | 
| +      values->push_back(s1.ColumnString16(0)); | 
| + | 
| +    succeeded = s1.Succeeded(); | 
| + | 
| +    if (IsFeatureSubstringMatchEnabled()) { | 
| +      sql::Statement s2; | 
| +      s2.Assign(db_->GetUniqueStatement( | 
| +          "SELECT value FROM autofill " | 
| +          "WHERE name = ? AND (" | 
| +          " value LIKE '% ' || :prefix || '%' ESCAPE '!' OR " | 
| +          " value LIKE '%.' || :prefix || '%' ESCAPE '!' OR " | 
| +          " value LIKE '%,' || :prefix || '%' ESCAPE '!' OR " | 
| +          " value LIKE '%-' || :prefix || '%' ESCAPE '!' OR " | 
| +          " value LIKE '%@' || :prefix || '%' ESCAPE '!' OR " | 
| +          " value LIKE '%!_' || :prefix || '%' ESCAPE '!' ) " | 
| +          "ORDER BY count DESC " | 
| +          "LIMIT ?")); | 
| + | 
| +      s2.BindString16(0, name); | 
| +      // escaper as L'!' -> 0x21. | 
| +      s2.BindString16(1, Substitute(prefix_lower, ASCIIToUTF16("_%"), 0x21)); | 
| +      s2.BindInt(2, limit); | 
| +      while (s2.Step()) | 
| +        values->push_back(s2.ColumnString16(0)); | 
| + | 
| +      succeeded &= s2.Succeeded(); | 
| +    } | 
| } | 
|  | 
| -  values->clear(); | 
| -  while (s.Step()) | 
| -    values->push_back(s.ColumnString16(0)); | 
| -  return s.Succeeded(); | 
| +  return succeeded; | 
| } | 
|  | 
| bool AutofillTable::HasFormElements() { | 
|  |