chromium/components/autofill/ios/browser/autofill_driver_ios.h

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_H_
#define COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_H_

#import <set>
#import <string>

#import "base/containers/flat_map.h"
#import "base/containers/flat_set.h"
#import "base/containers/span.h"
#import "base/memory/raw_ptr.h"
#import "base/memory/raw_ref.h"
#import "base/memory/weak_ptr.h"
#import "components/autofill/core/browser/autofill_client.h"
#import "components/autofill/core/browser/browser_autofill_manager.h"
#import "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#import "url/origin.h"

namespace web {
class WebFrame;
class WebState;
}

@protocol AutofillDriverIOSBridge;

namespace autofill {

// Histogram for recording the renderer event used to infer a form submission.
inline constexpr char kAutofillSubmissionDetectionSourceHistogram[] =
    "Autofill.SubmissionDetectionSource.AutofillAgent";

// Histogram for recording whether the form detected as submitted after a form
// removal event was the synthetic form. Recorded when a submission is detected
// after a form removal event.
inline constexpr char kFormlessSubmissionAfterFormRemovalHistogram[] =
    "Autofill.iOS.FormRemoval.SubmissionDetected.IsFormless";

// Histogram for recording whether a form submission was detected after a form
// removal event.
inline constexpr char kFormSubmissionAfterFormRemovalHistogram[] =
    "Autofill.iOS.FormRemoval.SubmissionDetected";

// Histogram for recording the number of removed forms in a form removal event.
inline constexpr char kFormRemovalRemovedFormsHistogram[] =
    "Autofill.iOS.FormRemoval.RemovedForms";

// Histogram for recording the number of removed unowned fields in a form
// removal event.
inline constexpr char kFormRemovalRemovedUnownedFieldsHistogram[] =
    "Autofill.iOS.FormRemoval.RemovedUnownedFields";

class AutofillDriverIOSFactory;
class AutofillDriverRouter;

// AutofillDriverIOS drives the Autofill flow in the browser process based
// on communication from JavaScript and from the external world.
//
// AutofillDriverIOS communicates with an AutofillDriverIOSBridge, which in
// Chrome is implemented by AutofillAgent, and a BrowserAutofillManager.
//
// AutofillDriverIOS is associated with exactly one WebFrame and its lifecycle
// is bound to that WebFrame. Since WebFrames do not survive cross-document
// navigations, AutofillDriverIOS does not survive them either.
//
// AutofillDriverIOS is final because its constructor and destructor calls
// AutofillManager::SetLifecycleState(), which must be called at the very
// end/beginning of con-/destruction.
class AutofillDriverIOS final : public AutofillDriver,
                                public AutofillManager::Observer {
 public:
  // Returns the AutofillDriverIOS for `web_state` and `web_frame`. Creates the
  // driver if necessary.
  static AutofillDriverIOS* FromWebStateAndWebFrame(web::WebState* web_state,
                                                    web::WebFrame* web_frame);

  // Convenience method that grabs the frame associated with `token` and returns
  // the associated driver. Creates the driver if `token` refers to a valid
  // frame but no driver exists; returns nullptr if `token` does not refer to a
  // valid frame.
  static AutofillDriverIOS* FromWebStateAndLocalFrameToken(
      web::WebState* web_state,
      LocalFrameToken token);

  AutofillDriverIOS(web::WebState* web_state,
                    web::WebFrame* web_frame,
                    AutofillClient* client,
                    AutofillDriverRouter* router,
                    id<AutofillDriverIOSBridge> bridge,
                    const std::string& app_locale,
                    base::PassKey<AutofillDriverIOSFactory>);

  ~AutofillDriverIOS() override;

  // AutofillDriver:
  LocalFrameToken GetFrameToken() const override;
  std::optional<LocalFrameToken> Resolve(FrameToken query) override;
  AutofillDriverIOS* GetParent() override;
  AutofillClient& GetAutofillClient() override;
  BrowserAutofillManager& GetAutofillManager() override;
  bool IsActive() const override;
  bool IsInAnyMainFrame() const override;
  bool HasSharedAutofillPermission() const override;
  bool CanShowAutofillUi() const override;
  base::flat_set<FieldGlobalId> ApplyFormAction(
      mojom::FormActionType action_type,
      mojom::ActionPersistence action_persistence,
      base::span<const FormFieldData> fields,
      const url::Origin& triggered_origin,
      const base::flat_map<FieldGlobalId, FieldType>& field_type_map) override;
  void ApplyFieldAction(mojom::FieldActionType action_type,
                        mojom::ActionPersistence action_persistence,
                        const FieldGlobalId& field_id,
                        const std::u16string& value) override;
  void ExtractForm(
      FormGlobalId form,
      base::OnceCallback<void(AutofillDriver*, const std::optional<FormData>&)>
          response_callback) override;
  void SendTypePredictionsToRenderer(
      const std::vector<raw_ptr<FormStructure, VectorExperimental>>& forms)
      override;
  void RendererShouldClearPreviewedForm() override;
  void RendererShouldTriggerSuggestions(
      const FieldGlobalId& field_id,
      AutofillSuggestionTriggerSource trigger_source) override;
  void RendererShouldAcceptDataListSuggestion(
      const FieldGlobalId& field_id,
      const std::u16string& value) override;
  void TriggerFormExtractionInDriverFrame(
      AutofillDriverRouterAndFormForestPassKey pass_key) override;
  void TriggerFormExtractionInAllFrames(
      base::OnceCallback<void(bool)> form_extraction_finished_callback)
      override;
  void GetFourDigitCombinationsFromDom(
      base::OnceCallback<void(const std::vector<std::string>&)>
          potential_matches) override;

  void RendererShouldSetSuggestionAvailability(
      const FieldGlobalId& field_id,
      mojom::AutofillSuggestionAvailability suggestion_availability) override;
  std::optional<net::IsolationInfo> GetIsolationInfo() override;

  bool is_processed() const { return processed_; }
  void set_processed(bool processed) { processed_ = processed; }
  web::WebFrame* web_frame() const;

  // Methods routed by AutofillDriverRouter. These are a subset of the methods
  // in mojom::AutofillDriver; that interface is content-specific, but to
  // simplify interaction with the Router, we duplicate some methods (with a few
  // irrelevant args omitted). See
  // components/autofill/content/common/mojom/autofill_driver.mojom
  // for further documentation of each method.
  void AskForValuesToFill(const FormData& form, const FieldGlobalId& field_id);
  void DidFillAutofillFormData(const FormData& form, base::TimeTicks timestamp);
  void FormsSeen(const std::vector<FormData>& updated_forms,
                 const std::vector<FormGlobalId>& removed_forms);
  void FormSubmitted(const FormData& form,
                     bool known_success,
                     mojom::SubmissionSource submission_source);
  void CaretMovedInFormField(const FormData& form,
                             const FieldGlobalId& field_id,
                             const gfx::Rect& caret_bounds);
  void TextFieldDidChange(const FormData& form,
                          const FieldGlobalId& field_id,
                          base::TimeTicks timestamp);

  // AutofillDriverIOS:

  // Notification that forms or formless fields have been removed. Since Bling's
  // renderer does not have API's to detect async form submissions, we use he
  // removal last interacted form or formless field as an indication that the
  // form was submitted asynchronously.
  void FormsRemoved(const std::set<FormRendererId>& removed_forms,
                    const std::set<FieldRendererId>& removed_unowned_fields);

  // Unregisters the driver as a standalone node which means that the
  // corresponding frame is now invalid. It is possible to unregister without
  // deleting the frame so it is definitely possible that the frame lives while
  // not being registered. Can't be rolled back where the driver cannot be
  // re-registered after being unregistered.
  void Unregister();

 private:
  friend class AutofillDriverIOSTestApi;

  // Represents the last form or formless field where the user entered data.
  struct LastInteractedForm {
    // Snapshot of the last interacted form or formless form.
    FormData form_data;

    // Renderer id of the last interacted formless field or `FieldRendererId()`
    // if the last interaction was not with a single formless field.
    // TODO: crbug.com/40266699 - Convert to FieldGlobalId.
    FieldRendererId formless_field;
  };

  void SetParent(base::WeakPtr<AutofillDriverIOS> parent);

  // Sets `this` as the parent of the frame identified by `token` and with
  // `form` as parent.
  void SetSelfAsParent(const autofill::FormData& form, LocalFrameToken token);

  // Updates the saved information about the last interacted form or formless
  // field.
  // - `form_data`: `FormData` version of the interacted form or
  // formless form.
  // - `formless_field`: Renderer id of the interacted formless
  // field. Default to `FieldRendererId()` when the user interaction was not
  // with a single formless field.
  void UpdateLastInteractedForm(
      const FormData& form_data,
      const FieldRendererId& formless_field = FieldRendererId());
  // Clears the saved information about the last interacted form or formless
  // field.
  void ClearLastInteractedForm();

  // Updates the snapshot of the last interacted form or formless form with
  // field data in `autofill::FieldDataManager`. Called before sending a
  // submitted form to `autofill::AutofillManager`.
  void UpdateLastInteractedFormFromFieldDataManager();

  // Whether a form submission can be inferred after a form removal event.
  bool DetectFormSubmissionAfterFormRemoval(
      const std::set<FormRendererId>& removed_forms,
      const std::set<FieldRendererId>& removed_unowned_fields) const;

  // AutofillManager::Observer:
  void OnAutofillManagerStateChanged(
      AutofillManager& manager,
      AutofillManager::LifecycleState old_state,
      AutofillManager::LifecycleState new_state) override;
  void OnAfterFormsSeen(AutofillManager& manager,
                        base::span<const FormGlobalId> updated_forms,
                        base::span<const FormGlobalId> removed_forms) override;

  // Logs metrics related to form removal events.
  void RecordFormRemoval(bool submission_detected,
                         int removed_forms_count,
                         int removed_unowned_fields_count);

  // The WebState with which this object is associated.
  raw_ptr<web::WebState> web_state_ = nullptr;

  // The id of the WebFrame with which this object is associated.
  // "" if frame messaging is disabled.
  std::string web_frame_id_;

  // A LocalFrameToken containing a value equivalent to `web_frame_id_` if that
  // string is populated with a valid 128-bit hex value, or empty otherwise.
  LocalFrameToken local_frame_token_;

  // The driver of this frame's parent frame, if it is known and valid. Always
  // null for the main (root) frame.
  base::WeakPtr<AutofillDriverIOS> parent_ = nullptr;

  // All RemoteFrameTokens that have ever been dispatched from this frame to
  // a child frame.
  base::flat_set<RemoteFrameToken> known_child_frames_;

  // AutofillDriverIOSBridge instance that is passed in.
  __unsafe_unretained id<AutofillDriverIOSBridge> bridge_;

  // Whether the initial processing has been done (JavaScript observers have
  // been enabled and the forms have been extracted).
  bool processed_ = false;

  // Information about the last form or formless field where the user entered
  // data. Used for form submission detection.
  std::optional<LastInteractedForm> last_interacted_form_;

  // The embedder's AutofillClient instance.
  raw_ref<AutofillClient> client_;

  std::unique_ptr<BrowserAutofillManager> manager_;

  base::ScopedObservation<AutofillManager, AutofillManager::Observer>
      manager_observation_{this};

  raw_ptr<AutofillDriverRouter> router_;

  // True if the drive was once unregistered.
  bool unregistered_ = false;

  base::WeakPtrFactory<AutofillDriverIOS> weak_ptr_factory_{this};
};

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_H_