1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
6 #define CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
7 
8 #include <oleacc.h>
9 
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <vector>
14 
15 #include "base/macros.h"
16 #include "content/browser/accessibility/browser_accessibility_manager.h"
17 #include "ui/accessibility/platform/ax_platform_node_win.h"
18 
19 namespace content {
20 class BrowserAccessibilityWin;
21 
22 // Manages a tree of BrowserAccessibilityWin objects.
23 class CONTENT_EXPORT BrowserAccessibilityManagerWin
24     : public BrowserAccessibilityManager {
25  public:
26   BrowserAccessibilityManagerWin(const ui::AXTreeUpdate& initial_tree,
27                                  BrowserAccessibilityDelegate* delegate);
28 
29   ~BrowserAccessibilityManagerWin() override;
30 
31   static ui::AXTreeUpdate GetEmptyDocument();
32 
33   // Get the closest containing HWND.
34   HWND GetParentHWND();
35 
36   // BrowserAccessibilityManager methods
37   void UserIsReloading() override;
38   BrowserAccessibility* GetFocus() const override;
39   bool CanFireEvents() const override;
40   gfx::Rect GetViewBoundsInScreenCoordinates() const override;
41 
42   void FireFocusEvent(BrowserAccessibility* node) override;
43   void FireBlinkEvent(ax::mojom::Event event_type,
44                       BrowserAccessibility* node) override;
45   void FireGeneratedEvent(ui::AXEventGenerator::Event event_type,
46                           BrowserAccessibility* node) override;
47 
48   void FireWinAccessibilityEvent(LONG win_event, BrowserAccessibility* node);
49   void FireUiaAccessibilityEvent(LONG uia_event, BrowserAccessibility* node);
50   void FireUiaPropertyChangedEvent(LONG uia_property,
51                                    BrowserAccessibility* node);
52   void FireUiaStructureChangedEvent(StructureChangeType change_type,
53                                     BrowserAccessibility* node);
54 
55   // Do event pre-processing
56   void BeforeAccessibilityEvents() override;
57 
58   // Do event post-processing
59   void FinalizeAccessibilityEvents() override;
60 
61   // Track this object and post a VISIBLE_DATA_CHANGED notification when
62   // its container scrolls.
63   // TODO(dmazzoni): remove once http://crbug.com/113483 is fixed.
64   void TrackScrollingObject(BrowserAccessibilityWin* node);
65 
66   // Called when |accessible_hwnd_| is deleted by its parent.
67   void OnAccessibleHwndDeleted();
68 
69  protected:
70   // AXTreeObserver methods.
71   void OnSubtreeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
72   void OnNodeWillBeDeleted(ui::AXTree* tree, ui::AXNode* node) override;
73   void OnAtomicUpdateFinished(
74       ui::AXTree* tree,
75       bool root_changed,
76       const std::vector<ui::AXTreeObserver::Change>& changes) override;
77 
78  private:
79   struct SelectionEvents {
80     std::vector<BrowserAccessibility*> added;
81     std::vector<BrowserAccessibility*> removed;
82     SelectionEvents();
83     ~SelectionEvents();
84   };
85 
86   using SelectionEventsMap = std::map<BrowserAccessibility*, SelectionEvents>;
87   using IsSelectedPredicate =
88       base::RepeatingCallback<bool(BrowserAccessibility*)>;
89   using FirePlatformSelectionEventsCallback =
90       base::RepeatingCallback<void(BrowserAccessibility*,
91                                    BrowserAccessibility*,
92                                    const SelectionEvents&)>;
93 
94   static bool IsIA2NodeSelected(BrowserAccessibility* node);
95   static bool IsUIANodeSelected(BrowserAccessibility* node);
96 
97   void FireIA2SelectionEvents(BrowserAccessibility* container,
98                               BrowserAccessibility* only_selected_child,
99                               const SelectionEvents& changes);
100   void FireUIASelectionEvents(BrowserAccessibility* container,
101                               BrowserAccessibility* only_selected_child,
102                               const SelectionEvents& changes);
103 
104   static void HandleSelectedStateChanged(
105       SelectionEventsMap& selection_events_map,
106       BrowserAccessibility* node,
107       bool is_selected);
108 
109   static void FinalizeSelectionEvents(
110       SelectionEventsMap& selection_events_map,
111       IsSelectedPredicate is_selected_predicate,
112       FirePlatformSelectionEventsCallback fire_platform_events_callback);
113 
114   void HandleAriaPropertiesChangedEvent(BrowserAccessibility& node);
115   void HandleTextChangedEvent(BrowserAccessibility& node);
116   void HandleTextSelectionChangedEvent(BrowserAccessibility& node);
117 
118   // Give BrowserAccessibilityManager::Create access to our constructor.
119   friend class BrowserAccessibilityManager;
120 
121   // Keep track of if we got a "load complete" event but were unable to fire
122   // it because of no HWND, because otherwise JAWS can get very confused.
123   // TODO(dmazzoni): a better fix would be to always have an HWND.
124   // http://crbug.com/521877
125   bool load_complete_pending_;
126 
127   // Since there could be multiple aria property changes on a node and we only
128   // want to fire UIA_AriaPropertiesPropertyId once for that node, we use the
129   // set here to keep track of the unique nodes that had aria property changes,
130   // so we only fire the event once for every node.
131   std::set<BrowserAccessibility*> aria_properties_events_;
132 
133   // Since there could be duplicate text selection changed events on a node
134   // raised from both FireBlinkEvent and FireGeneratedEvent, we use the set here
135   // to keep track of the unique nodes that had
136   // UIA_Text_TextSelectionChangedEventId, so we only fire the event once for
137   // every node.
138   std::set<BrowserAccessibility*> text_selection_changed_events_;
139 
140   // Since there could be duplicate text changed events on a node raised from
141   // both FireBlinkEvent and FireGeneratedEvent, we use the set here to keep
142   // track of the unique nodes that had UIA_Text_TextChangedEventId, so we only
143   // fire the event once for every node.
144   std::set<BrowserAccessibility*> text_changed_events_;
145 
146   // When the ignored state changes for a node, we only want to fire the
147   // events relevant to the ignored state change (e.g. show / hide).
148   // This set keeps track of what nodes should suppress superfluous events.
149   std::set<BrowserAccessibility*> ignored_changed_nodes_;
150 
151   // Keep track of selection changes so we can optimize UIA event firing.
152   // Pointers are only stored for the duration of |OnAccessibilityEvents|, and
153   // the map is cleared in |FinalizeAccessibilityEvents|.
154   SelectionEventsMap ia2_selection_events_;
155   SelectionEventsMap uia_selection_events_;
156 
157   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityManagerWin);
158 };
159 
160 }  // namespace content
161 
162 #endif  // CONTENT_BROWSER_ACCESSIBILITY_BROWSER_ACCESSIBILITY_MANAGER_WIN_H_
163