| // 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/foundations/autofill_client.h" |
| #import "components/autofill/core/browser/foundations/browser_autofill_manager.h" |
| #import "components/autofill/core/common/mojom/autofill_types.mojom-shared.h" |
| #import "components/autofill/ios/browser/form_fetch_batcher.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 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 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, |
| base::PassKey<AutofillDriverIOSFactory>); |
| |
| ~AutofillDriverIOS() override; |
| |
| // AutofillDriver: |
| LocalFrameToken GetFrameToken() const override; |
| std::optional<LocalFrameToken> Resolve(FrameToken query) override; |
| AutofillDriverIOS* GetParent() override; |
| bool IsActive() const override; |
| bool IsEmbedded() const override; |
| AutofillClient& GetAutofillClient() override; |
| BrowserAutofillManager& GetAutofillManager() override; |
| ukm::SourceId GetPageUkmSourceId() 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, |
| const Section& section_for_clear_form_on_ios) override; |
| void ApplyFieldAction(mojom::FieldActionType action_type, |
| mojom::ActionPersistence action_persistence, |
| const FieldGlobalId& field_id, |
| const std::u16string& value) override; |
| void ExtractFormWithField( |
| FieldGlobalId field_id, |
| base::OnceCallback<void(AutofillDriver*, const std::optional<FormData>&)> |
| response_callback) override; |
| void ExposeDomNodeIdsInAllFrames() override; |
| void SendTypePredictionsToRenderer(const FormStructure& form) 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 ExtractLabeledTextNodeValue( |
| const std::u16string& value_regex, |
| const std::u16string& label_regex, |
| uint32_t number_of_ancestor_levels_to_search, |
| base::OnceCallback<void(const std::string& amount)> response_callback) |
| override; |
| void DispatchEmailVerifiedEvent( |
| FieldGlobalId field_id, |
| const std::string& presentation_token) 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; |
| base::WeakPtr<AutofillDriverIOS> GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| // 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 DidAutofillForm(const FormData& form); |
| void FormsSeen(const std::vector<FormData>& updated_forms, |
| const std::vector<FormGlobalId>& removed_forms); |
| void FormSubmitted(const FormData& form, |
| mojom::SubmissionSource submission_source); |
| void CaretMovedInFormField(const FormData& form, |
| const FieldGlobalId& field_id, |
| const gfx::Rect& caret_bounds); |
| void TextFieldValueChanged(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(); |
| |
| // Called when form extraction was triggered on the driver's frame. Called |
| // as soon as the extraction request is started regardless of the results. |
| void OnDidTriggerFormFetch(); |
| |
| // Scans to find all eligible forms in the frame's document. If batching is |
| // enabled and `immediately` is true, runs this scan and the batch |
| // immediately altogether. |
| void ScanForms(bool immediately = false); |
| |
| // Fetches forms filtered by `form_name` and calls `caller_completion` with |
| // the form fetch results upon completion of the fetch. |
| void FetchFormsFilteredByName(const std::u16string& form_name, |
| FormFetchCompletion completion); |
| |
| 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); |
| |
| // Logs metrics related to triggered form extraction. |
| void RecordTriggeredFormExtractionMetrics(); |
| |
| // 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. |
| __weak 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; |
| |
| // Counter for the number of form extractions that were triggered during the |
| // driver's lifetime. The counter doesn't care whether the extraction |
| // actually happened for real where it focuses on the trigger. |
| int form_extraction_trigger_count_ = 0; |
| |
| // FetchRequestBatcher used exclusively for batching document form scans. |
| FormFetchBatcher document_scan_batcher_; |
| |
| // FetchRequestBatcher used exclusively for batching filtered document form |
| // scans. |
| FormFetchBatcher document_filtered_scan_batcher_; |
| |
| base::WeakPtrFactory<AutofillDriverIOS> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace autofill |
| |
| #endif // COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_H_ |