Home | History | Annotate | Download | only in renderer
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/autofill/content/renderer/form_cache.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "components/autofill/content/renderer/form_autofill_util.h"
     10 #include "components/autofill/core/common/autofill_constants.h"
     11 #include "components/autofill/core/common/form_data.h"
     12 #include "components/autofill/core/common/form_data_predictions.h"
     13 #include "components/autofill/core/common/form_field_data.h"
     14 #include "components/autofill/core/common/form_field_data_predictions.h"
     15 #include "grit/component_strings.h"
     16 #include "third_party/WebKit/public/platform/WebString.h"
     17 #include "third_party/WebKit/public/platform/WebVector.h"
     18 #include "third_party/WebKit/public/web/WebDocument.h"
     19 #include "third_party/WebKit/public/web/WebFormControlElement.h"
     20 #include "third_party/WebKit/public/web/WebFormElement.h"
     21 #include "third_party/WebKit/public/web/WebFrame.h"
     22 #include "third_party/WebKit/public/web/WebInputElement.h"
     23 #include "third_party/WebKit/public/web/WebSelectElement.h"
     24 #include "third_party/WebKit/public/web/WebTextAreaElement.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 
     27 using blink::WebDocument;
     28 using blink::WebFormControlElement;
     29 using blink::WebFormElement;
     30 using blink::WebFrame;
     31 using blink::WebInputElement;
     32 using blink::WebSelectElement;
     33 using blink::WebTextAreaElement;
     34 using blink::WebString;
     35 using blink::WebVector;
     36 
     37 namespace autofill {
     38 
     39 // Helper function to discard state of various WebFormElements when they go out
     40 // of web frame's scope. This is done to release memory that we no longer need
     41 // to hold.
     42 // K should inherit from WebFormControlElement as the function looks to extract
     43 // WebFormElement for K.form().
     44 template <class K, class V>
     45 void RemoveOldElements(const WebFrame& frame, std::map<const K, V>* states) {
     46   std::vector<K> to_remove;
     47   for (typename std::map<const K, V>::const_iterator it = states->begin();
     48        it != states->end(); ++it) {
     49     WebFormElement form_element = it->first.form();
     50     if (form_element.isNull()) {
     51       to_remove.push_back(it->first);
     52     } else {
     53       const WebFrame* element_frame = form_element.document().frame();
     54       if (!element_frame || element_frame == &frame)
     55         to_remove.push_back(it->first);
     56     }
     57   }
     58 
     59   for (typename std::vector<K>::const_iterator it = to_remove.begin();
     60        it != to_remove.end(); ++it) {
     61     states->erase(*it);
     62   }
     63 }
     64 
     65 FormCache::FormCache() {
     66 }
     67 
     68 FormCache::~FormCache() {
     69 }
     70 
     71 void FormCache::ExtractForms(const WebFrame& frame,
     72                              std::vector<FormData>* forms) {
     73   ExtractFormsAndFormElements(frame, kRequiredAutofillFields, forms, NULL);
     74 }
     75 
     76 bool FormCache::ExtractFormsAndFormElements(
     77     const WebFrame& frame,
     78     size_t minimum_required_fields,
     79     std::vector<FormData>* forms,
     80     std::vector<WebFormElement>* web_form_elements) {
     81   // Reset the cache for this frame.
     82   ResetFrame(frame);
     83 
     84   WebDocument document = frame.document();
     85   if (document.isNull())
     86     return false;
     87 
     88   web_documents_.insert(document);
     89 
     90   WebVector<WebFormElement> web_forms;
     91   document.forms(web_forms);
     92 
     93   size_t num_fields_seen = 0;
     94   bool has_skipped_forms = false;
     95   for (size_t i = 0; i < web_forms.size(); ++i) {
     96     WebFormElement form_element = web_forms[i];
     97 
     98     std::vector<WebFormControlElement> control_elements;
     99     ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
    100                                 &control_elements);
    101 
    102     size_t num_editable_elements = 0;
    103     for (size_t j = 0; j < control_elements.size(); ++j) {
    104       WebFormControlElement element = control_elements[j];
    105 
    106       // Save original values of <select> elements so we can restore them
    107       // when |ClearFormWithNode()| is invoked.
    108       if (IsSelectElement(element)) {
    109         const WebSelectElement select_element =
    110             element.toConst<WebSelectElement>();
    111         initial_select_values_.insert(std::make_pair(select_element,
    112                                                      select_element.value()));
    113         ++num_editable_elements;
    114       } else if (IsTextAreaElement(element)) {
    115         ++num_editable_elements;
    116       } else {
    117         const WebInputElement input_element =
    118             element.toConst<WebInputElement>();
    119         if (IsCheckableElement(&input_element)) {
    120           initial_checked_state_.insert(
    121               std::make_pair(input_element, input_element.isChecked()));
    122         } else {
    123           ++num_editable_elements;
    124         }
    125       }
    126     }
    127 
    128     // To avoid overly expensive computation, we impose a minimum number of
    129     // allowable fields.  The corresponding maximum number of allowable fields
    130     // is imposed by WebFormElementToFormData().
    131     if (num_editable_elements < minimum_required_fields &&
    132         control_elements.size() > 0) {
    133       has_skipped_forms = true;
    134       continue;
    135     }
    136 
    137     FormData form;
    138     ExtractMask extract_mask =
    139       static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS);
    140 
    141     if (!WebFormElementToFormData(form_element, WebFormControlElement(),
    142                                   REQUIRE_NONE, extract_mask, &form, NULL)) {
    143       continue;
    144     }
    145 
    146     num_fields_seen += form.fields.size();
    147     if (num_fields_seen > kMaxParseableFields)
    148       break;
    149 
    150     if (form.fields.size() >= minimum_required_fields) {
    151       forms->push_back(form);
    152       if (web_form_elements)
    153         web_form_elements->push_back(form_element);
    154     } else {
    155       has_skipped_forms = true;
    156     }
    157   }
    158 
    159   // Return true if there are any WebFormElements skipped, else false.
    160   return has_skipped_forms;
    161 }
    162 
    163 void FormCache::ResetFrame(const WebFrame& frame) {
    164   std::vector<WebDocument> documents_to_delete;
    165   for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
    166        it != web_documents_.end(); ++it) {
    167     const WebFrame* document_frame = it->frame();
    168     if (!document_frame || document_frame == &frame)
    169       documents_to_delete.push_back(*it);
    170   }
    171 
    172   for (std::vector<WebDocument>::const_iterator it =
    173            documents_to_delete.begin();
    174        it != documents_to_delete.end(); ++it) {
    175     web_documents_.erase(*it);
    176   }
    177 
    178   RemoveOldElements(frame, &initial_select_values_);
    179   RemoveOldElements(frame, &initial_checked_state_);
    180 }
    181 
    182 bool FormCache::ClearFormWithElement(const WebInputElement& element) {
    183   WebFormElement form_element = element.form();
    184   if (form_element.isNull())
    185     return false;
    186 
    187   std::vector<WebFormControlElement> control_elements;
    188   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
    189                               &control_elements);
    190   for (size_t i = 0; i < control_elements.size(); ++i) {
    191     WebFormControlElement control_element = control_elements[i];
    192     // Don't modify the value of disabled fields.
    193     if (!control_element.isEnabled())
    194       continue;
    195 
    196     control_element.setAutofilled(false);
    197 
    198     WebInputElement* input_element = toWebInputElement(&control_element);
    199     if (IsTextInput(input_element) || IsMonthInput(input_element)) {
    200       input_element->setValue(base::string16(), true);
    201 
    202       // Clearing the value in the focused node (above) can cause selection
    203       // to be lost. We force selection range to restore the text cursor.
    204       if (element == *input_element) {
    205         int length = input_element->value().length();
    206         input_element->setSelectionRange(length, length);
    207       }
    208     } else if (IsTextAreaElement(control_element)) {
    209       WebTextAreaElement text_area = control_element.to<WebTextAreaElement>();
    210       text_area.setValue(base::string16());
    211       text_area.dispatchFormControlChangeEvent();
    212     } else if (IsSelectElement(control_element)) {
    213       WebSelectElement select_element = control_element.to<WebSelectElement>();
    214 
    215       std::map<const WebSelectElement, base::string16>::const_iterator
    216           initial_value_iter = initial_select_values_.find(select_element);
    217       if (initial_value_iter != initial_select_values_.end() &&
    218           select_element.value() != initial_value_iter->second) {
    219         select_element.setValue(initial_value_iter->second);
    220         select_element.dispatchFormControlChangeEvent();
    221       }
    222     } else {
    223       WebInputElement input_element = control_element.to<WebInputElement>();
    224       DCHECK(IsCheckableElement(&input_element));
    225       std::map<const WebInputElement, bool>::const_iterator it =
    226           initial_checked_state_.find(input_element);
    227       if (it != initial_checked_state_.end() &&
    228           input_element.isChecked() != it->second) {
    229         input_element.setChecked(it->second, true);
    230       }
    231     }
    232   }
    233 
    234   return true;
    235 }
    236 
    237 bool FormCache::ShowPredictions(const FormDataPredictions& form) {
    238   DCHECK_EQ(form.data.fields.size(), form.fields.size());
    239 
    240   // Find the form.
    241   bool found_form = false;
    242   WebFormElement form_element;
    243   for (std::set<WebDocument>::const_iterator it = web_documents_.begin();
    244        it != web_documents_.end() && !found_form; ++it) {
    245     WebVector<WebFormElement> web_forms;
    246     it->forms(web_forms);
    247 
    248     for (size_t i = 0; i < web_forms.size(); ++i) {
    249       form_element = web_forms[i];
    250 
    251       // Note: matching on the form name here which is not guaranteed to be
    252       // unique for the page, nor is it guaranteed to be non-empty.  Ideally, we
    253       // would have a way to uniquely identify the form cross-process.  For now,
    254       // we'll check form name and form action for identity.
    255       // Also note that WebString() == WebString(string16()) does not evaluate
    256       // to |true| -- WebKit distinguishes between a "null" string (lhs) and an
    257       // "empty" string (rhs).  We don't want that distinction, so forcing to
    258       // string16.
    259       base::string16 element_name = GetFormIdentifier(form_element);
    260       GURL action(form_element.document().completeURL(form_element.action()));
    261       if (element_name == form.data.name && action == form.data.action) {
    262         found_form = true;
    263         break;
    264       }
    265     }
    266   }
    267 
    268   if (!found_form)
    269     return false;
    270 
    271   std::vector<WebFormControlElement> control_elements;
    272   ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE,
    273                               &control_elements);
    274   if (control_elements.size() != form.fields.size()) {
    275     // Keep things simple.  Don't show predictions for forms that were modified
    276     // between page load and the server's response to our query.
    277     return false;
    278   }
    279 
    280   for (size_t i = 0; i < control_elements.size(); ++i) {
    281     WebFormControlElement* element = &control_elements[i];
    282 
    283     if (base::string16(element->nameForAutofill()) !=
    284         form.data.fields[i].name) {
    285       // Keep things simple.  Don't show predictions for elements whose names
    286       // were modified between page load and the server's response to our query.
    287       continue;
    288     }
    289 
    290     std::string placeholder = form.fields[i].overall_type;
    291     base::string16 title = l10n_util::GetStringFUTF16(
    292         IDS_AUTOFILL_SHOW_PREDICTIONS_TITLE,
    293         UTF8ToUTF16(form.fields[i].heuristic_type),
    294         UTF8ToUTF16(form.fields[i].server_type),
    295         UTF8ToUTF16(form.fields[i].signature),
    296         UTF8ToUTF16(form.signature),
    297         UTF8ToUTF16(form.experiment_id));
    298     if (!element->hasAttribute("placeholder"))
    299       element->setAttribute("placeholder", WebString(UTF8ToUTF16(placeholder)));
    300     element->setAttribute("title", WebString(title));
    301   }
    302 
    303   return true;
    304 }
    305 
    306 }  // namespace autofill
    307