Move password filling logic into components.

Note: Unit test will be added in https://chromium-review.googlesource.com/c/chromium/src/+/1195292.

Bug: 865114
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: I91e187ae90b7515cc3bc37cdd80bdfbf33ae5ca1
Reviewed-on: https://chromium-review.googlesource.com/1195246
Commit-Queue: Scott Wu <scottwu@chromium.org>
Reviewed-by: Vasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: John Wu <jzw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587986}
diff --git a/components/password_manager/ios/password_controller_helper.h b/components/password_manager/ios/password_controller_helper.h
index 676e812..781feb7f 100644
--- a/components/password_manager/ios/password_controller_helper.h
+++ b/components/password_manager/ios/password_controller_helper.h
@@ -18,9 +18,11 @@
 
 namespace autofill {
 struct PasswordForm;
+struct PasswordFormFillData;
 }  // namespace autofill
 
 namespace password_manager {
+struct FillData;
 // Returns true if the trust level for the current page URL of |web_state| is
 // kAbsolute. If |page_url| is not null, fills it with the current page URL.
 bool GetPageURLAndCheckTrustLevel(web::WebState* web_state,
@@ -48,11 +50,35 @@
 // The JsPasswordManager processing password form via javascript.
 @property(nonatomic, readonly) JsPasswordManager* jsPasswordManager;
 
+// Last committed URL of current web state.
+// Returns empty URL if current web state is not available.
+@property(nonatomic, readonly) const GURL& lastCommittedURL;
+
 // Uses JavaScript to find password forms. Calls |completionHandler| with the
 // extracted information used for matching and saving passwords. Calls
 // |completionHandler| with an empty vector if no password forms are found.
 - (void)findPasswordFormsWithCompletionHandler:
-    (void (^)(const std::vector<autofill::PasswordForm>&))completionHandler;
+    (nullable void (^)(const std::vector<autofill::PasswordForm>&))
+        completionHandler;
+
+// Autofills credentials into the page. Credentials and input fields are
+// specified by |formData|. Invokes |completionHandler| when finished with YES
+// if successful and NO otherwise.
+- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
+       completionHandler:(nullable void (^)(BOOL))completionHandler;
+
+// Autofills credentials into the page. Credentials and input fields are
+// specified by |fillData|. Invokes |completionHandler| when finished with YES
+// if successful and NO otherwise.
+- (void)fillPasswordFormWithFillData:(const password_manager::FillData&)fillData
+                   completionHandler:(nullable void (^)(BOOL))completionHandler;
+
+// Finds password forms in the page and fills them with the |username| and
+// |password|. If not nil, |completionHandler| is called once per form filled.
+- (void)findAndFillPasswordFormsWithUserName:(NSString*)username
+                                    password:(NSString*)password
+                           completionHandler:
+                               (nullable void (^)(BOOL))completionHandler;
 
 // Creates a instance with the given WebState, observer and delegate.
 - (instancetype)initWithWebState:(web::WebState*)webState
diff --git a/components/password_manager/ios/password_controller_helper.mm b/components/password_manager/ios/password_controller_helper.mm
index 266e676..ad0de29 100644
--- a/components/password_manager/ios/password_controller_helper.mm
+++ b/components/password_manager/ios/password_controller_helper.mm
@@ -10,8 +10,10 @@
 #include "base/values.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/password_form_fill_data.h"
 #include "components/autofill/ios/browser/autofill_util.h"
 #include "components/password_manager/core/browser/form_parsing/ios_form_parser.h"
+#include "components/password_manager/ios/account_select_fill_data.h"
 #include "components/password_manager/ios/js_password_manager.h"
 #import "ios/web/public/web_state/web_state.h"
 
@@ -22,6 +24,8 @@
 using autofill::FormData;
 using autofill::PasswordForm;
 using password_manager::GetPageURLAndCheckTrustLevel;
+using password_manager::FillData;
+using password_manager::SerializePasswordFormFillData;
 
 namespace password_manager {
 bool GetPageURLAndCheckTrustLevel(web::WebState* web_state,
@@ -63,6 +67,13 @@
                          pageURL:(const GURL&)pageURL
                            forms:(std::vector<autofill::PasswordForm>*)forms;
 
+// Autofills |username| and |password| into the form specified by |formData|,
+// invoking |completionHandler| when finished with YES if successful and
+// NO otherwise. |completionHandler| may be nil.
+- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
+            withUsername:(const base::string16&)username
+                password:(const base::string16&)password
+       completionHandler:(nullable void (^)(BOOL))completionHandler;
 @end
 
 @implementation PasswordControllerHelper {
@@ -83,6 +94,10 @@
 @synthesize delegate = _delegate;
 @synthesize jsPasswordManager = _jsPasswordManager;
 
+- (const GURL&)lastCommittedURL {
+  return _webState ? _webState->GetLastCommittedURL() : GURL::EmptyGURL();
+}
+
 #pragma mark - Initialization
 
 - (instancetype)initWithWebState:(web::WebState*)webState
@@ -258,17 +273,42 @@
   for (const auto& formData : formsData) {
     std::unique_ptr<PasswordForm> form =
         ParseFormData(formData, password_manager::FormParsingMode::FILLING);
-    if (form)
+    if (form) {
       forms->push_back(*form);
+    }
   }
 }
 
+- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
+            withUsername:(const base::string16&)username
+                password:(const base::string16&)password
+       completionHandler:(nullable void (^)(BOOL))completionHandler {
+  if (formData.origin.GetOrigin() != self.lastCommittedURL.GetOrigin()) {
+    if (completionHandler) {
+      completionHandler(NO);
+    }
+    return;
+  }
+
+  // Send JSON over to the web view.
+  [self.jsPasswordManager
+       fillPasswordForm:SerializePasswordFormFillData(formData)
+           withUsername:base::SysUTF16ToNSString(username)
+               password:base::SysUTF16ToNSString(password)
+      completionHandler:^(BOOL result) {
+        if (completionHandler) {
+          completionHandler(result);
+        }
+      }];
+}
+
 #pragma mark - Public methods
 
 - (void)findPasswordFormsWithCompletionHandler:
     (void (^)(const std::vector<autofill::PasswordForm>&))completionHandler {
-  if (!_webState)
+  if (!_webState) {
     return;
+  }
 
   GURL pageURL;
   if (!GetPageURLAndCheckTrustLevel(_webState, &pageURL)) {
@@ -284,4 +324,59 @@
   }];
 }
 
+- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
+       completionHandler:(nullable void (^)(BOOL))completionHandler {
+  // Don't fill immediately if waiting for the user to type a username.
+  if (formData.wait_for_username) {
+    if (completionHandler) {
+      completionHandler(NO);
+    }
+    return;
+  }
+
+  [self fillPasswordForm:formData
+            withUsername:formData.username_field.value
+                password:formData.password_field.value
+       completionHandler:completionHandler];
+}
+
+- (void)fillPasswordFormWithFillData:(const password_manager::FillData&)fillData
+                   completionHandler:
+                       (nullable void (^)(BOOL))completionHandler {
+  [self.jsPasswordManager
+       fillPasswordForm:SerializeFillData(fillData)
+           withUsername:base::SysUTF16ToNSString(fillData.username_value)
+               password:base::SysUTF16ToNSString(fillData.password_value)
+      completionHandler:^(BOOL result) {
+        if (completionHandler) {
+          completionHandler(result);
+        }
+      }];
+}
+
+- (void)findAndFillPasswordFormsWithUserName:(NSString*)username
+                                    password:(NSString*)password
+                           completionHandler:
+                               (nullable void (^)(BOOL))completionHandler {
+  __weak PasswordControllerHelper* weakSelf = self;
+  [self findPasswordFormsWithCompletionHandler:^(
+            const std::vector<autofill::PasswordForm>& forms) {
+    PasswordControllerHelper* strongSelf = weakSelf;
+    for (const auto& form : forms) {
+      autofill::PasswordFormFillData formData;
+      std::map<base::string16, const autofill::PasswordForm*> matches;
+      // Initialize |matches| to satisfy the expectation from
+      // InitPasswordFormFillData() that the preferred match (3rd parameter)
+      // should be one of the |matches|.
+      matches.insert(std::make_pair(form.username_value, &form));
+      autofill::InitPasswordFormFillData(form, matches, &form, false,
+                                         &formData);
+      [strongSelf fillPasswordForm:formData
+                      withUsername:base::SysNSStringToUTF16(username)
+                          password:base::SysNSStringToUTF16(password)
+                 completionHandler:completionHandler];
+    }
+  }];
+}
+
 @end
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index e2d4e252..b34a633 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -126,20 +126,6 @@
 - (void)didFinishPasswordFormExtraction:
     (const std::vector<autofill::PasswordForm>&)forms;
 
-// Autofills |username| and |password| into the form specified by |formData|,
-// invoking |completionHandler| when finished with YES if successful and
-// NO otherwise. |completionHandler| may be nil.
-- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
-            withUsername:(const base::string16&)username
-                password:(const base::string16&)password
-       completionHandler:(void (^)(BOOL))completionHandler;
-
-// Autofills credentials into the page. Credentials and input fields are
-// specified by |fillData|. Invoking |completionHandler| when finished with YES
-// if successful and NO otherwise. |completionHandler| may be nil.
-- (void)fillPasswordFormWithFillData:(const password_manager::FillData&)fillData
-                   completionHandler:(void (^)(BOOL))completionHandler;
-
 // Finds all password forms in DOM and sends them to the password store for
 // fetching stored credentials.
 - (void)findPasswordFormsAndSendThemToPasswordStore;
@@ -150,6 +136,11 @@
 - (void)showInfoBarForForm:(std::unique_ptr<PasswordFormManagerForUI>)form
                infoBarType:(PasswordInfoBarType)type;
 
+// Hides auto sign-in notification. Removes the view from superview and destroys
+// the controller.
+// TODO(crbug.com/435048): Animate disappearance.
+- (void)hideAutosigninNotification;
+
 @end
 
 namespace {
@@ -284,18 +275,7 @@
   }
 }
 
-- (ios::ChromeBrowserState*)browserState {
-  return _webState ? ios::ChromeBrowserState::FromBrowserState(
-                         _webState->GetBrowserState())
-                   : nullptr;
-}
-
-- (const GURL&)lastCommittedURL {
-  return _webState ? _webState->GetLastCommittedURL() : GURL::EmptyGURL();
-}
-
-#pragma mark -
-#pragma mark Properties
+#pragma mark - Properties
 
 - (id<PasswordFormFiller>)passwordFormFiller {
   return self;
@@ -309,37 +289,17 @@
   return _passwordManagerDriver.get();
 }
 
-- (PasswordManager*)passwordManager {
-  return _passwordManager.get();
-}
-
-#pragma mark -
-#pragma mark PasswordFormFiller
+#pragma mark - PasswordFormFiller
 
 - (void)findAndFillPasswordForms:(NSString*)username
                         password:(NSString*)password
                completionHandler:(void (^)(BOOL))completionHandler {
-  [self.helper findPasswordFormsWithCompletionHandler:^(
-                   const std::vector<autofill::PasswordForm>& forms) {
-    for (const auto& form : forms) {
-      autofill::PasswordFormFillData formData;
-      std::map<base::string16, const autofill::PasswordForm*> matches;
-      // Initialize |matches| to satisfy the expectation from
-      // InitPasswordFormFillData() that the preferred match (3rd parameter)
-      // should be one of the |matches|.
-      matches.insert(std::make_pair(form.username_value, &form));
-      autofill::InitPasswordFormFillData(form, matches, &form, false,
-                                         &formData);
-      [self fillPasswordForm:formData
-                withUsername:base::SysNSStringToUTF16(username)
-                    password:base::SysNSStringToUTF16(password)
-           completionHandler:completionHandler];
-    }
-  }];
+  [self.helper findAndFillPasswordFormsWithUserName:username
+                                           password:password
+                                  completionHandler:completionHandler];
 }
 
-#pragma mark -
-#pragma mark CRWWebStateObserver
+#pragma mark - CRWWebStateObserver
 
 // If Tab was shown, and there is a pending PasswordForm, display autosign-in
 // notification.
@@ -399,52 +359,7 @@
   _credentialManager.reset();
 }
 
-#pragma mark - Private methods
-
-- (void)findPasswordFormsAndSendThemToPasswordStore {
-  // Read all password forms from the page and send them to the password
-  // manager.
-  __weak PasswordController* weakSelf = self;
-  [self.helper findPasswordFormsWithCompletionHandler:^(
-                   const std::vector<autofill::PasswordForm>& forms) {
-    [weakSelf didFinishPasswordFormExtraction:forms];
-  }];
-}
-
-- (void)didFinishPasswordFormExtraction:
-    (const std::vector<autofill::PasswordForm>&)forms {
-  // Do nothing if |self| has been detached.
-  if (!self.passwordManager)
-    return;
-
-  if (!forms.empty()) {
-    // Notify web_state about password forms, so that this can be taken into
-    // account for the security state.
-    if (_webState && !web::IsOriginSecure(_webState->GetLastCommittedURL())) {
-      InsecureInputTabHelper::GetOrCreateForWebState(_webState)
-          ->DidShowPasswordFieldInInsecureContext();
-    }
-
-    _sentRequestToStore = YES;
-    // Invoke the password manager callback to autofill password forms
-    // on the loaded page.
-    self.passwordManager->OnPasswordFormsParsed(self.passwordManagerDriver,
-                                                forms);
-  } else {
-    [self onNoSavedCredentials];
-  }
-  // Invoke the password manager callback to check if password was
-  // accepted or rejected. If accepted, infobar is presented. If
-  // rejected, the provisionally saved password is deleted. On Chrome
-  // w/ a renderer, it is the renderer who calls OnPasswordFormsParsed()
-  // and OnPasswordFormsRendered(). Bling has to improvised a bit on the
-  // ordering of these two calls.
-  self.passwordManager->OnPasswordFormsRendered(self.passwordManagerDriver,
-                                                forms, true);
-}
-
-#pragma mark -
-#pragma mark FormSuggestionProvider
+#pragma mark - FormSuggestionProvider
 
 - (id<FormSuggestionProvider>)suggestionProvider {
   return self;
@@ -529,14 +444,28 @@
   if (!fillData)
     completion();
 
-  [self fillPasswordFormWithFillData:*fillData
-                   completionHandler:^(BOOL success) {
-                     completion();
-                   }];
+  [self.helper fillPasswordFormWithFillData:*fillData
+                          completionHandler:^(BOOL success) {
+                            completion();
+                          }];
 }
 
 #pragma mark - PasswordManagerClientDelegate
 
+- (ios::ChromeBrowserState*)browserState {
+  return _webState ? ios::ChromeBrowserState::FromBrowserState(
+                         _webState->GetBrowserState())
+                   : nullptr;
+}
+
+- (PasswordManager*)passwordManager {
+  return _passwordManager.get();
+}
+
+- (const GURL&)lastCommittedURL {
+  return self.helper.lastCommittedURL;
+}
+
 - (void)showSavePasswordInfoBar:
     (std::unique_ptr<PasswordFormManagerForUI>)formToSave {
   [self showInfoBarForForm:std::move(formToSave)
@@ -549,16 +478,6 @@
                infoBarType:PasswordInfoBarType::UPDATE];
 }
 
-// Hides auto sign-in notification. Removes the view from superview and destroys
-// the controller.
-// TODO(crbug.com/435048): Animate disappearance.
-- (void)hideAutosigninNotification {
-  [self.notifyAutoSigninViewController willMoveToParentViewController:nil];
-  [self.notifyAutoSigninViewController.view removeFromSuperview];
-  [self.notifyAutoSigninViewController removeFromParentViewController];
-  self.notifyAutoSigninViewController = nil;
-}
-
 // Shows auto sign-in notification and schedules hiding it after 3 seconds.
 // TODO(crbug.com/435048): Animate appearance.
 - (void)showAutosigninNotification:
@@ -599,29 +518,7 @@
       }));
 }
 
-#pragma mark -
-#pragma mark WebPasswordFormData Adaptation
-
-- (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
-            withUsername:(const base::string16&)username
-                password:(const base::string16&)password
-       completionHandler:(void (^)(BOOL))completionHandler {
-  if (formData.origin.GetOrigin() != self.lastCommittedURL.GetOrigin()) {
-    if (completionHandler)
-      completionHandler(NO);
-    return;
-  }
-
-  // Send JSON over to the web view.
-  [self.helper.jsPasswordManager
-       fillPasswordForm:SerializePasswordFormFillData(formData)
-           withUsername:base::SysUTF16ToNSString(username)
-               password:base::SysUTF16ToNSString(password)
-      completionHandler:^(BOOL result) {
-        if (completionHandler)
-          completionHandler(result);
-      }];
-}
+#pragma mark - PasswordManagerDriverDelegate
 
 - (void)fillPasswordForm:(const autofill::PasswordFormFillData&)formData
        completionHandler:(void (^)(BOOL))completionHandler {
@@ -632,17 +529,7 @@
     _suggestionsAvailableCompletion = nil;
   }
 
-  // Don't fill immediately if waiting for the user to type a username.
-  if (formData.wait_for_username) {
-    if (completionHandler)
-      completionHandler(NO);
-    return;
-  }
-
-  [self fillPasswordForm:formData
-            withUsername:formData.username_field.value
-                password:formData.password_field.value
-       completionHandler:completionHandler];
+  [self.helper fillPasswordForm:formData completionHandler:completionHandler];
 }
 
 - (void)onNoSavedCredentials {
@@ -651,19 +538,6 @@
   _suggestionsAvailableCompletion = nil;
 }
 
-- (void)fillPasswordFormWithFillData:(const password_manager::FillData&)fillData
-                   completionHandler:(void (^)(BOOL))completionHandler {
-  // Send JSON over to the web view.
-  [self.helper.jsPasswordManager
-       fillPasswordForm:SerializeFillData(fillData)
-           withUsername:base::SysUTF16ToNSString(fillData.username_value)
-               password:base::SysUTF16ToNSString(fillData.password_value)
-      completionHandler:^(BOOL result) {
-        if (completionHandler)
-          completionHandler(result);
-      }];
-}
-
 #pragma mark - PasswordControllerHelperDelegate
 
 - (void)helper:(PasswordControllerHelper*)helper
@@ -682,6 +556,48 @@
 
 #pragma mark - Private methods
 
+- (void)didFinishPasswordFormExtraction:
+    (const std::vector<autofill::PasswordForm>&)forms {
+  // Do nothing if |self| has been detached.
+  if (!self.passwordManager)
+    return;
+
+  if (!forms.empty()) {
+    // Notify web_state about password forms, so that this can be taken into
+    // account for the security state.
+    if (_webState && !web::IsOriginSecure(_webState->GetLastCommittedURL())) {
+      InsecureInputTabHelper::GetOrCreateForWebState(_webState)
+          ->DidShowPasswordFieldInInsecureContext();
+    }
+
+    _sentRequestToStore = YES;
+    // Invoke the password manager callback to autofill password forms
+    // on the loaded page.
+    self.passwordManager->OnPasswordFormsParsed(self.passwordManagerDriver,
+                                                forms);
+  } else {
+    [self onNoSavedCredentials];
+  }
+  // Invoke the password manager callback to check if password was
+  // accepted or rejected. If accepted, infobar is presented. If
+  // rejected, the provisionally saved password is deleted. On Chrome
+  // w/ a renderer, it is the renderer who calls OnPasswordFormsParsed()
+  // and OnPasswordFormsRendered(). Bling has to improvised a bit on the
+  // ordering of these two calls.
+  self.passwordManager->OnPasswordFormsRendered(self.passwordManagerDriver,
+                                                forms, true);
+}
+
+- (void)findPasswordFormsAndSendThemToPasswordStore {
+  // Read all password forms from the page and send them to the password
+  // manager.
+  __weak PasswordController* weakSelf = self;
+  [self.helper findPasswordFormsWithCompletionHandler:^(
+                   const std::vector<autofill::PasswordForm>& forms) {
+    [weakSelf didFinishPasswordFormExtraction:forms];
+  }];
+}
+
 - (void)showInfoBarForForm:(std::unique_ptr<PasswordFormManagerForUI>)form
                infoBarType:(PasswordInfoBarType)type {
   if (!_webState)
@@ -712,4 +628,11 @@
   }
 }
 
+- (void)hideAutosigninNotification {
+  [self.notifyAutoSigninViewController willMoveToParentViewController:nil];
+  [self.notifyAutoSigninViewController.view removeFromSuperview];
+  [self.notifyAutoSigninViewController removeFromParentViewController];
+  self.notifyAutoSigninViewController = nil;
+}
+
 @end