4273db5eb2b6fa1d777b8c287261e60bae565c34
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / mac / WKAccessibilityWebPageObjectBase.mm
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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKAccessibilityWebPageObjectBase.h"
28
29 #import "WebFrame.h"
30 #import "WebPage.h"
31 #import "WKArray.h"
32 #import "WKNumber.h"
33 #import "WKRetainPtr.h"
34 #import "WKSharedAPICast.h"
35 #import "WKString.h"
36 #import "WKStringCF.h"
37 #import <WebCore/AXIsolatedTree.h>
38 #import <WebCore/AXObjectCache.h>
39 #import <WebCore/Document.h>
40 #import <WebCore/Frame.h>
41 #import <WebCore/FrameView.h>
42 #import <WebCore/Page.h>
43 #import <WebCore/ScrollView.h>
44 #import <WebCore/Scrollbar.h>
45 #import <wtf/ObjCRuntimeExtras.h>
46
47 @implementation WKAccessibilityWebPageObjectBase
48
49 - (WebCore::AXObjectCache*)axObjectCache
50 {
51     if (!m_page)
52         return nullptr;
53
54     auto page = m_page->corePage();
55     if (!page)
56         return nullptr;
57
58     auto& core = page->mainFrame();
59     if (!core.document())
60         return nullptr;
61
62     return core.document()->axObjectCache();
63 }
64
65 - (id)accessibilityPluginObject
66 {
67     auto retrieveBlock = [&self]() -> id {
68         id axPlugin = nil;
69         auto dispatchBlock = [&axPlugin, &self] {
70             if (self->m_page)
71                 axPlugin = self->m_page->accessibilityObjectForMainFramePlugin();
72         };
73
74         if (isMainThread())
75             dispatchBlock();
76         else {
77             callOnMainThreadAndWait([&dispatchBlock] {
78                 dispatchBlock();
79             });
80         }
81         return axPlugin;
82     };
83     
84     return retrieveBlock();
85 }
86
87 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
88 - (BOOL)clientSupportsIsolatedTree
89 {
90     AXClientType type = _AXGetClientForCurrentRequestUntrusted();
91     // FIXME: Remove unknown client before enabling ACCESSIBILITY_ISOLATED_TREE.
92     return type == kAXClientTypeVoiceOver || type == kAXClientTypeUnknown;
93 }
94
95 - (id)isolatedTreeRootObject
96 {
97     if (isMainThread()) {
98         if (auto cache = [self axObjectCache]) {
99             auto tree = AXIsolatedTree::initializeTreeForPageId(m_pageID, *cache);
100
101             // Now that we have created our tree, initialize the secondary thread,
102             // so future requests come in on the other thread.
103             _AXUIElementUseSecondaryAXThread(true);
104             if (auto rootNode = tree->rootNode())
105                 return rootNode->wrapper();
106         }
107     } else {
108         auto tree = AXIsolatedTree::treeForPageID(m_pageID);
109         tree->applyPendingChanges();
110         if (auto rootNode = tree->rootNode())
111             return rootNode->wrapper();
112     }
113
114     return nil;
115 }
116 #endif
117
118 - (id)accessibilityRootObjectWrapper
119 {
120     if (!WebCore::AXObjectCache::accessibilityEnabled())
121         WebCore::AXObjectCache::enableAccessibility();
122
123     if (m_hasMainFramePlugin)
124         return self.accessibilityPluginObject;
125
126 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
127     // If VoiceOver is on, ensure subsequent requests are now handled on the secondary AX thread.
128     bool clientSupportsIsolatedTree = [self clientSupportsIsolatedTree];
129     if (clientSupportsIsolatedTree)
130         return [self isolatedTreeRootObject];
131 #endif
132
133     if (auto cache = [self axObjectCache]) {
134         if (WebCore::AccessibilityObject* root = cache->rootObject())
135             return root->wrapper();
136     }
137
138     return nil;
139 }
140
141 - (void)setWebPage:(WebKit::WebPage*)page
142 {
143     m_page = page;
144
145     if (page) {
146         m_pageID = page->identifier();
147
148         auto* frame = page->mainFrame();
149         m_hasMainFramePlugin = frame && frame->document() ? frame->document()->isPluginDocument() : false;
150     } else {
151         m_pageID = { };
152         m_hasMainFramePlugin = false;
153     }
154 }
155
156 - (void)setHasMainFramePlugin:(bool)hasPlugin
157 {
158     m_hasMainFramePlugin = hasPlugin;
159 }
160
161 - (void)setRemoteParent:(id)parent
162 {
163     if (parent != m_parent) {
164         [m_parent release];
165         m_parent = [parent retain];
166     }
167 }
168
169 - (id)accessibilityFocusedUIElement
170 {
171     return [[self accessibilityRootObjectWrapper] accessibilityFocusedUIElement];
172 }
173
174
175 @end