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