File: form_tracker.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (222 lines) | stat: -rw-r--r-- 8,319 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// Copyright 2017 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_CONTENT_RENDERER_FORM_TRACKER_H_
#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_FORM_TRACKER_H_

#include <optional>
#include <variant>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/types/strong_alias.h"
#include "components/autofill/content/renderer/timing.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom.h"
#include "components/autofill/core/common/unique_ids.h"
#include "content/public/renderer/render_frame_observer.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame_observer.h"

namespace blink {
class WebFormElementObserver;
}

namespace autofill {

class AutofillAgent;

// Reference to a WebFormElement, represented as such and as a FormRendererId.
// TODO(crbug.com/40056157): Replace with FormRendererId when
// `kAutofillReplaceCachedWebElementsByRendererIds` launches.
class FormRef {
 public:
  FormRef() = default;
  explicit FormRef(blink::WebFormElement form);

  blink::WebFormElement GetForm() const;
  FormRendererId GetId() const;

 private:
  blink::WebFormElement form_;
  FormRendererId form_renderer_id_;
};

// Reference to a WebFormControlElement, represented as such and as a
// FieldRendererId.
// TODO(crbug.com/40056157): Replace with FieldRendererId when
// `kAutofillReplaceCachedWebElementsByRendererIds` launches.
class FieldRef {
 public:
  FieldRef() = default;
  explicit FieldRef(blink::WebFormControlElement form_control);
  explicit FieldRef(blink::WebElement content_editable);

  friend bool operator<(const FieldRef& lhs, const FieldRef& rhs);

  blink::WebFormControlElement GetField() const;
  blink::WebElement GetContentEditable() const;
  FieldRendererId GetId() const;

 private:
  blink::WebElement field_;
  FieldRendererId field_renderer_id_;
};

// TODO(crbug.com/40550175): Track the select and checkbox change.
// This class is used to track user's change of form or WebFormControlElement,
// notifies observers of form's change and submission.
class FormTracker : public content::RenderFrameObserver,
                    public blink::WebLocalFrameObserver {
 public:
  enum class SaveFormReason {
    kTextFieldChanged,
    // TODO(crbug.com/40281981): Remove after launching the feature
    // kAutofillPreferSavedFormAsSubmittedForm.
    kWillSendSubmitEvent,
    kSelectChanged,
  };

  using UserGestureRequired =
      base::StrongAlias<class UserGestureRequiredTag, bool>;
  explicit FormTracker(content::RenderFrame* render_frame,
                       AutofillAgent& agent);

  FormTracker(const FormTracker&) = delete;
  FormTracker& operator=(const FormTracker&) = delete;

  ~FormTracker() override;

  // Same methods as those in blink::WebAutofillClient, but invoked by
  // AutofillAgent.
  void AjaxSucceeded();
  void TextFieldValueChanged(const blink::WebFormControlElement& element);
  void SelectControlSelectionChanged(
      const blink::WebFormControlElement& element);
  virtual void ElementDisappeared(const blink::WebElement& element);

  // Tells the tracker to track the autofilled `element`. Since autofilling a
  // form or field won't trigger the regular *DidChange events, the tracker
  // won't be notified of this `element` otherwise. This is currently only used
  // by PWM.
  void TrackAutofilledElement(const blink::WebFormControlElement& element);

  // Called in order to update submission data when a form is autofilled.
  // `filled_fields_and_forms` represent the fields and forms that were affected
  // by the corresponding autofill operation  and is used to determine an
  // appropriate single element to track.
  void TrackAutofilledElement(
      const base::flat_map<FieldRendererId, FormRendererId>&
          filled_fields_and_forms);

  void UpdateLastInteractedElement(
      std::variant<FormRendererId, FieldRendererId> element_id);
  void ResetLastInteractedElements();

  // Set whether a user gesture is required to accept text changes. If
  // `user_gesture_required` is false, text changes without user gestures are
  // discarded.
  void SetUserGestureRequired(UserGestureRequired user_gesture_required);

  FormRef last_interacted_form() const { return last_interacted_.form; }

  // TODO(crbug.com/40281981): Remove.
  std::optional<FormData>& provisionally_saved_form() {
    return last_interacted_.saved_state;
  }

  bool IsTracking() const;

 private:
  friend class FormTrackerTestApi;

  // content::RenderFrameObserver:
  void DidCommitProvisionalLoad(ui::PageTransition transition) override;
  void DidFinishSameDocumentNavigation() override;
  void DidStartNavigation(
      const GURL& url,
      std::optional<blink::WebNavigationType> navigation_type) override;
  void WillDetach(blink::DetachReason detach_reason) override;
  void WillSubmitForm(const blink::WebFormElement& form) override;
  void OnDestruct() override;

  // The RenderFrame* is nullptr while the AutofillAgent that owns this
  // FormTracker is pending deletion, between OnDestruct() and ~FormTracker().
  content::RenderFrame* unsafe_render_frame() const {
    return content::RenderFrameObserver::render_frame();
  }

  // Use unsafe_render_frame() instead.
  template <typename T = int>
  content::RenderFrame* render_frame(T* = 0) const {
    static_assert(
        std::is_void_v<T>,
        "Beware that the RenderFrame may become nullptr by OnDestruct() "
        "because AutofillAgent destructs itself asynchronously. Use "
        "unsafe_render_frame() instead and make test that it is non-nullptr.");
  }

  // content::WebLocalFrameObserver:
  void OnFrameDetached() override {}
  void WillSendSubmitEvent(const blink::WebFormElement& form) override;

  // Called in a posted task by textFieldDidChange() to work-around a WebKit bug
  // http://bugs.webkit.org/show_bug.cgi?id=16976 , we also don't want to
  // process element while it is changing.
  void FormControlDidChangeImpl(FieldRendererId element_id,
                                SaveFormReason change_source);
  // Virtual for testing.
  virtual void FireFormSubmission(
      mojom::SubmissionSource source,
      std::optional<blink::WebFormElement> submitted_form_element);
  void FireSubmissionIfFormDisappear(mojom::SubmissionSource source);
  bool CanInferFormSubmitted();

  // Tracks the cached element, as well as its ancestors, until it disappears
  // (removed or hidden), then directly infers submission. `source` is the type
  // of submission to fire when the tracked element disappears.
  // TODO(crbug.com/40281981): Remove.
  void TrackElement(mojom::SubmissionSource source);

  // Invoked when the observed element was either removed from the DOM or it's
  // computed style changed to display: none. `source` is the type of submission
  // to be inferred in case this function is called.
  // TODO(crbug.com/40281981): Remove.
  void ElementWasHiddenOrRemoved(mojom::SubmissionSource source);

  // Whether a user gesture is required to pass on text field change events.
  UserGestureRequired user_gesture_required_ = UserGestureRequired(true);

  struct {
    FormRef form;
    FieldRef formless_element;
    // Used when a FormData version of the last interacted form is needed if
    // we'd like to avoid extracting using `form`.
    std::optional<FormData> saved_state;
  } last_interacted_;

  // TODO(crbug.com/40281981): Remove.
  raw_ptr<blink::WebFormElementObserver> form_element_observer_ = nullptr;

  struct {
    bool tracked_element_disappeared = false;
    bool tracked_element_autofilled = false;
    bool finished_same_document_navigation = false;
    bool xhr_succeeded = false;
  } submission_triggering_events_;

  // The object owning this `FormTracker`.
  raw_ref<AutofillAgent> agent_;

  SEQUENCE_CHECKER(form_tracker_sequence_checker_);

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

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CONTENT_RENDERER_FORM_TRACKER_H_