0e7d54205c83567aa65e360d47ac0533a3150e6f
[WebKit-https.git] / Source / WebCore / accessibility / isolatedtree / AXIsolatedTree.cpp
1 /*
2  * Copyright (C) 2019 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 #include "config.h"
27
28 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
29 #include "AXIsolatedTree.h"
30
31 #include "AXIsolatedTreeNode.h"
32 #include "Page.h"
33 #include <wtf/NeverDestroyed.h>
34
35 namespace WebCore {
36
37 static Lock s_cacheLock;
38
39 static unsigned newTreeID()
40 {
41     static unsigned s_currentTreeID = 0;
42     return ++s_currentTreeID;
43 }
44
45 HashMap<uint64_t, Ref<AXIsolatedTree>>& AXIsolatedTree::treePageCache()
46 {
47     static NeverDestroyed<HashMap<uint64_t, Ref<AXIsolatedTree>>> map;
48     return map;
49 }
50
51 HashMap<AXIsolatedTreeID, Ref<AXIsolatedTree>>& AXIsolatedTree::treeIDCache()
52 {
53     static NeverDestroyed<HashMap<AXIsolatedTreeID, Ref<AXIsolatedTree>>> map;
54     return map;
55 }
56
57 AXIsolatedTree::AXIsolatedTree()
58     : m_treeID(newTreeID())
59 {
60 }
61
62 AXIsolatedTree::~AXIsolatedTree() = default;
63
64 Ref<AXIsolatedTree> AXIsolatedTree::create()
65 {
66     ASSERT(isMainThread());
67     return adoptRef(*new AXIsolatedTree());
68 }
69
70 Ref<AXIsolatedTree> AXIsolatedTree::initializePageTreeForID(PageIdentifier pageID, AXObjectCache& cache)
71 {
72     RELEASE_ASSERT(isMainThread());
73     auto tree = cache->generateIsolatedAccessibilityTree();
74     tree->setInitialRequestI\ 1nProgress(true);
75     tree->applyPendingChanges();
76     tree->setInitialRequestInProgress(false);
77     return tree;
78 }
79
80 RefPtr<AXIsolatedTreeNode> AXIsolatedTree::nodeInTreeForID(AXIsolatedTreeID treeID, AXID axID)
81 {
82     return treeForID(treeID)->nodeForID(axID);
83 }
84
85 RefPtr<AXIsolatedTree> AXIsolatedTree::treeForID(AXIsolatedTreeID treeID)
86 {
87     return treeIDCache().get(treeID);
88 }
89
90 Ref<AXIsolatedTree> AXIsolatedTree::createTreeForPageID(PageIdentifier pageID)
91 {
92     LockHolder locker(s_cacheLock);
93
94     auto newTree = AXIsolatedTree::create();
95     treePageCache().set(pageID, newTree.copyRef());
96     treeIDCache().set(newTree->treeIdentifier(), newTree.copyRef());
97     return newTree;
98 }
99
100 RefPtr<AXIsolatedTree> AXIsolatedTree::treeForPageID(PageIdentifier pageID)
101 {
102     LockHolder locker(s_cacheLock);
103
104     if (auto tree = treePageCache().get(pageID))
105         return makeRefPtr(tree);
106
107     return nullptr;
108 }
109
110 RefPtr<AXIsolatedTreeNode> AXIsolatedTree::nodeForID(AXID axID) const
111 {
112     RELEASE_ASSERT(!isMainThread() || initialRequest);
113     if (!axID)
114         return nullptr;
115     return m_readerThreadNodeMap.get(axID);
116 }
117
118 RefPtr<AXIsolatedTreeNode> AXIsolatedTree::focusedUIElement()
119 {
120     return nodeForID(m_focusedNodeID);
121 }
122     
123 RefPtr<AXIsolatedTreeNode> AXIsolatedTree::rootNode()
124 {
125     return nodeForID(m_rootNodeID);
126 }
127
128 void AXIsolatedTree::setRootNodeID(AXID axID)
129 {
130     LockHolder locker { m_changeLogLock };
131     m_pendingRootNodeID = axID;
132 }
133     
134 void AXIsolatedTree::setFocusedNodeID(AXID axID)
135 {
136     LockHolder locker { m_changeLogLock };
137     m_pendingFocusedNodeID = axID;
138 }
139     
140 void AXIsolatedTree::removeNode(AXID axID)
141 {
142     LockHolder locker { m_changeLogLock };
143     m_pendingRemovals.append(axID);
144 }
145
146 void AXIsolatedTree::appendNodeChanges(Vector<Ref<AXIsolatedTreeNode>>& log)
147 {
148     LockHolder locker { m_changeLogLock };
149     for (auto& node : log)
150         m_pendingAppends.append(node.copyRef());
151 }
152
153 void AXIsolatedTree::setInitialRequestInProgress(bool initialRequestInProgress)
154 {
155     m_initialRequestInProgress = initialRequestInProgress;
156 }
157
158 void AXIsolatedTree::applyPendingChanges()
159 {
160     RELEASE_ASSERT(!isMainThread() || initialRequest);
161     LockHolder locker { m_changeLogLock };
162     Vector<Ref<AXIsolatedTreeNode>> appendCopy;
163     std::swap(appendCopy, m_pendingAppends);
164     Vector<AXID> removeCopy({ WTFMove(m_pendingRemovals) });
165     locker.unlockEarly();
166
167     // We don't clear the pending IDs beacause if the next round of updates does not modify them, then they stay the same
168     // value without extra bookkeeping.
169     m_rootNodeID = m_pendingRootNodeID;
170     m_focusedNodeID = m_pendingFocusedNodeID;
171     
172     for (auto& item : appendCopy) {
173         item->setTreeIdentifier(m_treeID);
174         m_readerThreadNodeMap.add(item->identifier(), WTFMove(item));
175     }
176
177     for (auto item : removeCopy)
178         m_readerThreadNodeMap.remove(item);
179 }
180     
181 } // namespace WebCore
182
183 #endif // ENABLE(ACCESSIBILITY_ISOLATED_TREE)