diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc index 43b4bbff3a0145..4b2093f7f2ed1f 100644 --- a/chrome/renderer/autofill/form_autofill_browsertest.cc +++ b/chrome/renderer/autofill/form_autofill_browsertest.cc @@ -3592,6 +3592,23 @@ TEST_F(FormAutofillTest, LabelForAttribute) { testing::UnorderedElementsAre(base::Bucket(AssignedLabelSource::kId, 2))); } +// Tests that when a label is assigned to an input, text behind it is considered +// as a fallback. +// The label is assigned to the input without the for-attribute, by declaring it +// it inside the label. +TEST_F(FormAutofillTest, LabelTextBehindInput) { + ExpectLabels(R"( +
+ +
+ )", + /*id_attributes=*/{u""}, /*name_attributes=*/{u""}, + /*labels=*/{u"label"}, /*names=*/{u""}, /*values=*/{u""}); +} + TEST_F(FormAutofillTest, LabelsWithSpans) { ExpectJohnSmithLabelsAndIdAttributes( "
" diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index 7fa31b982bb793..55ffb379849cb3 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc @@ -1396,12 +1396,33 @@ void MatchLabelsAndFields( field_data = iter->first; } + // Skip `label` if we could not find an associated form control. if (!field_data) continue; std::u16string label_text = FindChildText(label); - if (label_text.empty()) - continue; + if (label_text.empty()) { + if (label.HasAttribute(*kFor)) { + continue; + } + DCHECK(!control.IsNull() && control.IsFormControlElement()); + // An associated form control was found, but the `label` does not have a + // for-attribute, so the form control must be a descendant of the `label`. + // Since `FindChildText()` stops at autofillable elements, the + // `label_text` can be empty if the "text" is declared behind the . + // For example: + // + // Thus, consider text behind the as a fallback. + // Since associated labels are counted as `kFor`, the source is ignored. + FormFieldData::LabelSource irrelevant_source; + if (!InferLabelFromNext(control.To(), label_text, + irrelevant_source)) { + continue; + } + } // Concatenate labels because some sites might have multiple label // candidates. diff --git a/components/autofill/ios/form_util/resources/fill.js b/components/autofill/ios/form_util/resources/fill.js index 1237455f446fcc..f0e0ac4631d8d6 100644 --- a/components/autofill/ios/form_util/resources/fill.js +++ b/components/autofill/ios/form_util/resources/fill.js @@ -729,7 +729,10 @@ function matchLabelsAndFields_( if (!('label' in fieldData)) { fieldData['label'] = ''; } - const labelText = __gCrWeb.fill.findChildText(label); + let labelText = __gCrWeb.fill.findChildText(label); + if (labelText.length === 0 && !label.htmlFor) { + labelText = __gCrWeb.fill.inferLabelFromNext(fieldElement); + } // Concatenate labels because some sites might have multiple label // candidates. if (fieldData['label'].length > 0 && labelText.length > 0) { diff --git a/components/test/data/autofill/heuristics/output/047_register_continental.com.out b/components/test/data/autofill/heuristics/output/047_register_continental.com.out index 3e2320f0ecc181..5d2eb5c865f19f 100644 --- a/components/test/data/autofill/heuristics/output/047_register_continental.com.out +++ b/components/test/data/autofill/heuristics/output/047_register_continental.com.out @@ -8,8 +8,8 @@ NAME_FIRST | ctl00$ContentInfo$Name$FName$txtFName | First Name: | | ctl00$Cust NAME_MIDDLE_INITIAL | ctl00$ContentInfo$Name$MName$txtMName | Middle Initial (optional): | | ctl00$CustomerHeader$ddlCountries_1 NAME_LAST | ctl00$ContentInfo$Name$LName$txtLName | Last Name: | | ctl00$CustomerHeader$ddlCountries_1 UNKNOWN_TYPE | ctl00$ContentInfo$Name$suffix$txtSuffix | Suffix (optional): | | ctl00$CustomerHeader$ddlCountries_1 -UNKNOWN_TYPE | ctl00$ContentInfo$MemberAge$EnrollmentAge | This OnePass account is for an adult 18 years of age or older. | rdoAdult | ctl00$CustomerHeader$ddlCountries_1 -UNKNOWN_TYPE | ctl00$ContentInfo$MemberAge$EnrollmentAge | This OnePass account is for a minor under the age of 18. | rdoMinor | ctl00$CustomerHeader$ddlCountries_1 +UNKNOWN_TYPE | ctl00$ContentInfo$MemberAge$EnrollmentAge | This OnePass account is for an adult 18 years of age or older. This OnePass account is for an adult 18 years of age or older. | rdoAdult | ctl00$CustomerHeader$ddlCountries_1 +UNKNOWN_TYPE | ctl00$ContentInfo$MemberAge$EnrollmentAge | This OnePass account is for a minor under the age of 18. This OnePass account is for a minor under the age of 18. | rdoMinor | ctl00$CustomerHeader$ddlCountries_1 UNKNOWN_TYPE | ctl00$ContentInfo$BirthDate$txtDOB | Minor’s Date of Birth: | mm/dd/yyyy | ctl00$CustomerHeader$ddlCountries_1 UNKNOWN_TYPE | ctl00$ContentInfo$AddressType$AddressType | Home | rdoAddTypeHome | ctl00$CustomerHeader$ddlCountries_1 UNKNOWN_TYPE | ctl00$ContentInfo$AddressType$AddressType | Business/Other | rdoAddTypeBusiness | ctl00$CustomerHeader$ddlCountries_1 diff --git a/components/test/data/autofill/heuristics/output/111_checkout_virgin_america.com.out b/components/test/data/autofill/heuristics/output/111_checkout_virgin_america.com.out index 813336a39de148..2fd7529e972073 100644 --- a/components/test/data/autofill/heuristics/output/111_checkout_virgin_america.com.out +++ b/components/test/data/autofill/heuristics/output/111_checkout_virgin_america.com.out @@ -1,10 +1,10 @@ -UNKNOWN_TYPE | creditCard | American Express Discover | | creditCard_1 -CREDIT_CARD_NAME_FULL | cardholderName | Cardholder's name | | cardholderName_2 -CREDIT_CARD_EXP_MONTH | expireMonth | Expiration Date | | cardholderName_2 -CREDIT_CARD_EXP_4_DIGIT_YEAR | expireYear | Expiration Date | | cardholderName_2 -CREDIT_CARD_VERIFICATION_CODE | securityNumber | CVV Number 3 or 4 digit number | | cardholderName_2 -UNKNOWN_TYPE | nickname | Card's nickname e.g. My Visa, Corporate card, etc | | creditCard_1 -UNKNOWN_TYPE | useAddress | Use stored address | use-stored-address | creditCard_1 -UNKNOWN_TYPE | stored-address | | ? | creditCard_1 -UNKNOWN_TYPE | useAddress | Add new address | add-new-address | creditCard_1 -UNKNOWN_TYPE | shouldSave | Save credit card info | on | creditCard_1 +CREDIT_CARD_NUMBER | creditCard | Invalid card # | | creditCard_1 +CREDIT_CARD_NAME_FULL | cardholderName | Cardholder's name | | creditCard_1 +CREDIT_CARD_EXP_MONTH | expireMonth | Expiration Date | | creditCard_1 +CREDIT_CARD_EXP_4_DIGIT_YEAR | expireYear | Expiration Date | | creditCard_1 +CREDIT_CARD_VERIFICATION_CODE | securityNumber | CVV Number 3 or 4 digit number | | creditCard_1 +UNKNOWN_TYPE | nickname | Card's nickname e.g. My Visa, Corporate card, etc | | nickname_2 +UNKNOWN_TYPE | useAddress | Use stored address | use-stored-address | nickname_2 +UNKNOWN_TYPE | stored-address | | ? | nickname_2 +UNKNOWN_TYPE | useAddress | Add new address | add-new-address | nickname_2 +UNKNOWN_TYPE | shouldSave | Save credit card info | on | nickname_2