81a4c1007186743b2fb4665e3edcd9858f826a79
[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     m_accessibilityIsolatedTreeMode = flag;
61     updateIsolatedTreeMode();
62 }
63
64 void AccessibilityController::updateIsolatedTreeMode()
65 {
66     // Override to set identifier to VoiceOver so that requests are handled in isolated mode.
67     _AXSetClientIdentificationOverride(m_accessibilityIsolatedTreeMode ? kAXClientTypeVoiceOver : kAXClientTypeNoActiveRequestFound);
68     m_useMockAXThread = WKAccessibilityCanUseSecondaryAXThread(InjectedBundle::singleton().page()->page());
69 }
70 #endif
71
72 void AccessibilityController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
73 {
74     setProperty(context, windowObject, "accessibilityController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
75 }
76
77 JSClassRef AccessibilityController::wrapperClass()
78 {
79     return JSAccessibilityController::accessibilityControllerClass();
80 }
81
82 void AccessibilityController::enableEnhancedAccessibility(bool enable)
83 {
84     WKAccessibilityEnableEnhancedAccessibility(enable);
85 }
86
87 bool AccessibilityController::enhancedAccessibilityEnabled()
88 {
89     return WKAccessibilityEnhancedAccessibilityEnabled();
90 }
91
92 #if PLATFORM(COCOA)
93 Ref<AccessibilityUIElement> AccessibilityController::rootElement()
94 {
95     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
96     PlatformUIElement root = static_cast<PlatformUIElement>(WKAccessibilityRootObject(page));
97
98     return AccessibilityUIElement::create(root);
99 }
100
101 Ref<AccessibilityUIElement> AccessibilityController::focusedElement()
102 {
103     WKBundlePageRef page = InjectedBundle::singleton().page()->page();
104     PlatformUIElement focusedElement = static_cast<PlatformUIElement>(WKAccessibilityFocusedObject(page));
105     return AccessibilityUIElement::create(focusedElement);
106 }
107
108 void AccessibilityController::executeOnAXThreadIfPossible(Function<void()>&& function)
109 {
110 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
111     if (m_useMockAXThread) {
112         AXThread::dispatch([&function, this] {
113             function();
114             m_semaphore.signal();
115         });
116
117         // Spin the main loop so that any required DOM processing can be
118         // executed in the main thread. That is the case of most parameterized
119         // attributes, where the attribute value has to be calculated
120         // back in the main thread.
121         CFRunLoopRunInMode(kCFRunLoopDefaultMode, .25, false);
122         m_semaphore.wait();
123     } else
124 #endif
125         function();
126 }
127 #endif
128
129 RefPtr<AccessibilityUIElement> AccessibilityController::elementAtPoint(int x, int y)
130 {
131     auto uiElement = rootElement();
132     return uiElement->elementAtPoint(x, y);
133 }
134
135 #if PLATFORM(COCOA)
136
137 // AXThread implementation
138
139 AXThread::AXThread()
140 {
141 }
142
143 bool AXThread::isCurrentThread()
144 {
145     return AXThread::singleton().m_thread == &Thread::current();
146 }
147
148 void AXThread::dispatch(Function<void()>&& function)
149 {
150     auto& axThread = AXThread::singleton();
151     axThread.createThreadIfNeeded();
152
153     {
154         auto locker = holdLock(axThread.m_functionsMutex);
155         axThread.m_functions.append(WTFMove(function));
156     }
157
158     axThread.wakeUpRunLoop();
159 }
160
161 void AXThread::dispatchBarrier(Function<void()>&& function)
162 {
163     dispatch([function = WTFMove(function)]() mutable {
164         callOnMainThread(WTFMove(function));
165     });
166 }
167
168 AXThread& AXThread::singleton()
169 {
170     static NeverDestroyed<AXThread> axThread;
171     return axThread;
172 }
173
174 void AXThread::createThreadIfNeeded()
175 {
176     // Wait for the thread to initialize the run loop.
177     std::unique_lock<Lock> lock(m_initializeRunLoopMutex);
178
179     if (!m_thread) {
180         m_thread = Thread::create("WKTR: AccessibilityController", [this] {
181             WTF::Thread::setCurrentThreadIsUserInteractive();
182             initializeRunLoop();
183         });
184     }
185
186     m_initializeRunLoopConditionVariable.wait(lock, [this] {
187 #if PLATFORM(COCOA)
188         return m_threadRunLoop;
189 #else
190         return m_runLoop;
191 #endif
192     });
193 }
194
195 void AXThread::dispatchFunctionsFromAXThread()
196 {
197     ASSERT(isCurrentThread());
198
199     Vector<Function<void()>> functions;
200
201     {
202         auto locker = holdLock(m_functionsMutex);
203         functions = WTFMove(m_functions);
204     }
205
206     for (auto& function : functions)
207         function();
208 }
209
210 #if !PLATFORM(MAC)
211 NO_RETURN_DUE_TO_ASSERT void AXThread::initializeRunLoop()
212 {
213     ASSERT_NOT_REACHED();
214 }
215
216 void AXThread::wakeUpRunLoop()
217 {
218 }
219
220 void AXThread::threadRunLoopSourceCallback(void*)
221 {
222 }
223
224 void AXThread::threadRunLoopSourceCallback()
225 {
226 }
227 #endif // !PLATFORM(MAC)
228
229 #endif // PLATFORM(COCOA)
230
231 } // namespace WTR
232 #endif // ENABLE(ACCESSIBILITY)
233