[Autofill] Respect the autocomplete=off attribute on desktop for non credit card related fields and forms.

BUG=468153

Review URL: https://codereview.chromium.org/1473733008

Cr-Commit-Position: refs/heads/master@{#363052}
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 2cecdc1..5cb9c09 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1433,7 +1433,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForPasswordFormWithoutUsernameField) {
+                       AutofillSuggestionsForPasswordFormWithoutUsernameField) {
   std::string submit =
       "document.getElementById('password').value = 'mypassword';"
       "document.getElementById('submit-button').click();";
@@ -1795,7 +1795,7 @@
 // Tests that if a site embeds the login and signup forms into one <form>, the
 // login form still gets autofilled.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForLoginSignupForm) {
+                       AutofillSuggestionsForLoginSignupForm) {
   std::string submit =
       "document.getElementById('username').value = 'myusername';"
       "document.getElementById('password').value = 'mypassword';"
@@ -2261,7 +2261,7 @@
 // ambiguity in id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForPasswordFormWithAmbiguousIdAttribute) {
+    AutofillSuggestionsForPasswordFormWithAmbiguousIdAttribute) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2309,7 +2309,7 @@
 // name and id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForPasswordFormWithoutNameOrIdAttribute) {
+    AutofillSuggestionsForPasswordFormWithoutNameOrIdAttribute) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2356,7 +2356,7 @@
 // Test whether the change password form having username and password fields
 // without name and id attribute gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForChangePwdWithEmptyNames) {
+                       AutofillSuggestionsForChangePwdWithEmptyNames) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2416,7 +2416,7 @@
 // correctly.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForChangePwdWithEmptyNamesAndAutocomplete) {
+    AutofillSuggestionsForChangePwdWithEmptyNamesAndAutocomplete) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2473,7 +2473,7 @@
 // |autocomplete='new-password'| atrribute do not get autofilled.
 IN_PROC_BROWSER_TEST_F(
     PasswordManagerBrowserTestBase,
-    AutofillSuggetionsForChangePwdWithEmptyNamesButOnlyNewPwdField) {
+    AutofillSuggestionsForChangePwdWithEmptyNamesButOnlyNewPwdField) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2588,10 +2588,10 @@
 // Test whether the password form which is loaded as hidden is autofilled
 // correctly. This happens very often in situations when in order to sign-in the
 // user clicks a sign-in button and a hidden passsword form becomes visible.
-// This test differs from AutofillSuggetionsForProblematicPasswordForm in that
+// This test differs from AutofillSuggestionsForProblematicPasswordForm in that
 // the form is hidden and in that test only some fields are hidden.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsHiddenPasswordForm) {
+                       AutofillSuggestionsHiddenPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2638,7 +2638,7 @@
 // Test whether the password form with the problematic invisible password field
 // gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForProblematicPasswordForm) {
+                       AutofillSuggestionsForProblematicPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2685,7 +2685,7 @@
 // Test whether the password form with the problematic invisible password field
 // in ambiguous password form gets autofilled correctly.
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       AutofillSuggetionsForProblematicAmbiguousPasswordForm) {
+                       AutofillSuggestionsForProblematicAmbiguousPasswordForm) {
   // At first let us save credentials to the PasswordManager.
   scoped_refptr<password_manager::PasswordStore> password_store =
       PasswordStoreFactory::GetForProfile(browser()->profile(),
@@ -2871,4 +2871,35 @@
 }
 #endif
 
+// Tests that the prompt to save the password is still shown if the fields have
+// the "autocomplete" attribute set off.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+                       PromptForSubmitWithAutocompleteOff) {
+  NavigateToFile("/password/password_autocomplete_off_test.html");
+
+  NavigationObserver observer(WebContents());
+  scoped_ptr<PromptObserver> prompt_observer(
+      PromptObserver::Create(WebContents()));
+  std::string fill_and_submit =
+      "document.getElementById('username').value = 'temp';"
+      "document.getElementById('password').value = 'random';"
+      "document.getElementById('submit').click()";
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+  observer.Wait();
+  EXPECT_TRUE(prompt_observer->IsShowingPrompt());
+}
+
+// Tests that password suggestions still work if the fields have the
+// "autocomplete" attribute set to off.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+                       AutofillSuggestionsForPasswordFormWithAutocompleteOff) {
+  std::string submit =
+      "document.getElementById('username').value = 'temp';"
+      "document.getElementById('password').value = 'mypassword';"
+      "document.getElementById('submit').click();";
+  VerifyPasswordIsSavedAndFilled(
+      "/password/password_autocomplete_off_test.html", submit, "password",
+      "mypassword");
+}
+
 }  // namespace password_manager
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index bc7a762..6e876015 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -2068,6 +2068,67 @@
                                         &field));
 }
 
+// Tests that the |should_autocomplete| is set to false for all the fields when
+// an autocomplete='off' attribute is set for the form in HTML.
+TEST_F(FormAutofillTest, WebFormElementToFormData_AutocompleteOff_OnForm) {
+  LoadHTML(
+      "<FORM name='TestForm' id='form' action='http://cnn.com' method='post' "
+      "autocomplete='off'>"
+      "  <LABEL for='firstname'>First name:</LABEL>"
+      "    <INPUT type='text' id='firstname' value='John'/>"
+      "  <LABEL for='lastname'>Last name:</LABEL>"
+      "    <INPUT type='text' id='lastname' value='Smith'/>"
+      "  <LABEL for='street-address'>Address:</LABEL>"
+      "    <INPUT type='text' id='addressline1' value='123 Test st.'/>"
+      "</FORM>");
+
+  WebFrame* frame = GetMainFrame();
+  ASSERT_NE(nullptr, frame);
+
+  WebFormElement web_form =
+      frame->document().getElementById("form").to<WebFormElement>();
+  ASSERT_FALSE(web_form.isNull());
+
+  FormData form;
+  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
+                                       EXTRACT_NONE, &form, nullptr));
+
+  for (const FormFieldData& field : form.fields) {
+    EXPECT_FALSE(field.should_autocomplete);
+  }
+}
+
+// Tests that the |should_autocomplete| is set to false only for the field
+// which has an autocomplete='off' attribute set for it in HTML.
+TEST_F(FormAutofillTest, WebFormElementToFormData_AutocompleteOff_OnField) {
+  LoadHTML(
+      "<FORM name='TestForm' id='form' action='http://cnn.com' method='post'>"
+      "  <LABEL for='firstname'>First name:</LABEL>"
+      "    <INPUT type='text' id='firstname' value='John' autocomplete='off'/>"
+      "  <LABEL for='lastname'>Last name:</LABEL>"
+      "    <INPUT type='text' id='lastname' value='Smith'/>"
+      "  <LABEL for='street-address'>Address:</LABEL>"
+      "    <INPUT type='text' id='addressline1' value='123 Test st.'/>"
+      "</FORM>");
+
+  WebFrame* frame = GetMainFrame();
+  ASSERT_NE(nullptr, frame);
+
+  WebFormElement web_form =
+      frame->document().getElementById("form").to<WebFormElement>();
+  ASSERT_FALSE(web_form.isNull());
+
+  FormData form;
+  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
+                                       EXTRACT_NONE, &form, nullptr));
+
+  ASSERT_EQ(3U, form.fields.size());
+
+  EXPECT_FALSE(form.fields[0].should_autocomplete);
+  EXPECT_TRUE(form.fields[1].should_autocomplete);
+  EXPECT_TRUE(form.fields[2].should_autocomplete);
+}
+
 TEST_F(FormAutofillTest, ExtractForms) {
   ExpectJohnSmithLabels(
       "<FORM name='TestForm' action='http://cnn.com' method='post'>"
diff --git a/chrome/test/data/password/password_autocomplete_off_test.html b/chrome/test/data/password/password_autocomplete_off_test.html
index 902409a..ae18625 100644
--- a/chrome/test/data/password/password_autocomplete_off_test.html
+++ b/chrome/test/data/password/password_autocomplete_off_test.html
@@ -5,15 +5,10 @@
     <title>Password Test Form</title>
   </head>
   <body>
-    <form id="loginform" action="google.com" method="post">
-    <table cellspacing="3" cellpadding="5" border="0">
-      <tbody>
-        <tr><td>Username:</td><td align="left"><input type="text" name="Email" id="Email" size="18" value=""></td></tr>
-        <tr><td>Password:</td><td align="left"><input autocomplete="off" type="password" name="Passwd" id="Passwd" size="18"></td></tr>
-        <tr><td></td><td align="left"><input type="submit" class="button" name="signIn" id="signIn" value="Sign in"></td></tr>
-      </tbody>
-    </table>
+    <form method="POST" action="done.html" id="loginform">
+      <input type="text" id="username" autocomplete="off">
+      <input type="password" id="password" autocomplete="off">
+      <input type="submit" id="submit">
     </form>
   </body>
-</html>
-
+</html>
\ No newline at end of file
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 5fd597d..41bc2fc0 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/state_names.h"
 #include "components/autofill/core/common/autofill_l10n_util.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "grit/components_strings.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
@@ -500,6 +501,13 @@
                                   FormFieldData* field_data) {
   AutofillType type = field.Type();
 
+  // Don't fill if autocomplete=off is set on |field| on desktop for non credit
+  // card related fields.
+  if (!field.should_autocomplete && IsDesktopPlatform() &&
+      (type.group() != CREDIT_CARD)) {
+    return false;
+  }
+
   if (type.GetStorableType() == PHONE_HOME_NUMBER) {
     FillPhoneNumberField(field, value, field_data);
     return true;
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index c65daaa..46009a2 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::ASCIIToUTF16;
@@ -129,11 +130,45 @@
   field.set_server_type(NAME_LAST);
   EXPECT_TRUE(field.IsFieldFillable());
 
-  // Field has autocomplete="off" set. Chrome ignores the attribute.
+  // Field has autocomplete="off" set. Since autofill was able to make a
+  // prediction, it is still considered a fillable field.
   field.should_autocomplete = false;
   EXPECT_TRUE(field.IsFieldFillable());
 }
 
+// Verify that non credit card related fields with the autocomplete attribute
+// set to off don't get filled on desktop.
+TEST(AutofillFieldTest, FillFormField_AutocompleteOff_AddressField) {
+  AutofillField field;
+  field.should_autocomplete = false;
+
+  // Non credit card related field.
+  AutofillField::FillFormField(field, ASCIIToUTF16("Test"), "en-US", "en-US",
+                               &field);
+
+  // Verifiy that the field is filled on mobile but not on desktop.
+  if (IsDesktopPlatform()) {
+    EXPECT_EQ(base::string16(), field.value);
+  } else {
+    EXPECT_EQ(ASCIIToUTF16("Test"), field.value);
+  }
+}
+
+// Verify that credit card related fields with the autocomplete attribute
+// set to off get filled.
+TEST(AutofillFieldTest, FillFormField_AutocompleteOff_CreditCardField) {
+  AutofillField field;
+  field.should_autocomplete = false;
+
+  // Credit card related field.
+  field.set_heuristic_type(CREDIT_CARD_NUMBER);
+  AutofillField::FillFormField(field, ASCIIToUTF16("4111111111111111"), "en-US",
+                               "en-US", &field);
+
+  // Verify that the field is filled.
+  EXPECT_EQ(ASCIIToUTF16("4111111111111111"), field.value);
+}
+
 TEST(AutofillFieldTest, FillPhoneNumber) {
   AutofillField field;
   field.SetHtmlType(HTML_TYPE_TEL_LOCAL_PREFIX, HtmlFieldMode());
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index e3c5e3c6..dca717d 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -49,6 +49,7 @@
 #include "components/autofill/core/common/autofill_data_validation.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_data_predictions.h"
 #include "components/autofill/core/common/form_field_data.h"
@@ -407,6 +408,12 @@
       got_autofillable_form) {
     AutofillType type = autofill_field->Type();
     bool is_filling_credit_card = (type.group() == CREDIT_CARD);
+    // On desktop, don't return non credit card related suggestions for forms or
+    // fields that have the "autocomplete" attribute set to off.
+    if (IsDesktopPlatform() && !is_filling_credit_card &&
+        !field.should_autocomplete) {
+      return;
+    }
     if (is_filling_credit_card) {
       suggestions = GetCreditCardSuggestions(field, type);
     } else {
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 487eb108..87dccd9 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -35,6 +35,7 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "grit/components_strings.h"
@@ -1895,6 +1896,89 @@
   }
 }
 
+// Test that non credit card related fields with the autocomplete attribute set
+// to off are not filled on desktop.
+TEST_F(AutofillManagerTest, FillAddressForm_AutocompleteOff) {
+  FormData address_form;
+  address_form.name = ASCIIToUTF16("MyForm");
+  address_form.origin = GURL("https://myform.com/form.html");
+  address_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("First name", "firstname", "", "text", &field);
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Middle name", "middle", "", "text", &field);
+  field.should_autocomplete = false;
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+  field.should_autocomplete = true;
+  address_form.fields.push_back(field);
+  test::CreateTestFormField("Address Line 1", "addr1", "", "text", &field);
+  field.should_autocomplete = false;
+  address_form.fields.push_back(field);
+  std::vector<FormData> address_forms(1, address_form);
+  FormsSeen(address_forms);
+
+  // Fill the address form.
+  const char guid[] = "00000000-0000-0000-0000-000000000001";
+  int response_page_id = 0;
+  FormData response_data;
+  FillAutofillFormDataAndSaveResults(
+      kDefaultPageID, address_form, address_form.fields[0],
+      MakeFrontendID(std::string(), guid), &response_page_id, &response_data);
+
+  // The fist name should be filled.
+  ExpectFilledField("First name", "firstname", "Elvis", "text",
+                    response_data.fields[0]);
+
+  // The middle name should not be filled on desktop.
+  if (IsDesktopPlatform()) {
+    ExpectFilledField("Middle name", "middle", "", "text",
+                      response_data.fields[1]);
+  } else {
+    ExpectFilledField("Middle name", "middle", "Aaron", "text",
+                      response_data.fields[1]);
+  }
+
+  // The last name should be filled.
+  ExpectFilledField("Last name", "lastname", "Presley", "text",
+                    response_data.fields[2]);
+
+  // The address line 1 should not be filled on desktop.
+  if (IsDesktopPlatform()) {
+    ExpectFilledField("Address Line 1", "addr1", "", "text",
+                      response_data.fields[3]);
+  } else {
+    ExpectFilledField("Address Line 1", "addr1", "3734 Elvis Presley Blvd.",
+                      "text", response_data.fields[3]);
+  }
+}
+
+// Test that credit card fields are filled even if they have the autocomplete
+// attribute set to off.
+TEST_F(AutofillManagerTest, FillCreditCardForm_AutocompleteOff) {
+  // Set up our form data.
+  FormData form;
+  CreateTestCreditCardFormData(&form, true, false);
+
+  // Set the autocomplete=off on all fields.
+  for (FormFieldData field : form.fields)
+    field.should_autocomplete = false;
+
+  std::vector<FormData> forms(1, form);
+  FormsSeen(forms);
+
+  const char guid[] = "00000000-0000-0000-0000-000000000004";
+  int response_page_id = 0;
+  FormData response_data;
+  FillAutofillFormDataAndSaveResults(kDefaultPageID, form, *form.fields.begin(),
+                                     MakeFrontendID(guid, std::string()),
+                                     &response_page_id, &response_data);
+
+  // All fields should be filled.
+  ExpectFilledCreditCardFormElvis(response_page_id, response_data,
+                                  kDefaultPageID, false);
+}
+
 // Test that non-focusable field is ignored while inferring boundaries between
 // sections: http://crbug.com/231160
 TEST_F(AutofillManagerTest, FillFormWithNonFocusableFields) {
@@ -3870,4 +3954,72 @@
   EXPECT_FALSE(autofill_manager_->ShouldUploadForm(form_structure_3));
 }
 
+// Verify that no suggestions are shown on desktop for non credit card related
+// fields if the initiating field has the "autocomplete" attribute set to off.
+TEST_F(AutofillManagerTest, DisplaySuggestions_AutocompleteOff_AddressField) {
+  // Set up an address form.
+  FormData mixed_form;
+  mixed_form.name = ASCIIToUTF16("MyForm");
+  mixed_form.origin = GURL("https://myform.com/form.html");
+  mixed_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("First name", "firstname", "", "text", &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Address", "address", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  std::vector<FormData> mixed_forms(1, mixed_form);
+  FormsSeen(mixed_forms);
+
+  // Suggestions should not be displayed on desktop for this field.
+  GetAutofillSuggestions(mixed_form, mixed_form.fields[0]);
+  if (IsDesktopPlatform()) {
+    EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+  } else {
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+
+  // Suggestions should always be displayed for all the other fields.
+  for (size_t i = 1U; i < mixed_form.fields.size(); ++i) {
+    GetAutofillSuggestions(mixed_form, mixed_form.fields[i]);
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+}
+
+// Verify that suggestions are shown on desktop for credit card related fields
+// even if the initiating field field has the "autocomplete" attribute set to
+// off.
+TEST_F(AutofillManagerTest,
+       DisplaySuggestions_AutocompleteOff_CreditCardField) {
+  // Set up a credit card form.
+  FormData mixed_form;
+  mixed_form.name = ASCIIToUTF16("MyForm");
+  mixed_form.origin = GURL("https://myform.com/form.html");
+  mixed_form.action = GURL("https://myform.com/submit.html");
+  FormFieldData field;
+  test::CreateTestFormField("Name on Card", "nameoncard", "", "text", &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+  field.should_autocomplete = true;
+  mixed_form.fields.push_back(field);
+  test::CreateTestFormField("Expiration Month", "ccexpiresmonth", "", "text",
+                            &field);
+  field.should_autocomplete = false;
+  mixed_form.fields.push_back(field);
+  mixed_form.fields.push_back(field);
+  std::vector<FormData> mixed_forms(1, mixed_form);
+  FormsSeen(mixed_forms);
+
+  // Suggestions should always be displayed.
+  for (const FormFieldData& field : mixed_form.fields) {
+    GetAutofillSuggestions(mixed_form, field);
+    EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  }
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_util.cc b/components/autofill/core/common/autofill_util.cc
index b2c3671..1359816 100644
--- a/components/autofill/core/common/autofill_util.cc
+++ b/components/autofill/core/common/autofill_util.cc
@@ -96,4 +96,12 @@
   return base::string16::npos;
 }
 
+bool IsDesktopPlatform() {
+#if defined(OS_ANDROID) || defined(OS_IOS)
+  return false;
+#else
+  return true;
+#endif
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_util.h b/components/autofill/core/common/autofill_util.h
index 81c3062..e29318d 100644
--- a/components/autofill/core/common/autofill_util.h
+++ b/components/autofill/core/common/autofill_util.h
@@ -36,6 +36,10 @@
                              const base::string16& field_contents,
                              bool case_sensitive);
 
+// Returns true if running on a desktop platform. Any platform that is not
+// Android or iOS is considered desktop.
+bool IsDesktopPlatform();
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_UTIL_H_
diff --git a/third_party/WebKit/Source/web/WebFormControlElement.cpp b/third_party/WebKit/Source/web/WebFormControlElement.cpp
index c78a047..0c65d270e 100644
--- a/third_party/WebKit/Source/web/WebFormControlElement.cpp
+++ b/third_party/WebKit/Source/web/WebFormControlElement.cpp
@@ -83,6 +83,8 @@
         return constUnwrap<HTMLInputElement>()->shouldAutocomplete();
     if (isHTMLTextAreaElement(*m_private))
         return constUnwrap<HTMLTextAreaElement>()->shouldAutocomplete();
+    if (isHTMLSelectElement(*m_private))
+        return constUnwrap<HTMLSelectElement>()->shouldAutocomplete();
     return false;
 }