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_
|