This source file includes following definitions.
- RemoveOldElements
- ExtractForms
- ExtractFormsAndFormElements
- ResetFrame
- ClearFormWithElement
- ShowPredictions
#include "components/autofill/content/renderer/form_cache.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/form_field_data_predictions.h"
#include "grit/component_strings.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebSelectElement.h"
#include "third_party/WebKit/public/web/WebTextAreaElement.h"
#include "ui/base/l10n/l10n_util.h"
using blink::WebDocument;
using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebFrame;
using blink::WebInputElement;
using blink::WebSelectElement;
using blink::WebTextAreaElement;
using blink::WebString;
using blink::WebVector;
namespace autofill {
template <class K, class V>
void RemoveOldElements(const WebFrame& frame, std::map<const K, V>* states) {
std::vector<K> to_remove;
for (typename std::map<const K, V>::const_iterator it = states->begin();
it != states->end(); ++it) {
WebFormElement form_element = it->first.form();
if (form_element.isNull()) {
to_remove.push_back(it->first);
} else {
const WebFrame* element_frame = form_element.document().frame();
if (!element_frame || element_frame == &frame)
to_remove.push_back(it->first);
}
}
for (typename std::vector<K>::const_iterator it = to_remove.begin();
it != to_remove.end(); ++it) {
states->erase(*it);
}
}
FormCache::FormCache() {
}
FormCache::~FormCache() {
}
void FormCache::ExtractForms(const WebFrame& frame,
std::vector<FormData>* forms) {
ExtractFormsAndFormElements(frame, kRequiredAutofillFields, forms, NULL);
}
bool FormCache::ExtractFormsAndFormElements(
const WebFrame& frame,
size_t minimum_required_fields,
std::vector<FormData>* forms,
std::vector<WebFormElement>* web_form_elements) {
ResetFrame(frame);
WebDocument document = frame.document();
if (document.isNull())
return false;
web_documents_.insert(document);
WebVector<WebFormElement> web_forms;
document.forms(web_forms);
size_t num_fields_seen = 0;
bool has_skipped_forms = false;
for (size_t i = 0; i < web_forms.size(); ++i) {
WebFormElement form_element = web_forms[i];
std::vector<WebFormControlElement> control_elements;
ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
&control_elements);
size_t num_editable_elements = 0;
for (size_t j = 0; j < control_elements.size(); ++j) {
WebFormControlElement element = control_elements[j];
if (IsSelectElement(element)) {
const WebSelectElement select_element =
element.toConst<WebSelectElement>();
initial_select_values_.insert(std::make_pair(select_element,
select_element.value()));
++num_editable_elements;
} else if (IsTextAreaElement(element)) {
++num_editable_elements;
} else {
const WebInputElement input_element =
element.toConst<WebInputElement>();
if (IsCheckableElement(&input_element)) {
initial_checked_state_.insert(
std::make_pair(input_element, input_element.isChecked()));
} else {
++num_editable_elements;
}
}
}
if (num_editable_elements < minimum_required_fields &&
control_elements.size() > 0) {
has_skipped_forms = true;
continue;
}
FormData form;
ExtractMask extract_mask =
static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
if (!WebFormElementToFormData(form_element, WebFormControlElement(),
REQUIRE_NONE, extract_mask, &form, NULL)) {
continue;
}
num_fields_seen += form.fields.size();
if (num_fields_seen > kMaxParseableFields)
break;
if (form.fields.size() >= minimum_required_fields) {
forms->push_back(form);
if (web_form_elements)
web_form_elements->push_back(form_element);
} else {
has_skipped_forms = true;
}
}
return has_skipped_forms;
}
void FormCache::ResetFrame(const WebFrame& frame) {
std::vector<WebDocument> documents_to_delete;
for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
it != web_documents_.end(); ++it) {
const WebFrame* document_frame = it->frame();
if (!document_frame || document_frame == &frame)
documents_to_delete.push_back(*it);
}
for (std::vector<WebDocument>::const_iterator it =
documents_to_delete.begin();
it != documents_to_delete.end(); ++it) {
web_documents_.erase(*it);
}
RemoveOldElements(frame, &initial_select_values_);
RemoveOldElements(frame, &initial_checked_state_);
}
bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
WebFormElement form_element = element.form();
if (form_element.isNull())
return false;
std::vector<WebFormControlElement> control_elements;
ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
&control_elements);
for (size_t i = 0; i < control_elements.size(); ++i) {
WebFormControlElement control_element = control_elements[i];
if (!control_element.isEnabled())
continue;
control_element.setAutofilled(false);
WebInputElement* input_element = toWebInputElement(&control_element);
if (IsTextInput(input_element) || IsMonthInput(input_element)) {
input_element->setValue(base::string16(), true);
if (element == *input_element) {
int length = input_element->value().length();
input_element->setSelectionRange(length, length);
}
} else if (IsTextAreaElement(control_element)) {
control_element.setValue(base::string16(), true);
} else if (IsSelectElement(control_element)) {
WebSelectElement select_element = control_element.to<WebSelectElement>();
std::map<const WebSelectElement, base::string16>::const_iterator
initial_value_iter = initial_select_values_.find(select_element);
if (initial_value_iter != initial_select_values_.end() &&
select_element.value() != initial_value_iter->second) {
select_element.setValue(initial_value_iter->second, true);
}
} else {
WebInputElement input_element = control_element.to<WebInputElement>();
DCHECK(IsCheckableElement(&input_element));
std::map<const WebInputElement, bool>::const_iterator it =
initial_checked_state_.find(input_element);
if (it != initial_checked_state_.end() &&
input_element.isChecked() != it->second) {
input_element.setChecked(it->second, true);
}
}
}
return true;
}
bool FormCache::ShowPredictions(const FormDataPredictions& form) {
DCHECK_EQ(form.data.fields.size(), form.fields.size());
bool found_form = false;
WebFormElement form_element;
for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
it != web_documents_.end() && !found_form; ++it) {
WebVector<WebFormElement> web_forms;
it->forms(web_forms);
for (size_t i = 0; i < web_forms.size(); ++i) {
form_element = web_forms[i];
base::string16 element_name = GetFormIdentifier(form_element);
GURL action(form_element.document().completeURL(form_element.action()));
if (element_name == form.data.name && action == form.data.action) {
found_form = true;
break;
}
}
}
if (!found_form)
return false;
std::vector<WebFormControlElement> control_elements;
ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
&control_elements);
if (control_elements.size() != form.fields.size()) {
return false;
}
for (size_t i = 0; i < control_elements.size(); ++i) {
WebFormControlElement* element = &control_elements[i];
if (base::string16(element->nameForAutofill()) !=
form.data.fields[i].name) {
continue;
}
std::string placeholder = form.fields[i].overall_type;
base::string16 title = l10n_util::GetStringFUTF16(
IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
base::UTF8ToUTF16(form.fields[i].heuristic_type),
base::UTF8ToUTF16(form.fields[i].server_type),
base::UTF8ToUTF16(form.fields[i].signature),
base::UTF8ToUTF16(form.signature),
base::UTF8ToUTF16(form.experiment_id));
if (!element->hasAttribute("placeholder")) {
element->setAttribute("placeholder",
WebString(base::UTF8ToUTF16(placeholder)));
}
element->setAttribute("title", WebString(title));
}
return true;
}
}