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