AX: WKTR: Don't update isolated tree mode behavior if not required
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / AccessibilityController.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "AccessibilityController.h"
28
29 #if ENABLE(ACCESSIBILITY)
30
31 #include "AccessibilityUIElement.h"
32 #include "InjectedBundle.h"
33 #include "InjectedBundlePage.h"
34 #include "JSAccessibilityController.h"
35 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
36 #include <pal/spi/mac/HIServicesSPI.h>
37 #endif
38 #include <WebKit/WKBundle.h>
39 #include <WebKit/WKBundlePage.h>
40 #include <WebKit/WKBundlePagePrivate.h>
41
42 namespace WTR {
43
44 Ref<AccessibilityController> AccessibilityController::create()
45 {
46     return adoptRef(*new AccessibilityController);
47 }
48
49 AccessibilityController::AccessibilityController()
50 {
51 }
52
53 AccessibilityController::~AccessibilityController()
54 {
55 }
56
57 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
58 void AccessibilityController::setAccessibilityIsolatedTreeMode(bool flag)
59 {
60     if (m_accessibilityIsolatedTreeMode != flag) {
61         m_accessibilityIsolatedTreeMode = flag;
62         updateIsolatedTreeMode();
63     }
64 }
65
66 void AccessibilityController::updateIsolatedTreeMode()
67 {
68     // Override to set identifier to VoiceOver so that requests are handled in isolated mode.
69     _AXSetClientIdentificationOverride(m_accessibilityIsolatedTreeMode ? kAXClientTypeVoiceOver : kAXClientTypeNoActiveRequestFound);
70     m_useMockAXThread = WKAccessibilityCanUseSecondaryAXThread(InjectedBundle::singleton().page()->page());
71 }
72 #endif
73
74 void AccessibilityController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
75 {
76     setProperty(context, windowObject, "accessibilityController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
77 }
78
79 JSClassRef AccessibilityController::wrapperClass()
80 {
81     return JSAccessibilityController::accessibilityControllerClass();
82 }
83
84 void AccessibilityController::enableEnhancedAccessibility(bool enable)
85 {
86     WKAccessibilityEnableEnhancedAccessibility(enable);
87 }
88
89 bool AccessibilityController::enhancedAccessibilityEnabled()
90 {
91     return WKAccessibilityEnhancedAccessibilityEnabled();
92 }
93
94 #if PLATFORM(COCOA)
95 Ref<AccessibilityUIElement> AccessibilityController::rootElement()
96 {
97     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
98     PlatformUIElement root = static_cast<PlatformUIElement>(WKAccessibilityRootObject(page));
99
100     return AccessibilityUIElement::create(root);
101 }
102
103 Ref<AccessibilityUIElement> AccessibilityController::focusedElement()
104 {
105     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
106     PlatformUIElement focusedElement = static_cast<PlatformUIElement>(WKAccessibilityFocusedObject(page));
107     return AccessibilityUIElement::create(focusedElement);
108 }
109
110 void AccessibilityController::executeOnAXThreadIfPossible(Function<void()>&& function)
111 {
112 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
113     if (m_useMockAXThread) {
114         AXThread::dispatch([&function, this] {
115             function();
116             m_semaphore.signal();
117         });
118
119         // Spin the main loop so that any required DOM processing can be
120         // executed in the main thread. That is the case of most parameterized
121         // attributes, where the attribute value has to be calculated
122         // back in the main thread.
123         CFRunLoopRunInMode(kCFRunLoopDefaultMode, .25, false);
124         m_semaphore.wait();
125     } else
126 #endif
127         function();
128 }
129 #endif
130
131 RefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y)
132 {
133     auto uiElement = rootElement();
134     return uiElement->elementAtPoint(x, y);
135 }
136
137 #if PLATFORM(COCOA)
138
139 // AXThread implementation
140
141 AXThread::AXThread()
142 {
143 }
144
145 bool AXThread::isCurrentThread()
146 {
147     return AXThread::singleton().m_thread == &Thread::current();
148 }
149
150 void AXThread::dispatch(Function<void()>&& function)
151 {
152     auto& axThread = AXThread::singleton();
153     axThread.createThreadIfNeeded();
154
155     {
156         auto locker = holdLock(axThread.m_functionsMutex);
157         axThread.m_functions.append(WTFMove(function));
158     }
159
160     axThread.wakeUpRunLoop();
161 }
162
163 void AXThread::dispatchBarrier(Function<void()>&& function)
164 {
165     dispatch([function = WTFMove(function)]() mutable {
166         callOnMainThread(WTFMove(function));
167     });
168 }
169
170 AXThread& AXThread::singleton()
171 {
172     static NeverDestroyed<AXThread> axThread;
173     return axThread;
174 }
175
176 void AXThread::createThreadIfNeeded()
177 {
178     // Wait for the thread to initialize the run loop.
179     std::unique_lock<Lock> lock(m_initializeRunLoopMutex);
180
181     if (!m_thread) {
182         m_thread = Thread::create("WKTR: AccessibilityController", [this] {
183             WTF::Thread::setCurrentThreadIsUserInteractive();
184             initializeRunLoop();
185         });
186     }
187
188     m_initializeRunLoopConditionVariable.wait(lock, [this] {
189 #if PLATFORM(COCOA)
190         return m_threadRunLoop;
191 #else
192         return m_runLoop;
193 #endif
194     });
195 }
196
197 void AXThread::dispatchFunctionsFromAXThread()
198 {
199     ASSERT(isCurrentThread());
200
201     Vector<Function<void()>> functions;
202
203     {
204         auto locker = holdLock(m_functionsMutex);
205         functions = WTFMove(m_functions);
206     }
207
208     for (auto& function : functions)
209         function();
210 }
211
212 #if !PLATFORM(MAC)
213 NO_RETURN_DUE_TO_ASSERT void AXThread::initializeRunLoop()
214 {
215     ASSERT_NOT_REACHED();
216 }
217
218 void AXThread::wakeUpRunLoop()
219 {
220 }
221
222 void AXThread::threadRunLoopSourceCallback(void*)
223 {
224 }
225
226 void AXThread::threadRunLoopSourceCallback()
227 {
228 }
229 #endif // !PLATFORM(MAC)
230
231 #endif // PLATFORM(COCOA)
232
233 } // namespace WTR
234 #endif // ENABLE(ACCESSIBILITY)
235