blob: 1b4260caa1597f68c50769b95ae7625f0c6f807b [file] [log] [blame]
// Copyright (c) 2006-2008 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.
//
// This file provides the implementaiton of the password manager's autocomplete
// component.
#include "webkit/glue/password_autocomplete_listener.h"
#undef LOG
#include "base/logging.h"
#include "webkit/glue/glue_util.h"
namespace webkit_glue {
HTMLInputDelegate::HTMLInputDelegate(WebCore::HTMLInputElement* element)
: element_(element) {
// Reference the element for the lifetime of this delegate.
// element is NULL when testing.
if (element_)
element_->ref();
}
HTMLInputDelegate::~HTMLInputDelegate() {
if (element_)
element_->deref();
}
void HTMLInputDelegate::SetValue(const std::wstring& value) {
element_->setValue(StdWStringToString(value));
}
void HTMLInputDelegate::SetSelectionRange(size_t start, size_t end) {
element_->setSelectionRange(start, end);
}
void HTMLInputDelegate::OnFinishedAutocompleting() {
// This sets the input element to an autofilled state which will result in it
// having a yellow background.
element_->setAutofilled(true);
// Notify any changeEvent listeners.
element_->dispatchFormControlChangeEvent();
}
PasswordAutocompleteListener::PasswordAutocompleteListener(
HTMLInputDelegate* username_delegate,
HTMLInputDelegate* password_delegate,
const PasswordFormDomManager::FillData& data)
: password_delegate_(password_delegate),
username_delegate_(username_delegate),
data_(data) {
}
void PasswordAutocompleteListener::OnBlur(WebCore::HTMLInputElement* element,
const std::wstring& user_input) {
// If this listener exists, its because the password manager had more than
// one match for the password form, which implies it had at least one
// [preferred] username/password pair.
DCHECK(data_.basic_data.values.size() == 2);
// Set the password field to match the current username.
if (data_.basic_data.values[0] == user_input) {
// Preferred username/login is selected.
password_delegate_->SetValue(data_.basic_data.values[1]);
} else if (data_.additional_logins.find(user_input) !=
data_.additional_logins.end()) {
// One of the extra username/logins is selected.
password_delegate_->SetValue(data_.additional_logins[user_input]);
}
password_delegate_->OnFinishedAutocompleting();
}
void PasswordAutocompleteListener::OnInlineAutocompleteNeeded(
WebCore::HTMLInputElement* element,
const std::wstring& user_input) {
// If wait_for_username is true, we only autofill the password when
// the username field is blurred (i.e not inline) with a matching
// username string entered.
if (data_.wait_for_username)
return;
// Look for any suitable matches to current field text.
// TODO(timsteele): The preferred login (in basic_data.values) and
// additional logins could be bundled into the same data structure
// (possibly even as WebCore strings) upon construction of the
// PasswordAutocompleteListener to simplify lookup and save string
// conversions (see SetValue) on each successful call to
// OnInlineAutocompleteNeeded.
if (TryToMatch(user_input,
data_.basic_data.values[0],
data_.basic_data.values[1])) {
return;
}
// Scan additional logins for a match.
for (PasswordFormDomManager::LoginCollection::iterator it =
data_.additional_logins.begin();
it != data_.additional_logins.end();
++it) {
if (TryToMatch(user_input, it->first, it->second))
return;
}
}
bool PasswordAutocompleteListener::TryToMatch(const std::wstring& input,
const std::wstring& username,
const std::wstring& password) {
if (input.compare(0, input.length(), username, 0, input.length()) != 0)
return false;
// Input matches the username, fill in required values.
username_delegate_->SetValue(username);
username_delegate_->SetSelectionRange(input.length(), username.length());
username_delegate_->OnFinishedAutocompleting();
password_delegate_->SetValue(password);
password_delegate_->OnFinishedAutocompleting();
return true;
}
} // webkit_glue