普通文本  |  412行  |  10.89 KB

// 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 "chrome/browser/autofill/contact_info.h"

#include <stddef.h>
#include <ostream>
#include <string>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/field_types.h"

static const string16 kNameSplitChars = ASCIIToUTF16("-'. ");

static const AutofillFieldType kAutofillNameInfoTypes[] = {
  NAME_FIRST,
  NAME_MIDDLE,
  NAME_LAST
};

static const size_t kAutofillNameInfoLength =
    arraysize(kAutofillNameInfoTypes);

NameInfo::NameInfo() {}

NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
  *this = info;
}

NameInfo::~NameInfo() {}

NameInfo& NameInfo::operator=(const NameInfo& info) {
  if (this == &info)
    return *this;

  first_tokens_ = info.first_tokens_;
  middle_tokens_ = info.middle_tokens_;
  last_tokens_ = info.last_tokens_;
  first_ = info.first_;
  middle_ = info.middle_;
  last_ = info.last_;
  return *this;
}

void NameInfo::GetPossibleFieldTypes(const string16& text,
                                        FieldTypeSet* possible_types) const {
  DCHECK(possible_types);

  if (IsFirstName(text))
    possible_types->insert(NAME_FIRST);

  if (IsMiddleName(text))
    possible_types->insert(NAME_MIDDLE);

  if (IsLastName(text))
    possible_types->insert(NAME_LAST);

  if (IsMiddleInitial(text))
    possible_types->insert(NAME_MIDDLE_INITIAL);

  if (IsFullName(text))
    possible_types->insert(NAME_FULL);
}

void NameInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
  DCHECK(available_types);

  if (!first().empty())
    available_types->insert(NAME_FIRST);

  if (!middle().empty())
    available_types->insert(NAME_MIDDLE);

  if (!last().empty())
    available_types->insert(NAME_LAST);

  if (!MiddleInitial().empty())
    available_types->insert(NAME_MIDDLE_INITIAL);

  if (!FullName().empty())
    available_types->insert(NAME_FULL);
}

string16 NameInfo::GetInfo(AutofillFieldType type) const {
  if (type == NAME_FIRST)
    return first();

  if (type == NAME_MIDDLE)
    return middle();

  if (type == NAME_LAST)
    return last();

  if (type == NAME_MIDDLE_INITIAL)
    return MiddleInitial();

  if (type == NAME_FULL)
    return FullName();

  return string16();
}

void NameInfo::SetInfo(AutofillFieldType type, const string16& value) {
  DCHECK_EQ(AutofillType::NAME, AutofillType(type).group());
  if (type == NAME_FIRST)
    SetFirst(value);
  else if (type == NAME_MIDDLE || type == NAME_MIDDLE_INITIAL)
    SetMiddle(value);
  else if (type == NAME_LAST)
    SetLast(value);
  else if (type == NAME_FULL)
    SetFullName(value);
  else
    NOTREACHED();
}

string16 NameInfo::FullName() const {
  if (first_.empty())
    return string16();

  std::vector<string16> full_name;
  full_name.push_back(first_);

  if (!middle_.empty())
    full_name.push_back(middle_);

  if (!last_.empty())
    full_name.push_back(last_);

  return JoinString(full_name, ' ');
}

string16 NameInfo::MiddleInitial() const {
  if (middle_.empty())
    return string16();

  string16 middle_name(middle());
  string16 initial;
  initial.push_back(middle_name[0]);
  return initial;
}

// If each of the 'words' contained in the text are also present in the first
// name then we will consider the text to be of type kFirstName. This means
// that people with multiple first names will be able to enter any one of
// their first names and have it correctly recognized.
bool NameInfo::IsFirstName(const string16& text) const {
  return IsNameMatch(text, first_tokens_);
}

// If each of the 'words' contained in the text are also present in the middle
// name then we will consider the text to be of type kMiddleName.
bool NameInfo::IsMiddleName(const string16& text) const {
  return IsNameMatch(text, middle_tokens_);
}

// If each of the 'words' contained in the text are also present in the last
// name then we will consider the text to be of type kLastName.
bool NameInfo::IsLastName(const string16& text) const {
  return IsNameMatch(text, last_tokens_);
}

bool NameInfo::IsMiddleInitial(const string16& text) const {
  if (text.length() != 1)
     return false;

  string16 lower_case = StringToLowerASCII(text);
  // If the text entered was a single character and it matches the first letter
  // of any of the given middle names then we consider it to be a middle
  // initial field.
  size_t middle_tokens_size = middle_tokens_.size();
  for (size_t i = 0; i < middle_tokens_size; ++i) {
    if (middle_tokens_[i][0] == lower_case[0])
      return true;
  }

  return false;
}

// A field will be considered to be of type NAME_FULL if:
//    1) it contains at least one word from the first name.
//    2) it contains at least one word from the last name.
//    3) all of the words in the field match a word in either the first,
//       middle, or last name.
bool NameInfo::IsFullName(const string16& text) const {
  size_t first_tokens_size = first_tokens_.size();
  if (first_tokens_size == 0)
    return false;

  size_t middle_tokens_size = middle_tokens_.size();

  size_t last_tokens_size = last_tokens_.size();
  if (last_tokens_size == 0)
    return false;

  std::vector<string16> text_tokens;
  Tokenize(text, kNameSplitChars, &text_tokens);
  size_t text_tokens_size = text_tokens.size();
  if (text_tokens_size == 0 || text_tokens_size < 2)
    return false;

  size_t name_tokens_size =
      first_tokens_size + middle_tokens_size + last_tokens_size;
  if (text_tokens_size > name_tokens_size)
    return false;

  bool first_name_match = false;
  bool last_name_match = false;
  for (std::vector<string16>::iterator iter = text_tokens.begin();
       iter != text_tokens.end(); ++iter) {
    bool match = false;
    if (IsWordInName(*iter, first_tokens_)) {
      match = true;
      first_name_match = true;
    }

    if (IsWordInName(*iter, last_tokens_)) {
      match = true;
      last_name_match = true;
    }

    if (IsWordInName(*iter, middle_tokens_))
      match = true;

    if (!match)
      return false;
  }

  return (first_name_match && last_name_match);
}

bool NameInfo::IsNameMatch(const string16& text,
                           const std::vector<string16>& name_tokens) const {
  size_t name_tokens_size = name_tokens.size();
  if (name_tokens_size == 0)
    return false;

  std::vector<string16> text_tokens;
  Tokenize(text, kNameSplitChars, &text_tokens);
  size_t text_tokens_size = text_tokens.size();
  if (text_tokens_size == 0)
    return false;

  if (text_tokens_size > name_tokens_size)
    return false;

  // If each of the 'words' contained in the text are also present in the name,
  // then we will consider the text to match the name.
  for (std::vector<string16>::iterator iter = text_tokens.begin();
       iter != text_tokens.end(); ++iter) {
    if (!IsWordInName(*iter, name_tokens))
      return false;
  }

  return true;
}

bool NameInfo::IsWordInName(const string16& word,
                            const std::vector<string16>& name_tokens) const {
  for (std::vector<string16>::const_iterator iter = name_tokens.begin();
       iter != name_tokens.end(); ++iter) {
    // |*iter| is already lower-cased.
    if (StringToLowerASCII(word) == *iter)
      return true;
  }

  return false;
}

void NameInfo::SetFirst(const string16& first) {
  first_ = first;
  first_tokens_.clear();
  Tokenize(first, kNameSplitChars, &first_tokens_);
  for (std::vector<string16>::iterator iter = first_tokens_.begin();
       iter != first_tokens_.end(); ++iter) {
    *iter = StringToLowerASCII(*iter);
  }
}

void NameInfo::SetMiddle(const string16& middle) {
  middle_ = middle;
  middle_tokens_.clear();
  Tokenize(middle, kNameSplitChars, &middle_tokens_);
  for (std::vector<string16>::iterator iter = middle_tokens_.begin();
       iter != middle_tokens_.end(); ++iter) {
    *iter = StringToLowerASCII(*iter);
  }
}

void NameInfo::SetLast(const string16& last) {
  last_ = last;
  last_tokens_.clear();
  Tokenize(last, kNameSplitChars, &last_tokens_);
  for (std::vector<string16>::iterator iter = last_tokens_.begin();
       iter != last_tokens_.end(); ++iter) {
    *iter = StringToLowerASCII(*iter);
  }
}

void NameInfo::SetFullName(const string16& full) {
  std::vector<string16> full_name_tokens;
  Tokenize(full, ASCIIToUTF16(" "), &full_name_tokens);
  // Clear the names.
  SetFirst(string16());
  SetMiddle(string16());
  SetLast(string16());

  // There are four possibilities: empty; first name; first and last names;
  // first, middle (possibly multiple strings) and then the last name.
  if (full_name_tokens.size() > 0) {
    SetFirst(full_name_tokens[0]);
    if (full_name_tokens.size() > 1) {
      SetLast(full_name_tokens.back());
      if (full_name_tokens.size() > 2) {
        full_name_tokens.erase(full_name_tokens.begin());
        full_name_tokens.pop_back();
        SetMiddle(JoinString(full_name_tokens, ' '));
      }
    }
  }
}

EmailInfo::EmailInfo() {}

EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
  *this = info;
}

EmailInfo::~EmailInfo() {}

EmailInfo& EmailInfo::operator=(const EmailInfo& info) {
  if (this == &info)
    return *this;

  email_ = info.email_;
  return *this;
}

void EmailInfo::GetPossibleFieldTypes(const string16& text,
                                      FieldTypeSet* possible_types) const {
  DCHECK(possible_types);
  // TODO(isherman): Investigate case-insensitive comparison.
  if (email_ == text)
    possible_types->insert(EMAIL_ADDRESS);
}

void EmailInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
  DCHECK(available_types);
  if (!email_.empty())
    available_types->insert(EMAIL_ADDRESS);
}

string16 EmailInfo::GetInfo(AutofillFieldType type) const {
  if (type == EMAIL_ADDRESS)
    return email_;

  return string16();
}

void EmailInfo::SetInfo(AutofillFieldType type, const string16& value) {
  DCHECK_EQ(EMAIL_ADDRESS, type);
  email_ = value;
}

CompanyInfo::CompanyInfo() {}

CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() {
  *this = info;
}

CompanyInfo::~CompanyInfo() {}

CompanyInfo& CompanyInfo::operator=(const CompanyInfo& info) {
  if (this == &info)
    return *this;

  company_name_ = info.company_name_;
  return *this;
}

void CompanyInfo::GetPossibleFieldTypes(const string16& text,
                                        FieldTypeSet* possible_types) const {
  DCHECK(possible_types);

  if (company_name_ == text)
    possible_types->insert(COMPANY_NAME);
}

void CompanyInfo::GetAvailableFieldTypes(FieldTypeSet* available_types) const {
  DCHECK(available_types);

  if (!company_name_.empty())
    available_types->insert(COMPANY_NAME);
}

string16 CompanyInfo::GetInfo(AutofillFieldType type) const {
  if (type == COMPANY_NAME)
    return company_name_;

  return string16();
}

void CompanyInfo::SetInfo(AutofillFieldType type, const string16& value) {
  DCHECK_EQ(COMPANY_NAME, type);
  company_name_ = value;
}