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