| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/autofill/content/renderer/form_autofill_util.h" | 5 #include "components/autofill/content/renderer/form_autofill_util.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 element.hasHTMLTagName("td") || | 151 element.hasHTMLTagName("td") || |
| 152 element.hasHTMLTagName("table"); | 152 element.hasHTMLTagName("table"); |
| 153 } | 153 } |
| 154 | 154 |
| 155 // Returns the colspan for a <td> / <th>. Defaults to 1. | 155 // Returns the colspan for a <td> / <th>. Defaults to 1. |
| 156 size_t CalculateTableCellColumnSpan(const WebElement& element) { | 156 size_t CalculateTableCellColumnSpan(const WebElement& element) { |
| 157 DCHECK(element.hasHTMLTagName("td") || element.hasHTMLTagName("th")); | 157 DCHECK(element.hasHTMLTagName("td") || element.hasHTMLTagName("th")); |
| 158 | 158 |
| 159 size_t span = 1; | 159 size_t span = 1; |
| 160 if (element.hasAttribute("colspan")) { | 160 if (element.hasAttribute("colspan")) { |
| 161 base::string16 colspan = element.getAttribute("colspan"); | 161 base::string16 colspan = element.getAttribute("colspan").utf16(); |
| 162 // Do not check return value to accept imperfect conversions. | 162 // Do not check return value to accept imperfect conversions. |
| 163 base::StringToSizeT(colspan, &span); | 163 base::StringToSizeT(colspan, &span); |
| 164 // Handle overflow. | 164 // Handle overflow. |
| 165 if (span == std::numeric_limits<size_t>::max()) | 165 if (span == std::numeric_limits<size_t>::max()) |
| 166 span = 1; | 166 span = 1; |
| 167 span = std::max(span, static_cast<size_t>(1)); | 167 span = std::max(span, static_cast<size_t>(1)); |
| 168 } | 168 } |
| 169 | 169 |
| 170 return span; | 170 return span; |
| 171 } | 171 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 (element.isFormControlElement() && | 230 (element.isFormControlElement() && |
| 231 IsAutofillableElement(element.toConst<WebFormControlElement>()))) { | 231 IsAutofillableElement(element.toConst<WebFormControlElement>()))) { |
| 232 return base::string16(); | 232 return base::string16(); |
| 233 } | 233 } |
| 234 | 234 |
| 235 if (element.hasHTMLTagName("div") && base::ContainsKey(divs_to_skip, node)) | 235 if (element.hasHTMLTagName("div") && base::ContainsKey(divs_to_skip, node)) |
| 236 return base::string16(); | 236 return base::string16(); |
| 237 } | 237 } |
| 238 | 238 |
| 239 // Extract the text exactly at this node. | 239 // Extract the text exactly at this node. |
| 240 base::string16 node_text = node.nodeValue(); | 240 base::string16 node_text = node.nodeValue().utf16(); |
| 241 | 241 |
| 242 // Recursively compute the children's text. | 242 // Recursively compute the children's text. |
| 243 // Preserve inter-element whitespace separation. | 243 // Preserve inter-element whitespace separation. |
| 244 base::string16 child_text = | 244 base::string16 child_text = |
| 245 FindChildTextInner(node.firstChild(), depth - 1, divs_to_skip); | 245 FindChildTextInner(node.firstChild(), depth - 1, divs_to_skip); |
| 246 bool add_space = node.isTextNode() && node_text.empty(); | 246 bool add_space = node.isTextNode() && node_text.empty(); |
| 247 node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space); | 247 node_text = CombineAndCollapseWhitespace(node_text, child_text, add_space); |
| 248 | 248 |
| 249 // Recursively compute the siblings' text. | 249 // Recursively compute the siblings' text. |
| 250 // Again, preserve inter-element whitespace separation. | 250 // Again, preserve inter-element whitespace separation. |
| 251 base::string16 sibling_text = | 251 base::string16 sibling_text = |
| 252 FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip); | 252 FindChildTextInner(node.nextSibling(), depth - 1, divs_to_skip); |
| 253 add_space = node.isTextNode() && node_text.empty(); | 253 add_space = node.isTextNode() && node_text.empty(); |
| 254 node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space); | 254 node_text = CombineAndCollapseWhitespace(node_text, sibling_text, add_space); |
| 255 | 255 |
| 256 return node_text; | 256 return node_text; |
| 257 } | 257 } |
| 258 | 258 |
| 259 // Same as FindChildText() below, but with a list of div nodes to skip. | 259 // Same as FindChildText() below, but with a list of div nodes to skip. |
| 260 // TODO(thestig): See if other FindChildText() callers can benefit from this. | 260 // TODO(thestig): See if other FindChildText() callers can benefit from this. |
| 261 base::string16 FindChildTextWithIgnoreList( | 261 base::string16 FindChildTextWithIgnoreList( |
| 262 const WebNode& node, | 262 const WebNode& node, |
| 263 const std::set<WebNode>& divs_to_skip) { | 263 const std::set<WebNode>& divs_to_skip) { |
| 264 if (node.isTextNode()) | 264 if (node.isTextNode()) |
| 265 return node.nodeValue(); | 265 return node.nodeValue().utf16(); |
| 266 | 266 |
| 267 WebNode child = node.firstChild(); | 267 WebNode child = node.firstChild(); |
| 268 | 268 |
| 269 const int kChildSearchDepth = 10; | 269 const int kChildSearchDepth = 10; |
| 270 base::string16 node_text = | 270 base::string16 node_text = |
| 271 FindChildTextInner(child, kChildSearchDepth, divs_to_skip); | 271 FindChildTextInner(child, kChildSearchDepth, divs_to_skip); |
| 272 base::TrimWhitespace(node_text, base::TRIM_ALL, &node_text); | 272 base::TrimWhitespace(node_text, base::TRIM_ALL, &node_text); |
| 273 return node_text; | 273 return node_text; |
| 274 } | 274 } |
| 275 | 275 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 // Useful for cases like: <span><input type="checkbox">Label For Checkbox</span> | 363 // Useful for cases like: <span><input type="checkbox">Label For Checkbox</span> |
| 364 base::string16 InferLabelFromNext(const WebFormControlElement& element) { | 364 base::string16 InferLabelFromNext(const WebFormControlElement& element) { |
| 365 return InferLabelFromSibling(element, true /* forward? */); | 365 return InferLabelFromSibling(element, true /* forward? */); |
| 366 } | 366 } |
| 367 | 367 |
| 368 // Helper for |InferLabelForElement()| that infers a label, if possible, from | 368 // Helper for |InferLabelForElement()| that infers a label, if possible, from |
| 369 // the placeholder text. e.g. <input placeholder="foo"> | 369 // the placeholder text. e.g. <input placeholder="foo"> |
| 370 base::string16 InferLabelFromPlaceholder(const WebFormControlElement& element) { | 370 base::string16 InferLabelFromPlaceholder(const WebFormControlElement& element) { |
| 371 CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder")); | 371 CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder")); |
| 372 if (element.hasAttribute(kPlaceholder)) | 372 if (element.hasAttribute(kPlaceholder)) |
| 373 return element.getAttribute(kPlaceholder); | 373 return element.getAttribute(kPlaceholder).utf16(); |
| 374 | 374 |
| 375 return base::string16(); | 375 return base::string16(); |
| 376 } | 376 } |
| 377 | 377 |
| 378 // Helper for |InferLabelForElement()| that infers a label, from | 378 // Helper for |InferLabelForElement()| that infers a label, from |
| 379 // the value attribute when it is present and user has not typed in (if | 379 // the value attribute when it is present and user has not typed in (if |
| 380 // element's value attribute is same as the element's value). | 380 // element's value attribute is same as the element's value). |
| 381 base::string16 InferLabelFromValueAttr(const WebFormControlElement& element) { | 381 base::string16 InferLabelFromValueAttr(const WebFormControlElement& element) { |
| 382 CR_DEFINE_STATIC_LOCAL(WebString, kValue, ("value")); | 382 CR_DEFINE_STATIC_LOCAL(WebString, kValue, ("value")); |
| 383 if (element.hasAttribute(kValue) && element.getAttribute(kValue) == | 383 if (element.hasAttribute(kValue) && element.getAttribute(kValue) == |
| 384 element.value()) { | 384 element.value()) { |
| 385 return element.getAttribute(kValue); | 385 return element.getAttribute(kValue).utf16(); |
| 386 } | 386 } |
| 387 | 387 |
| 388 return base::string16(); | 388 return base::string16(); |
| 389 } | 389 } |
| 390 | 390 |
| 391 // Helper for |InferLabelForElement()| that infers a label, if possible, from | 391 // Helper for |InferLabelForElement()| that infers a label, if possible, from |
| 392 // enclosing list item, | 392 // enclosing list item, |
| 393 // e.g. <li>Some Text<input ...><input ...><input ...></li> | 393 // e.g. <li>Some Text<input ...><input ...><input ...></li> |
| 394 base::string16 InferLabelFromListItem(const WebFormControlElement& element) { | 394 base::string16 InferLabelFromListItem(const WebFormControlElement& element) { |
| 395 WebNode parent = element.parentNode(); | 395 WebNode parent = element.parentNode(); |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 759 // the browser, without entirely breaking autocomplete for some extreme | 759 // the browser, without entirely breaking autocomplete for some extreme |
| 760 // legitimate sites: http://crbug.com/49332 and http://crbug.com/363094 | 760 // legitimate sites: http://crbug.com/49332 and http://crbug.com/363094 |
| 761 if (list_items.size() > kMaxListSize) | 761 if (list_items.size() > kMaxListSize) |
| 762 return; | 762 return; |
| 763 | 763 |
| 764 option_values->reserve(list_items.size()); | 764 option_values->reserve(list_items.size()); |
| 765 option_contents->reserve(list_items.size()); | 765 option_contents->reserve(list_items.size()); |
| 766 for (size_t i = 0; i < list_items.size(); ++i) { | 766 for (size_t i = 0; i < list_items.size(); ++i) { |
| 767 if (IsOptionElement(list_items[i])) { | 767 if (IsOptionElement(list_items[i])) { |
| 768 const WebOptionElement option = list_items[i].toConst<WebOptionElement>(); | 768 const WebOptionElement option = list_items[i].toConst<WebOptionElement>(); |
| 769 option_values->push_back(option.value()); | 769 option_values->push_back(option.value().utf16()); |
| 770 option_contents->push_back(option.text()); | 770 option_contents->push_back(option.text().utf16()); |
| 771 } | 771 } |
| 772 } | 772 } |
| 773 } | 773 } |
| 774 | 774 |
| 775 // The callback type used by |ForEachMatchingFormField()|. | 775 // The callback type used by |ForEachMatchingFormField()|. |
| 776 typedef void (*Callback)(const FormFieldData&, | 776 typedef void (*Callback)(const FormFieldData&, |
| 777 bool, /* is_initiating_element */ | 777 bool, /* is_initiating_element */ |
| 778 blink::WebFormControlElement*); | 778 blink::WebFormControlElement*); |
| 779 | 779 |
| 780 void ForEachMatchingFormFieldCommon( | 780 void ForEachMatchingFormFieldCommon( |
| (...skipping 12 matching lines...) Expand all Loading... |
| 793 } | 793 } |
| 794 | 794 |
| 795 // It's possible that the site has injected fields into the form after the | 795 // It's possible that the site has injected fields into the form after the |
| 796 // page has loaded, so we can't assert that the size of the cached control | 796 // page has loaded, so we can't assert that the size of the cached control |
| 797 // elements is equal to the size of the fields in |form|. Fortunately, the | 797 // elements is equal to the size of the fields in |form|. Fortunately, the |
| 798 // one case in the wild where this happens, paypal.com signup form, the fields | 798 // one case in the wild where this happens, paypal.com signup form, the fields |
| 799 // are appended to the end of the form and are not visible. | 799 // are appended to the end of the form and are not visible. |
| 800 for (size_t i = 0; i < control_elements->size(); ++i) { | 800 for (size_t i = 0; i < control_elements->size(); ++i) { |
| 801 WebFormControlElement* element = &(*control_elements)[i]; | 801 WebFormControlElement* element = &(*control_elements)[i]; |
| 802 | 802 |
| 803 if (base::string16(element->nameForAutofill()) != data.fields[i].name) { | 803 if (element->nameForAutofill().utf16() != data.fields[i].name) { |
| 804 // This case should be reachable only for pathological websites, which | 804 // This case should be reachable only for pathological websites, which |
| 805 // rename form fields while the user is interacting with the Autofill | 805 // rename form fields while the user is interacting with the Autofill |
| 806 // popup. I (isherman) am not aware of any such websites, and so am | 806 // popup. I (isherman) am not aware of any such websites, and so am |
| 807 // optimistically including a NOTREACHED(). If you ever trip this check, | 807 // optimistically including a NOTREACHED(). If you ever trip this check, |
| 808 // please file a bug against me. | 808 // please file a bug against me. |
| 809 NOTREACHED(); | 809 NOTREACHED(); |
| 810 continue; | 810 continue; |
| 811 } | 811 } |
| 812 | 812 |
| 813 bool is_initiating_element = (*element == initiating_element); | 813 bool is_initiating_element = (*element == initiating_element); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 WebInputElement* input_element = toWebInputElement(field); | 894 WebInputElement* input_element = toWebInputElement(field); |
| 895 if (IsCheckableElement(input_element)) { | 895 if (IsCheckableElement(input_element)) { |
| 896 input_element->setChecked(IsChecked(data.check_status), true); | 896 input_element->setChecked(IsChecked(data.check_status), true); |
| 897 } else { | 897 } else { |
| 898 base::string16 value = data.value; | 898 base::string16 value = data.value; |
| 899 if (IsTextInput(input_element) || IsMonthInput(input_element)) { | 899 if (IsTextInput(input_element) || IsMonthInput(input_element)) { |
| 900 // If the maxlength attribute contains a negative value, maxLength() | 900 // If the maxlength attribute contains a negative value, maxLength() |
| 901 // returns the default maxlength value. | 901 // returns the default maxlength value. |
| 902 TruncateString(&value, input_element->maxLength()); | 902 TruncateString(&value, input_element->maxLength()); |
| 903 } | 903 } |
| 904 field->setAutofillValue(value); | 904 field->setAutofillValue(blink::WebString::fromUTF16(value)); |
| 905 } | 905 } |
| 906 // Setting the form might trigger JavaScript, which is capable of | 906 // Setting the form might trigger JavaScript, which is capable of |
| 907 // destroying the frame. | 907 // destroying the frame. |
| 908 if (!field->document().frame()) | 908 if (!field->document().frame()) |
| 909 return; | 909 return; |
| 910 | 910 |
| 911 field->setAutofilled(true); | 911 field->setAutofilled(true); |
| 912 | 912 |
| 913 if (is_initiating_node && | 913 if (is_initiating_node && |
| 914 ((IsTextInput(input_element) || IsMonthInput(input_element)) || | 914 ((IsTextInput(input_element) || IsMonthInput(input_element)) || |
| (...skipping 17 matching lines...) Expand all Loading... |
| 932 if (!data.is_autofilled) | 932 if (!data.is_autofilled) |
| 933 return; | 933 return; |
| 934 | 934 |
| 935 // Preview input, textarea and select fields. For input fields, excludes | 935 // Preview input, textarea and select fields. For input fields, excludes |
| 936 // checkboxes and radio buttons, as there is no provision for | 936 // checkboxes and radio buttons, as there is no provision for |
| 937 // setSuggestedCheckedValue in WebInputElement. | 937 // setSuggestedCheckedValue in WebInputElement. |
| 938 WebInputElement* input_element = toWebInputElement(field); | 938 WebInputElement* input_element = toWebInputElement(field); |
| 939 if (IsTextInput(input_element) || IsMonthInput(input_element)) { | 939 if (IsTextInput(input_element) || IsMonthInput(input_element)) { |
| 940 // If the maxlength attribute contains a negative value, maxLength() | 940 // If the maxlength attribute contains a negative value, maxLength() |
| 941 // returns the default maxlength value. | 941 // returns the default maxlength value. |
| 942 input_element->setSuggestedValue( | 942 input_element->setSuggestedValue(blink::WebString::fromUTF16( |
| 943 data.value.substr(0, input_element->maxLength())); | 943 data.value.substr(0, input_element->maxLength()))); |
| 944 input_element->setAutofilled(true); | 944 input_element->setAutofilled(true); |
| 945 } else if (IsTextAreaElement(*field) || IsSelectElement(*field)) { | 945 } else if (IsTextAreaElement(*field) || IsSelectElement(*field)) { |
| 946 field->setSuggestedValue(data.value); | 946 field->setSuggestedValue(blink::WebString::fromUTF16(data.value)); |
| 947 field->setAutofilled(true); | 947 field->setAutofilled(true); |
| 948 } | 948 } |
| 949 | 949 |
| 950 if (is_initiating_node && | 950 if (is_initiating_node && |
| 951 (IsTextInput(input_element) || IsTextAreaElement(*field))) { | 951 (IsTextInput(input_element) || IsTextAreaElement(*field))) { |
| 952 // Select the part of the text that the user didn't type. | 952 // Select the part of the text that the user didn't type. |
| 953 PreviewSuggestion(field->suggestedValue(), field->value(), field); | 953 PreviewSuggestion(field->suggestedValue().utf16(), field->value().utf16(), |
| 954 field); |
| 954 } | 955 } |
| 955 } | 956 } |
| 956 | 957 |
| 957 // Extracts the fields from |control_elements| with |extract_mask| to | 958 // Extracts the fields from |control_elements| with |extract_mask| to |
| 958 // |form_fields|. The extracted fields are also placed in |element_map|. | 959 // |form_fields|. The extracted fields are also placed in |element_map|. |
| 959 // |form_fields| and |element_map| should start out empty. | 960 // |form_fields| and |element_map| should start out empty. |
| 960 // |fields_extracted| should have as many elements as |control_elements|, | 961 // |fields_extracted| should have as many elements as |control_elements|, |
| 961 // initialized to false. | 962 // initialized to false. |
| 962 // Returns true if the number of fields extracted is within | 963 // Returns true if the number of fields extracted is within |
| 963 // [1, kMaxParseableFields]. | 964 // [1, kMaxParseableFields]. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 | 1011 |
| 1011 for (WebElement item = labels.firstItem(); !item.isNull(); | 1012 for (WebElement item = labels.firstItem(); !item.isNull(); |
| 1012 item = labels.nextItem()) { | 1013 item = labels.nextItem()) { |
| 1013 WebLabelElement label = item.to<WebLabelElement>(); | 1014 WebLabelElement label = item.to<WebLabelElement>(); |
| 1014 WebElement control = label.correspondingControl(); | 1015 WebElement control = label.correspondingControl(); |
| 1015 FormFieldData* field_data = nullptr; | 1016 FormFieldData* field_data = nullptr; |
| 1016 | 1017 |
| 1017 if (control.isNull()) { | 1018 if (control.isNull()) { |
| 1018 // Sometimes site authors will incorrectly specify the corresponding | 1019 // Sometimes site authors will incorrectly specify the corresponding |
| 1019 // field element's name rather than its id, so we compensate here. | 1020 // field element's name rather than its id, so we compensate here. |
| 1020 base::string16 element_name = label.getAttribute(kFor); | 1021 base::string16 element_name = label.getAttribute(kFor).utf16(); |
| 1021 if (element_name.empty()) | 1022 if (element_name.empty()) |
| 1022 continue; | 1023 continue; |
| 1023 // Look through the list for elements with this name. There can actually | 1024 // Look through the list for elements with this name. There can actually |
| 1024 // be more than one. In this case, the label may not be particularly | 1025 // be more than one. In this case, the label may not be particularly |
| 1025 // useful, so just discard it. | 1026 // useful, so just discard it. |
| 1026 for (const auto& iter : *element_map) { | 1027 for (const auto& iter : *element_map) { |
| 1027 if (iter.second->name == element_name) { | 1028 if (iter.second->name == element_name) { |
| 1028 if (field_data) { | 1029 if (field_data) { |
| 1029 field_data = nullptr; | 1030 field_data = nullptr; |
| 1030 break; | 1031 break; |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1312 return element->isCheckbox() || element->isRadioButton(); | 1313 return element->isCheckbox() || element->isRadioButton(); |
| 1313 } | 1314 } |
| 1314 | 1315 |
| 1315 bool IsAutofillableInputElement(const WebInputElement* element) { | 1316 bool IsAutofillableInputElement(const WebInputElement* element) { |
| 1316 return IsTextInput(element) || | 1317 return IsTextInput(element) || |
| 1317 IsMonthInput(element) || | 1318 IsMonthInput(element) || |
| 1318 IsCheckableElement(element); | 1319 IsCheckableElement(element); |
| 1319 } | 1320 } |
| 1320 | 1321 |
| 1321 const base::string16 GetFormIdentifier(const WebFormElement& form) { | 1322 const base::string16 GetFormIdentifier(const WebFormElement& form) { |
| 1322 base::string16 identifier = form.name(); | 1323 base::string16 identifier = form.name().utf16(); |
| 1323 CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id")); | 1324 CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id")); |
| 1324 if (identifier.empty()) | 1325 if (identifier.empty()) |
| 1325 identifier = form.getAttribute(kId); | 1326 identifier = form.getAttribute(kId).utf16(); |
| 1326 | 1327 |
| 1327 return identifier; | 1328 return identifier; |
| 1328 } | 1329 } |
| 1329 | 1330 |
| 1330 bool IsWebNodeVisible(const blink::WebNode& node) { | 1331 bool IsWebNodeVisible(const blink::WebNode& node) { |
| 1331 // TODO(esprehn): This code doesn't really check if the node is visible, just | 1332 // TODO(esprehn): This code doesn't really check if the node is visible, just |
| 1332 // if the node takes up space in the layout. Does it want to check opacity, | 1333 // if the node takes up space in the layout. Does it want to check opacity, |
| 1333 // transform, and visibility too? | 1334 // transform, and visibility too? |
| 1334 if (!node.isElementNode()) | 1335 if (!node.isElementNode()) |
| 1335 return false; | 1336 return false; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1366 DCHECK(field); | 1367 DCHECK(field); |
| 1367 DCHECK(!element.isNull()); | 1368 DCHECK(!element.isNull()); |
| 1368 CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete")); | 1369 CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete")); |
| 1369 CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id")); | 1370 CR_DEFINE_STATIC_LOCAL(WebString, kId, ("id")); |
| 1370 CR_DEFINE_STATIC_LOCAL(WebString, kRole, ("role")); | 1371 CR_DEFINE_STATIC_LOCAL(WebString, kRole, ("role")); |
| 1371 CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder")); | 1372 CR_DEFINE_STATIC_LOCAL(WebString, kPlaceholder, ("placeholder")); |
| 1372 CR_DEFINE_STATIC_LOCAL(WebString, kClass, ("class")); | 1373 CR_DEFINE_STATIC_LOCAL(WebString, kClass, ("class")); |
| 1373 | 1374 |
| 1374 // Save both id and name attributes, if present. If there is only one of them, | 1375 // Save both id and name attributes, if present. If there is only one of them, |
| 1375 // it will be saved to |name|. See HTMLFormControlElement::nameForAutofill. | 1376 // it will be saved to |name|. See HTMLFormControlElement::nameForAutofill. |
| 1376 field->name = element.nameForAutofill(); | 1377 field->name = element.nameForAutofill().utf16(); |
| 1377 base::string16 id = element.getAttribute(kId); | 1378 base::string16 id = element.getAttribute(kId).utf16(); |
| 1378 if (id != field->name) | 1379 if (id != field->name) |
| 1379 field->id = id; | 1380 field->id = id; |
| 1380 | 1381 |
| 1381 field->form_control_type = element.formControlType().utf8(); | 1382 field->form_control_type = element.formControlType().utf8(); |
| 1382 field->autocomplete_attribute = element.getAttribute(kAutocomplete).utf8(); | 1383 field->autocomplete_attribute = element.getAttribute(kAutocomplete).utf8(); |
| 1383 if (field->autocomplete_attribute.size() > kMaxDataLength) { | 1384 if (field->autocomplete_attribute.size() > kMaxDataLength) { |
| 1384 // Discard overly long attribute values to avoid DOS-ing the browser | 1385 // Discard overly long attribute values to avoid DOS-ing the browser |
| 1385 // process. However, send over a default string to indicate that the | 1386 // process. However, send over a default string to indicate that the |
| 1386 // attribute was present. | 1387 // attribute was present. |
| 1387 field->autocomplete_attribute = "x-max-data-length-exceeded"; | 1388 field->autocomplete_attribute = "x-max-data-length-exceeded"; |
| 1388 } | 1389 } |
| 1389 if (base::LowerCaseEqualsASCII( | 1390 if (base::LowerCaseEqualsASCII(element.getAttribute(kRole).utf16(), |
| 1390 base::StringPiece16(element.getAttribute(kRole)), "presentation")) | 1391 "presentation")) |
| 1391 field->role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION; | 1392 field->role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION; |
| 1392 | 1393 |
| 1393 field->placeholder = element.getAttribute(kPlaceholder); | 1394 field->placeholder = element.getAttribute(kPlaceholder).utf16(); |
| 1394 if (element.hasAttribute(kClass)) | 1395 if (element.hasAttribute(kClass)) |
| 1395 field->css_classes = element.getAttribute(kClass); | 1396 field->css_classes = element.getAttribute(kClass).utf16(); |
| 1396 | 1397 |
| 1397 if (field_value_and_properties_map) { | 1398 if (field_value_and_properties_map) { |
| 1398 FieldValueAndPropertiesMaskMap::const_iterator it = | 1399 FieldValueAndPropertiesMaskMap::const_iterator it = |
| 1399 field_value_and_properties_map->find(element); | 1400 field_value_and_properties_map->find(element); |
| 1400 if (it != field_value_and_properties_map->end()) | 1401 if (it != field_value_and_properties_map->end()) |
| 1401 field->properties_mask = it->second.second; | 1402 field->properties_mask = it->second.second; |
| 1402 } | 1403 } |
| 1403 | 1404 |
| 1404 if (!IsAutofillableElement(element)) | 1405 if (!IsAutofillableElement(element)) |
| 1405 return; | 1406 return; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1436 DCHECK(IsSelectElement(element)); | 1437 DCHECK(IsSelectElement(element)); |
| 1437 const WebSelectElement select_element = element.toConst<WebSelectElement>(); | 1438 const WebSelectElement select_element = element.toConst<WebSelectElement>(); |
| 1438 GetOptionStringsFromElement(select_element, | 1439 GetOptionStringsFromElement(select_element, |
| 1439 &field->option_values, | 1440 &field->option_values, |
| 1440 &field->option_contents); | 1441 &field->option_contents); |
| 1441 } | 1442 } |
| 1442 | 1443 |
| 1443 if (!(extract_mask & EXTRACT_VALUE)) | 1444 if (!(extract_mask & EXTRACT_VALUE)) |
| 1444 return; | 1445 return; |
| 1445 | 1446 |
| 1446 base::string16 value = element.value(); | 1447 base::string16 value = element.value().utf16(); |
| 1447 | 1448 |
| 1448 if (IsSelectElement(element) && (extract_mask & EXTRACT_OPTION_TEXT)) { | 1449 if (IsSelectElement(element) && (extract_mask & EXTRACT_OPTION_TEXT)) { |
| 1449 const WebSelectElement select_element = element.toConst<WebSelectElement>(); | 1450 const WebSelectElement select_element = element.toConst<WebSelectElement>(); |
| 1450 // Convert the |select_element| value to text if requested. | 1451 // Convert the |select_element| value to text if requested. |
| 1451 WebVector<WebElement> list_items = select_element.listItems(); | 1452 WebVector<WebElement> list_items = select_element.listItems(); |
| 1452 for (size_t i = 0; i < list_items.size(); ++i) { | 1453 for (size_t i = 0; i < list_items.size(); ++i) { |
| 1453 if (IsOptionElement(list_items[i])) { | 1454 if (IsOptionElement(list_items[i])) { |
| 1454 const WebOptionElement option_element = | 1455 const WebOptionElement option_element = |
| 1455 list_items[i].toConst<WebOptionElement>(); | 1456 list_items[i].toConst<WebOptionElement>(); |
| 1456 if (option_element.value() == value) { | 1457 if (option_element.value().utf16() == value) { |
| 1457 value = option_element.text(); | 1458 value = option_element.text().utf16(); |
| 1458 break; | 1459 break; |
| 1459 } | 1460 } |
| 1460 } | 1461 } |
| 1461 } | 1462 } |
| 1462 } | 1463 } |
| 1463 | 1464 |
| 1464 // Constrain the maximum data length to prevent a malicious site from DOS'ing | 1465 // Constrain the maximum data length to prevent a malicious site from DOS'ing |
| 1465 // the browser: http://crbug.com/49332 | 1466 // the browser: http://crbug.com/49332 |
| 1466 TruncateString(&value, kMaxDataLength); | 1467 TruncateString(&value, kMaxDataLength); |
| 1467 | 1468 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1547 if (!lang.empty() && | 1548 if (!lang.empty() && |
| 1548 !base::StartsWith(lang, "en", base::CompareCase::INSENSITIVE_ASCII)) { | 1549 !base::StartsWith(lang, "en", base::CompareCase::INSENSITIVE_ASCII)) { |
| 1549 return UnownedFormElementsAndFieldSetsToFormData( | 1550 return UnownedFormElementsAndFieldSetsToFormData( |
| 1550 fieldsets, control_elements, element, document, nullptr, extract_mask, | 1551 fieldsets, control_elements, element, document, nullptr, extract_mask, |
| 1551 form, field); | 1552 form, field); |
| 1552 } | 1553 } |
| 1553 | 1554 |
| 1554 // A potential problem is that this only checks document.title(), but should | 1555 // A potential problem is that this only checks document.title(), but should |
| 1555 // actually check the main frame's title. Thus it may make bad decisions for | 1556 // actually check the main frame's title. Thus it may make bad decisions for |
| 1556 // iframes. | 1557 // iframes. |
| 1557 base::string16 title(base::ToLowerASCII(base::string16(document.title()))); | 1558 base::string16 title(base::ToLowerASCII(document.title().utf16())); |
| 1558 | 1559 |
| 1559 // Don't check the path for url's without a standard format path component, | 1560 // Don't check the path for url's without a standard format path component, |
| 1560 // such as data:. | 1561 // such as data:. |
| 1561 std::string path; | 1562 std::string path; |
| 1562 GURL url(document.url()); | 1563 GURL url(document.url()); |
| 1563 if (url.IsStandard()) | 1564 if (url.IsStandard()) |
| 1564 path = base::ToLowerASCII(url.path()); | 1565 path = base::ToLowerASCII(url.path()); |
| 1565 | 1566 |
| 1566 const char* const kKeywords[] = { | 1567 const char* const kKeywords[] = { |
| 1567 "payment", | 1568 "payment", |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1810 // Zero selection start is for password manager, which can show usernames | 1811 // Zero selection start is for password manager, which can show usernames |
| 1811 // that do not begin with the user input value. | 1812 // that do not begin with the user input value. |
| 1812 selection_start = (offset == base::string16::npos) ? 0 : offset; | 1813 selection_start = (offset == base::string16::npos) ? 0 : offset; |
| 1813 } | 1814 } |
| 1814 | 1815 |
| 1815 input_element->setSelectionRange(selection_start, suggestion.length()); | 1816 input_element->setSelectionRange(selection_start, suggestion.length()); |
| 1816 } | 1817 } |
| 1817 | 1818 |
| 1818 } // namespace form_util | 1819 } // namespace form_util |
| 1819 } // namespace autofill | 1820 } // namespace autofill |
| OLD | NEW |