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
content / public / test / accessibility_notification_waiter.h [blame]
// 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 CONTENT_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_
#define CONTENT_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/accessibility/ax_event_generator.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/accessibility/ax_node_id_forward.h"
#include "ui/accessibility/ax_tree.h"
namespace base {
class RunLoop;
}
namespace ui {
class BrowserAccessibilityManager;
}
namespace content {
class RenderFrameHost;
class RenderFrameHostImpl;
class WebContents;
// Create an instance of this class *before* doing any operation that
// might generate an accessibility event (like a page navigation or
// clicking on a button). Then call WaitForNotification
// afterwards to block until the specified accessibility notification has been
// received.
class AccessibilityNotificationWaiter : public WebContentsObserver {
public:
// Will wait for any event across all ways including scroll or location
// changes as well normal and generated events.
explicit AccessibilityNotificationWaiter(WebContents* web_contents);
// Wait for a specific Blink event.
AccessibilityNotificationWaiter(WebContents* web_contents,
ui::AXMode accessibility_mode,
ax::mojom::Event event);
// Wait for a specific AXEventGenerator event.
AccessibilityNotificationWaiter(WebContents* web_contents,
ui::AXMode accessibility_mode,
ui::AXEventGenerator::Event event);
AccessibilityNotificationWaiter(const AccessibilityNotificationWaiter&) =
delete;
AccessibilityNotificationWaiter& operator=(
const AccessibilityNotificationWaiter&) = delete;
~AccessibilityNotificationWaiter() override;
// Blocks until the specific accessibility notification registered in
// AccessibilityNotificationWaiter is received. Returns true if an event was
// received, false if waiting ended for some other reason.
// Pass true for |all_frames| to wait for a notification on all frames
// before returning, rather than waiting for only a single notification
// from any frame.
[[nodiscard]] bool WaitForNotification(bool all_frames = false);
// Blocks until the notification is received, or the given timeout passes.
// Returns true if an event was received, false if waiting ended for some
// other reason.
[[nodiscard]] bool WaitForNotificationWithTimeout(base::TimeDelta timeout);
// After WaitForNotification has returned, this will retrieve
// the tree of accessibility nodes received from the renderer process for
// the observed WebContents (not including the trees of inner WebContents).
const ui::AXTree& GetAXTree() const;
// After WaitForNotification returns, use this to retrieve the id of the
// node that was the target of the event.
int event_target_id() const { return event_target_id_; }
bool notification_received() const { return notification_received_; }
// After WaitForNotification returns, use this to retrieve the
// `BrowserAccessibilityManager` that was the target of the event.
ui::BrowserAccessibilityManager* event_browser_accessibility_manager() const {
return event_browser_accessibility_manager_;
}
// WebContentsObserver override:
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) override;
// Quits listening and unblocks WaitForNotification* calls.
void Quit();
private:
// Listen to all frames within the frame tree of this WebContents.
void ListenToAllFrames(WebContents* web_contents);
// Bind either the OnAccessibilityEvent or OnGeneratedEvent callback
// for a given frame within the WebContent's frame tree.
void ListenToFrame(RenderFrameHostImpl* frame_host);
// Helper to bind the OnAccessibilityEvent callback.
void BindOnAccessibilityEvent(RenderFrameHostImpl* frame_host);
// Helper to bind the OnGeneratedEvent callback.
void BindOnGeneratedEvent(RenderFrameHostImpl* frame_host);
// Helper to bind the OnLocationsChanged callback.
void BindOnLocationsChanged(RenderFrameHostImpl* frame_host);
// Callback from RenderViewHostImpl.
void OnAccessibilityEvent(RenderFrameHostImpl* rfhi,
ax::mojom::Event event,
int event_target_id);
// Callback from BrowserAccessibilityManager for all generated events.
void OnGeneratedEvent(ui::BrowserAccessibilityManager* manager,
ui::AXEventGenerator::Event event,
ui::AXNodeID event_target_id);
// Callback from BrowserAccessibilityManager when locations / bounding
// boxes change.
void OnLocationsChanged();
// Callback from BrowserAccessibilityManager for the focus changed event.
//
// TODO(crbug.com/41470112): Remove this method once we migrate to using
// AXEventGenerator for focus changed events.
void OnFocusChanged();
// Returns the tree of accessibility nodes received from renderer processes
// for the WebContents that owns `render_frame`. This may not be the observed
// WebContents, but rather an inner WebContents (e.g., for a guest view).
const ui::AXTree& GetAXTreeForFrame(RenderFrameHostImpl* render_frame) const;
std::optional<ax::mojom::Event> event_to_wait_for_;
std::optional<ui::AXEventGenerator::Event> generated_event_to_wait_for_;
std::unique_ptr<base::RunLoop> loop_runner_;
base::RepeatingClosure loop_runner_quit_closure_;
int event_target_id_ = 0;
raw_ptr<ui::BrowserAccessibilityManager, AcrossTasksDanglingUntriaged>
event_browser_accessibility_manager_ = nullptr;
bool notification_received_ = false;
int frame_count_ = 0;
int notification_count_ = 0;
bool wait_for_any_event_ = false;
base::WeakPtrFactory<AccessibilityNotificationWaiter> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_PUBLIC_TEST_ACCESSIBILITY_NOTIFICATION_WAITER_H_