File: autofill_driver_router.h

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; 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 (331 lines) | stat: -rw-r--r-- 14,222 bytes parent folder | download | duplicates (2)
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
// Copyright 2021 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_CORE_BROWSER_FOUNDATIONS_AUTOFILL_DRIVER_ROUTER_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_FOUNDATIONS_AUTOFILL_DRIVER_ROUTER_H_

#include <optional>
#include <string>

#include "base/containers/flat_map.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/foundations/autofill_driver.h"
#include "components/autofill/core/browser/foundations/form_forest.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"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "ui/gfx/geometry/rect_f.h"

namespace autofill {

// AutofillDriverRouter routes events between AutofillDriver objects in order to
// handle frame-transcending forms.
//
// A *frame-transcending* form is a form whose fields live in different frames.
// For example, credit card forms often have the credit card number field in an
// iframe hosted by a payment service provider.
//
// A frame-transcending form therefore consists of multiple *renderer forms*.
// AutofillDriverRouter *flattens* these forms into a single *browser form*,
// and maps all events concerning the renderer forms to that browser form, and
// vice versa.
//
// That way, the collection of renderer forms appears as one ordinary form to
// the browser.
//
// For example, consider the following pseudo HTML code:
//   <html>
//   <form id="Form-1">
//     <input id="Field-1">
//     <iframe id="Frame-1">
//       <input id="Field-2">
//     </iframe>
//     <iframe id="Frame-2">
//       <iframe id="Frame-3">
//         <form id="Form-2">
//           <input id="Field-3">
//         </form>
//         <form id="Form-3">
//           <input id="Field-4">
//         </form>
//       </iframe>
//     </iframe>
//     <input id="Field-5">
//   </form>
//
// Forms can be actual <form> elements or synthetic forms: <input>, <select>,
// and <iframe> elements that are not in the scope of any <form> belong to the
// enclosing frame's synthetic form.
//
// The five renderer forms are therefore, in pseudo C++ code:
//   FormData{
//     .host_frame = "Frame-0",  // The main frame.
//     .name = "Form-1",
//     .fields = { "Field-1", "Field-5" },
//     .child_frames = { "Frame-1", "Frame-2" }
//   }
//   FormData{
//     .host_frame = "Frame-1",
//     .name = "synthetic",
//     .fields = { "Field-2" },
//     .child_frames = { }
//   }
//   FormData{
//     .host_frame = "Frame-2",
//     .name = "synthetic",
//     .fields = { },
//     .child_frames = { "Frame-3" }
//   }
//   FormData{
//     .host_frame = "Frame-3",
//     .name = "Form-2",
//     .fields = { "Field-3" },
//     .child_frames = { }
//   }
//   FormData{
//     .host_frame = "Frame-3",
//     .name = "Form-3",
//     .fields = { "Field-4" },
//     .child_frames = { }
//   }
//
// The browser form of these renderer forms is obtained by flattening the fields
// into the root form:
//   FormData{
//     .name = "Form-1",
//     .fields = { "Field-1", "Field-2", "Field-3", "Field-4", "Field-5" }
//   }
//
// Let AutofillAgent-N, AutofillDriver-N, and AutofillManager-N correspond to
// the Frame-N. AutofillDriverRouter would route an event concerning any of the
// forms in Frame-3 from AutofillDriver-3 to AutofillDriver-0:
//
//   +---Tab---+            +---Tab----+            +----Tab----+
//   | Agent-0 |      +---> | Driver-0 | ---------> | Manager-0 |
//   |         |      |     |          |            |           |
//   | Agent-1 |      |     | Driver-1 |            | Manager-1 |
//   |         |      |     |          |            |           |
//   | Agent-2 |      |     | Driver-2 |            | Manager-2 |
//   |         |      |     |          |            |           |
//   | Agent-3 | -----|---> | Driver-3 | -----+     | Manager-3 |
//   +---------+      |     +----------+      |     +-----------+
//                    |                       |
//                    |      +--Tab---+       |
//                    +----- | Router | <-----+
//                           +--------+
//
// If the event name is `Foo`, the control flow is as follows:
//   Driver-3.Foo(args1...)          calls
//   Router.Foo(callback, args1...)  calls
//   callback(Driver-0, args2...),
// where `args2` are obtained by mapping renderer forms to browser forms and
// vice versa.
//
// Events triggered by the renderer take a |source| parameter, which is the
// driver of the frame whose DOM contains the renderer form.
//
// See ContentAutofillDriver for details on the naming pattern and an example.
//
// See FormForest for details on (un)flattening.
class AutofillDriverRouter {
 public:
  template <typename... Args>
  using RoutedCallback = base::FunctionRef<void(AutofillDriver&, Args...)>;

  AutofillDriverRouter();
  AutofillDriverRouter(const AutofillDriverRouter&) = delete;
  AutofillDriverRouter& operator=(const AutofillDriverRouter&) = delete;
  ~AutofillDriverRouter();

  // Deletes all forms and fields related to |driver| (and this driver only).
  // Must be called whenever |driver| is destroyed.
  //
  // |driver_is_dying| indicates if the |driver| is being destructed or about to
  // be destructed. Typically, the driver dies on cross-origin navigations but
  // survives same-origin navigations (but more precisely this depends on the
  // lifecycle of the content::RenderFrameHost). If the driver survives, the
  // router may keep the meta data is collected about the frame (in particular,
  // the parent frame).
  void UnregisterDriver(AutofillDriver& driver, bool driver_is_dying);

  // Events called by the renderer, passed to the browser:
  // Keep in alphabetic order.
  void FormsSeen(RoutedCallback<const std::vector<FormData>&,
                                const std::vector<FormGlobalId>&> callback,
                 AutofillDriver& source,
                 std::vector<FormData> updated_forms,
                 const std::vector<FormGlobalId>& removed_forms);
  void FormSubmitted(
      RoutedCallback<const FormData&, mojom::SubmissionSource> callback,
      AutofillDriver& source,
      FormData form,
      mojom::SubmissionSource submission_source);
  void CaretMovedInFormField(
      RoutedCallback<const FormData&, const FieldGlobalId&, const gfx::Rect&>
          callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id,
      const gfx::Rect& caret_bounds);
  void TextFieldValueChanged(
      RoutedCallback<const FormData&, const FieldGlobalId&, base::TimeTicks>
          callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id,
      base::TimeTicks timestamp);
  void TextFieldDidScroll(
      RoutedCallback<const FormData&, const FieldGlobalId&> callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id);
  void SelectControlSelectionChanged(
      RoutedCallback<const FormData&, const FieldGlobalId&> callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id);
  void AskForValuesToFill(
      RoutedCallback<const FormData&,
                     const FieldGlobalId&,
                     const gfx::Rect&,
                     AutofillSuggestionTriggerSource,
                     std::optional<PasswordSuggestionRequest>> callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id,
      const gfx::Rect& caret_bounds,
      AutofillSuggestionTriggerSource trigger_source,
      std::optional<PasswordSuggestionRequest> password_request);
  // This event is broadcast to all drivers.
  void DidEndTextFieldEditing(RoutedCallback<> callback,
                              AutofillDriver& source);
  void DidFillAutofillFormData(
      RoutedCallback<const FormData&, base::TimeTicks> callback,
      AutofillDriver& source,
      FormData form,
      base::TimeTicks timestamp);
  void FocusOnFormField(
      RoutedCallback<const FormData&, const FieldGlobalId&> callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id,
      RoutedCallback<> focus_no_longer_on_form);
  // This event is broadcast to all drivers.
  void FocusOnNonFormField(RoutedCallback<> callback, AutofillDriver& source);
  // This event is broadcast to all drivers.
  void HidePopup(RoutedCallback<> callback, AutofillDriver& source);
  void JavaScriptChangedAutofilledValue(
      RoutedCallback<const FormData&,
                     const FieldGlobalId&,
                     const std::u16string&> callback,
      AutofillDriver& source,
      FormData form,
      const FieldGlobalId& field_id,
      const std::u16string& old_value);
  void SelectFieldOptionsDidChange(RoutedCallback<const FormData&> callback,
                                   AutofillDriver& source,
                                   FormData form);

  // Events called by the browser, passed to the renderer:
  // Keep in alphabetic order.
  base::flat_set<FieldGlobalId> ApplyFormAction(
      RoutedCallback<mojom::FormActionType,
                     mojom::ActionPersistence,
                     const std::vector<FormFieldData::FillData>&> callback,
      mojom::FormActionType action_type,
      mojom::ActionPersistence action_persistence,
      base::span<const FormFieldData> data,
      const url::Origin& main_origin,
      const url::Origin& triggered_origin,
      const base::flat_map<FieldGlobalId, FieldType>& field_type_map);
  void ApplyFieldAction(RoutedCallback<mojom::FieldActionType,
                                       mojom::ActionPersistence,
                                       FieldRendererId,
                                       const std::u16string&> callback,
                        mojom::FieldActionType action_type,
                        mojom::ActionPersistence action_persistence,
                        const FieldGlobalId& field_id,
                        const std::u16string& value);
  using BrowserFormHandler = AutofillDriver::BrowserFormHandler;
  using RendererFormHandler =
      base::OnceCallback<void(const std::optional<FormData>&)>;
  // Routes both the request *and* the response: it calls `callback` with
  // - the `target` driver that shall extract the form,
  // - the `form_id` to be extracted, and
  // - the `renderer_form_handler` that processes the extracted form.
  //
  // Processing the extracted form means to call the callback
  // `browser_form_handler`. For that to happen, the extracted renderer form
  // must be mapped to a browser form. The `renderer_form_handler` performs this
  // conversion and then passes the result to `browser_form_handler` together
  // with the driver that manages the browser form (i.e., the driver whose
  // AutofillDriver::GetFrameToken() is equal to the browser form's
  // FormData::host_frame`).
  //
  // It is the responsibility of `callback` to call `renderer_form_handler`
  // with the extracted renderer form so that the mapping and callback can
  // happen.
  //
  // So intuitively, `callback` should do something like
  // `target->autofill_agent()->ExtractForm(form_id, renderer_form_handler)`.
  //
  // If routing the request fails, ExtractForm() calls `browser_form_handler`
  // right away with nullptr and std::nullopt.
  void ExtractForm(RoutedCallback<FormRendererId, RendererFormHandler> callback,
                   FormGlobalId form_id,
                   BrowserFormHandler browser_form_handler);
  void RendererShouldAcceptDataListSuggestion(
      RoutedCallback<FieldRendererId, const std::u16string&> callback,
      const FieldGlobalId& field_id,
      const std::u16string& value);
  void RendererShouldClearPreviewedForm(RoutedCallback<> callback);
  void RendererShouldSetSuggestionAvailability(
      RoutedCallback<FieldRendererId, mojom::AutofillSuggestionAvailability>
          callback,
      const FieldGlobalId& field_id,
      mojom::AutofillSuggestionAvailability suggestion_availability);
  void RendererShouldTriggerSuggestions(
      RoutedCallback<FieldRendererId, AutofillSuggestionTriggerSource> callback,
      const FieldGlobalId& field_id,
      AutofillSuggestionTriggerSource trigger_source);
  void SendTypePredictionsToRenderer(
      RoutedCallback<const std::vector<FormDataPredictions>&> callback,
      const FormDataPredictions& type_predictions);

  // Returns the underlying renderer forms of `browser_form`.
  // Note that this function is intended for use outside of the `autofill`
  // component to ensure compatibility with callers whose concept of a form
  // does not include frame-transcending forms. It returns the constituent
  // renderer forms regardless of their frames' origins and the field types.
  std::vector<FormData> GetRendererForms(const FormData& browser_form) const;

 private:
  // Returns the driver of |frame| stored in |form_forest_|.
  // Does not invalidate any forms in the FormForest.
  AutofillDriver* DriverOfFrame(LocalFrameToken frame);

  // Calls AutofillDriver::TriggerFormExtractionInDriverFrame() for all
  // drivers in |form_forest_| except for |exception|.
  void TriggerFormExtractionExcept(AutofillDriver& exception);

  // The forest of forms. See its documentation for the usage protocol.
  internal::FormForest form_forest_;

  // When the focus moves to a different frame, the order of the events
  // FocusOnNonFormField() and FocusOnFormField() may be reversed due to race
  // conditions. We use these members to correct the order of the events.
  LocalFrameToken focused_frame_;
  bool focus_no_longer_on_form_has_fired_ = true;

  // The maximum number of coexisting FormForest::FrameDatas over the lifetime
  // of this factory.
  // TODO: crbug.com/342132628 - Remove the counter and the metric.
  size_t max_frame_datas_ = 0;
};

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FOUNDATIONS_AUTOFILL_DRIVER_ROUTER_H_