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