1 | /* |
2 | * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2015 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 | #pragma once |
27 | |
28 | #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) |
29 | #include "AXIsolatedTree.h" |
30 | #endif |
31 | #include "AXTextStateChangeIntent.h" |
32 | #include "AccessibilityObject.h" |
33 | #include "Range.h" |
34 | #include "Timer.h" |
35 | #include "VisibleUnits.h" |
36 | #include <limits.h> |
37 | #include <wtf/Forward.h> |
38 | #include <wtf/HashMap.h> |
39 | #include <wtf/HashSet.h> |
40 | #include <wtf/ListHashSet.h> |
41 | #include <wtf/RefPtr.h> |
42 | |
43 | #if PLATFORM(GTK) |
44 | #include <wtf/glib/GRefPtr.h> |
45 | #endif |
46 | |
47 | namespace WebCore { |
48 | |
49 | #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) |
50 | class AXIsolatedTreeNode; |
51 | #endif |
52 | class Document; |
53 | class HTMLAreaElement; |
54 | class HTMLTextFormControlElement; |
55 | class Node; |
56 | class Page; |
57 | class RenderBlock; |
58 | class RenderObject; |
59 | class RenderText; |
60 | class ScrollView; |
61 | class VisiblePosition; |
62 | class Widget; |
63 | |
64 | struct TextMarkerData { |
65 | AXID axID { 0 }; |
66 | Node* node { nullptr }; |
67 | int offset { 0 }; |
68 | int characterStartIndex { 0 }; |
69 | int characterOffset { 0 }; |
70 | bool ignored { false }; |
71 | EAffinity affinity { DOWNSTREAM }; |
72 | }; |
73 | |
74 | struct CharacterOffset { |
75 | Node* node; |
76 | int startIndex; |
77 | int offset; |
78 | int remainingOffset; |
79 | |
80 | CharacterOffset(Node* n = nullptr, int startIndex = 0, int offset = 0, int remaining = 0) |
81 | : node(n) |
82 | , startIndex(startIndex) |
83 | , offset(offset) |
84 | , remainingOffset(remaining) |
85 | { } |
86 | |
87 | int remaining() const { return remainingOffset; } |
88 | bool isNull() const { return !node; } |
89 | bool isEqual(const CharacterOffset& other) const |
90 | { |
91 | if (isNull() || other.isNull()) |
92 | return false; |
93 | return node == other.node && startIndex == other.startIndex && offset == other.offset; |
94 | } |
95 | }; |
96 | |
97 | class AXComputedObjectAttributeCache { |
98 | WTF_MAKE_FAST_ALLOCATED; |
99 | public: |
100 | AccessibilityObjectInclusion getIgnored(AXID) const; |
101 | void setIgnored(AXID, AccessibilityObjectInclusion); |
102 | |
103 | private: |
104 | struct CachedAXObjectAttributes { |
105 | CachedAXObjectAttributes() |
106 | : ignored(AccessibilityObjectInclusion::DefaultBehavior) |
107 | { } |
108 | |
109 | AccessibilityObjectInclusion ignored; |
110 | }; |
111 | |
112 | HashMap<AXID, CachedAXObjectAttributes> m_idMapping; |
113 | }; |
114 | |
115 | struct VisiblePositionIndex { |
116 | int value = -1; |
117 | RefPtr<ContainerNode> scope; |
118 | }; |
119 | |
120 | struct VisiblePositionIndexRange { |
121 | VisiblePositionIndex startIndex; |
122 | VisiblePositionIndex endIndex; |
123 | bool isNull() const { return startIndex.value == -1 || endIndex.value == -1; } |
124 | }; |
125 | |
126 | class AccessibilityReplacedText { |
127 | public: |
128 | AccessibilityReplacedText() = default; |
129 | AccessibilityReplacedText(const VisibleSelection&); |
130 | void postTextStateChangeNotification(AXObjectCache*, AXTextEditType, const String&, const VisibleSelection&); |
131 | const VisiblePositionIndexRange& replacedRange() { return m_replacedRange; } |
132 | protected: |
133 | String m_replacedText; |
134 | VisiblePositionIndexRange m_replacedRange; |
135 | }; |
136 | |
137 | #if !PLATFORM(COCOA) |
138 | enum AXTextChange { AXTextInserted, AXTextDeleted, AXTextAttributesChanged }; |
139 | #endif |
140 | |
141 | enum PostTarget { TargetElement, TargetObservableParent }; |
142 | |
143 | enum PostType { PostSynchronously, PostAsynchronously }; |
144 | |
145 | class AXObjectCache { |
146 | WTF_MAKE_NONCOPYABLE(AXObjectCache); WTF_MAKE_FAST_ALLOCATED; |
147 | public: |
148 | explicit AXObjectCache(Document&); |
149 | ~AXObjectCache(); |
150 | |
151 | WEBCORE_EXPORT static AccessibilityObject* focusedUIElementForPage(const Page*); |
152 | |
153 | // Returns the root object for the entire document. |
154 | WEBCORE_EXPORT AccessibilityObject* rootObject(); |
155 | // Returns the root object for a specific frame. |
156 | WEBCORE_EXPORT AccessibilityObject* rootObjectForFrame(Frame*); |
157 | |
158 | // For AX objects with elements that back them. |
159 | AccessibilityObject* getOrCreate(RenderObject*); |
160 | AccessibilityObject* getOrCreate(Widget*); |
161 | WEBCORE_EXPORT AccessibilityObject* getOrCreate(Node*); |
162 | |
163 | // used for objects without backing elements |
164 | AccessibilityObject* getOrCreate(AccessibilityRole); |
165 | |
166 | // will only return the AccessibilityObject if it already exists |
167 | AccessibilityObject* get(RenderObject*); |
168 | AccessibilityObject* get(Widget*); |
169 | AccessibilityObject* get(Node*); |
170 | |
171 | void remove(RenderObject*); |
172 | void remove(Node&); |
173 | void remove(Widget*); |
174 | void remove(AXID); |
175 | |
176 | void detachWrapper(AccessibilityObject*, AccessibilityDetachmentType); |
177 | void attachWrapper(AccessibilityObject*); |
178 | void childrenChanged(Node*, Node* newChild = nullptr); |
179 | void childrenChanged(RenderObject*, RenderObject* newChild = nullptr); |
180 | void childrenChanged(AccessibilityObject*); |
181 | void checkedStateChanged(Node*); |
182 | // Called when a node has just been attached, so we can make sure we have the right subclass of AccessibilityObject. |
183 | void updateCacheAfterNodeIsAttached(Node*); |
184 | |
185 | void deferFocusedUIElementChangeIfNeeded(Node* oldFocusedNode, Node* newFocusedNode); |
186 | void handleScrolledToAnchor(const Node* anchorNode); |
187 | void handleScrollbarUpdate(ScrollView*); |
188 | |
189 | Node* modalNode(); |
190 | |
191 | void deferAttributeChangeIfNeeded(const QualifiedName&, Element*); |
192 | void recomputeIsIgnored(RenderObject* renderer); |
193 | |
194 | #if ENABLE(ACCESSIBILITY_ISOLATED_TREE) |
195 | WEBCORE_EXPORT Ref<AXIsolatedTree> generateIsolatedAccessibilityTree(); |
196 | |
197 | void associateIsolatedTreeNode(AccessibilityObject&, AXIsolatedTreeNode&, AXIsolatedTreeID); |
198 | Ref<AXIsolatedTreeNode> createIsolatedAccessibilityTreeHierarchy(AccessibilityObject&, AXID, AXIsolatedTree&, Vector<Ref<AXIsolatedTreeNode>>&); |
199 | #endif |
200 | |
201 | #if HAVE(ACCESSIBILITY) |
202 | WEBCORE_EXPORT static void enableAccessibility(); |
203 | WEBCORE_EXPORT static void disableAccessibility(); |
204 | |
205 | // Enhanced user interface accessibility can be toggled by the assistive technology. |
206 | WEBCORE_EXPORT static void setEnhancedUserInterfaceAccessibility(bool flag); |
207 | |
208 | // Note: these may be called from a non-main thread concurrently as other readers. |
209 | static bool accessibilityEnabled() { return gAccessibilityEnabled; } |
210 | static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } |
211 | #else |
212 | static void enableAccessibility() { } |
213 | static void disableAccessibility() { } |
214 | static void setEnhancedUserInterfaceAccessibility(bool) { } |
215 | static bool accessibilityEnabled() { return false; } |
216 | static bool accessibilityEnhancedUserInterfaceEnabled() { return false; } |
217 | #endif |
218 | |
219 | const Element* rootAXEditableElement(const Node*); |
220 | bool nodeIsTextControl(const Node*); |
221 | |
222 | AXID platformGenerateAXID() const; |
223 | AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id); } |
224 | |
225 | // Text marker utilities. |
226 | Optional<TextMarkerData> textMarkerDataForVisiblePosition(const VisiblePosition&); |
227 | Optional<TextMarkerData> textMarkerDataForFirstPositionInTextControl(HTMLTextFormControlElement&); |
228 | void textMarkerDataForCharacterOffset(TextMarkerData&, const CharacterOffset&); |
229 | void textMarkerDataForNextCharacterOffset(TextMarkerData&, const CharacterOffset&); |
230 | void textMarkerDataForPreviousCharacterOffset(TextMarkerData&, const CharacterOffset&); |
231 | VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); |
232 | CharacterOffset characterOffsetForTextMarkerData(TextMarkerData&); |
233 | // Use ignoreNextNodeStart/ignorePreviousNodeEnd to determine the behavior when we are at node boundary. |
234 | CharacterOffset nextCharacterOffset(const CharacterOffset&, bool ignoreNextNodeStart = true); |
235 | CharacterOffset previousCharacterOffset(const CharacterOffset&, bool ignorePreviousNodeEnd = true); |
236 | void startOrEndTextMarkerDataForRange(TextMarkerData&, RefPtr<Range>, bool); |
237 | CharacterOffset startOrEndCharacterOffsetForRange(RefPtr<Range>, bool, bool enterTextControls = false); |
238 | AccessibilityObject* accessibilityObjectForTextMarkerData(TextMarkerData&); |
239 | RefPtr<Range> rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&); |
240 | static RefPtr<Range> rangeForNodeContents(Node*); |
241 | static int lengthForRange(Range*); |
242 | |
243 | // Word boundary |
244 | CharacterOffset nextWordEndCharacterOffset(const CharacterOffset&); |
245 | CharacterOffset previousWordStartCharacterOffset(const CharacterOffset&); |
246 | RefPtr<Range> leftWordRange(const CharacterOffset&); |
247 | RefPtr<Range> rightWordRange(const CharacterOffset&); |
248 | |
249 | // Paragraph |
250 | RefPtr<Range> paragraphForCharacterOffset(const CharacterOffset&); |
251 | CharacterOffset nextParagraphEndCharacterOffset(const CharacterOffset&); |
252 | CharacterOffset previousParagraphStartCharacterOffset(const CharacterOffset&); |
253 | |
254 | // Sentence |
255 | RefPtr<Range> sentenceForCharacterOffset(const CharacterOffset&); |
256 | CharacterOffset nextSentenceEndCharacterOffset(const CharacterOffset&); |
257 | CharacterOffset previousSentenceStartCharacterOffset(const CharacterOffset&); |
258 | |
259 | // Bounds |
260 | CharacterOffset characterOffsetForPoint(const IntPoint&, AccessibilityObject*); |
261 | IntRect absoluteCaretBoundsForCharacterOffset(const CharacterOffset&); |
262 | CharacterOffset characterOffsetForBounds(const IntRect&, bool); |
263 | |
264 | // Lines |
265 | CharacterOffset endCharacterOffsetOfLine(const CharacterOffset&); |
266 | CharacterOffset startCharacterOffsetOfLine(const CharacterOffset&); |
267 | |
268 | // Index |
269 | CharacterOffset characterOffsetForIndex(int, const AccessibilityObject*); |
270 | int indexForCharacterOffset(const CharacterOffset&, AccessibilityObject*); |
271 | |
272 | enum AXNotification { |
273 | AXActiveDescendantChanged, |
274 | AXAutocorrectionOccured, |
275 | AXCheckedStateChanged, |
276 | AXChildrenChanged, |
277 | AXCurrentChanged, |
278 | AXDisabledStateChanged, |
279 | AXFocusedUIElementChanged, |
280 | AXLayoutComplete, |
281 | AXLoadComplete, |
282 | AXNewDocumentLoadComplete, |
283 | AXSelectedChildrenChanged, |
284 | AXSelectedTextChanged, |
285 | AXValueChanged, |
286 | AXScrolledToAnchor, |
287 | AXLiveRegionCreated, |
288 | AXLiveRegionChanged, |
289 | , |
290 | , |
291 | , |
292 | , |
293 | AXRowCountChanged, |
294 | AXRowCollapsed, |
295 | AXRowExpanded, |
296 | AXExpandedChanged, |
297 | AXInvalidStatusChanged, |
298 | AXPressDidSucceed, |
299 | AXPressDidFail, |
300 | AXPressedStateChanged, |
301 | AXReadOnlyStatusChanged, |
302 | AXRequiredStatusChanged, |
303 | AXTextChanged, |
304 | AXAriaAttributeChanged, |
305 | AXElementBusyChanged |
306 | }; |
307 | |
308 | void postNotification(RenderObject*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); |
309 | void postNotification(Node*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); |
310 | void postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget = TargetElement, PostType = PostAsynchronously); |
311 | |
312 | #ifndef NDEBUG |
313 | void showIntent(const AXTextStateChangeIntent&); |
314 | #endif |
315 | |
316 | void setTextSelectionIntent(const AXTextStateChangeIntent&); |
317 | void setIsSynchronizingSelection(bool); |
318 | |
319 | void postTextStateChangeNotification(Node*, AXTextEditType, const String&, const VisiblePosition&); |
320 | void postTextReplacementNotification(Node*, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition&); |
321 | void postTextReplacementNotificationForTextControl(HTMLTextFormControlElement&, const String& deletedText, const String& insertedText); |
322 | void postTextStateChangeNotification(Node*, const AXTextStateChangeIntent&, const VisibleSelection&); |
323 | void postTextStateChangeNotification(const Position&, const AXTextStateChangeIntent&, const VisibleSelection&); |
324 | void postLiveRegionChangeNotification(AccessibilityObject*); |
325 | void focusModalNode(); |
326 | |
327 | enum AXLoadingEvent { |
328 | AXLoadingStarted, |
329 | AXLoadingReloaded, |
330 | AXLoadingFailed, |
331 | AXLoadingFinished |
332 | }; |
333 | |
334 | void frameLoadingEventNotification(Frame*, AXLoadingEvent); |
335 | |
336 | void prepareForDocumentDestruction(const Document&); |
337 | |
338 | void startCachingComputedObjectAttributesUntilTreeMutates(); |
339 | void stopCachingComputedObjectAttributes(); |
340 | |
341 | AXComputedObjectAttributeCache* computedObjectAttributeCache() { return m_computedObjectAttributeCache.get(); } |
342 | |
343 | Document& document() const { return m_document; } |
344 | |
345 | #if PLATFORM(MAC) |
346 | static void setShouldRepostNotificationsForTests(bool value); |
347 | #endif |
348 | void deferRecomputeIsIgnoredIfNeeded(Element*); |
349 | void deferRecomputeIsIgnored(Element*); |
350 | void deferTextChangedIfNeeded(Node*); |
351 | void deferSelectedChildrenChangedIfNeeded(Element&); |
352 | void performDeferredCacheUpdate(); |
353 | void deferTextReplacementNotificationForTextControl(HTMLTextFormControlElement&, const String& previousValue); |
354 | |
355 | RefPtr<Range> rangeMatchesTextNearRange(RefPtr<Range>, const String&); |
356 | |
357 | |
358 | protected: |
359 | void postPlatformNotification(AccessibilityObject*, AXNotification); |
360 | void platformHandleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode); |
361 | |
362 | void platformPerformDeferredCacheUpdate(); |
363 | |
364 | #if PLATFORM(COCOA) |
365 | void postTextStateChangePlatformNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&); |
366 | void postTextStateChangePlatformNotification(AccessibilityObject*, AXTextEditType, const String&, const VisiblePosition&); |
367 | void postTextReplacementPlatformNotificationForTextControl(AccessibilityObject*, const String& deletedText, const String& insertedText, HTMLTextFormControlElement&); |
368 | void postTextReplacementPlatformNotification(AccessibilityObject*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&); |
369 | #else |
370 | static AXTextChange textChangeForEditType(AXTextEditType); |
371 | void nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&); |
372 | #endif |
373 | |
374 | void frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent); |
375 | void textChanged(AccessibilityObject*); |
376 | void labelChanged(Element*); |
377 | |
378 | // This is a weak reference cache for knowing if Nodes used by TextMarkers are valid. |
379 | void setNodeInUse(Node* n) { m_textMarkerNodes.add(n); } |
380 | void removeNodeForUse(Node& n) { m_textMarkerNodes.remove(&n); } |
381 | bool isNodeInUse(Node* n) { return m_textMarkerNodes.contains(n); } |
382 | |
383 | // CharacterOffset functions. |
384 | enum TraverseOption { TraverseOptionDefault = 1 << 0, TraverseOptionToNodeEnd = 1 << 1, TraverseOptionIncludeStart = 1 << 2, TraverseOptionValidateOffset = 1 << 3, TraverseOptionDoNotEnterTextControls = 1 << 4 }; |
385 | Node* nextNode(Node*) const; |
386 | Node* previousNode(Node*) const; |
387 | CharacterOffset traverseToOffsetInRange(RefPtr<Range>, int, TraverseOption = TraverseOptionDefault, bool stayWithinRange = false); |
388 | VisiblePosition visiblePositionFromCharacterOffset(const CharacterOffset&); |
389 | CharacterOffset characterOffsetFromVisiblePosition(const VisiblePosition&); |
390 | void setTextMarkerDataWithCharacterOffset(TextMarkerData&, const CharacterOffset&); |
391 | UChar32 characterAfter(const CharacterOffset&); |
392 | UChar32 characterBefore(const CharacterOffset&); |
393 | CharacterOffset characterOffsetForNodeAndOffset(Node&, int, TraverseOption = TraverseOptionDefault); |
394 | |
395 | enum class NeedsContextAtParagraphStart { Yes, No }; |
396 | CharacterOffset previousBoundary(const CharacterOffset&, BoundarySearchFunction, NeedsContextAtParagraphStart = NeedsContextAtParagraphStart::No); |
397 | CharacterOffset nextBoundary(const CharacterOffset&, BoundarySearchFunction); |
398 | CharacterOffset startCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary); |
399 | CharacterOffset endCharacterOffsetOfWord(const CharacterOffset&, EWordSide = RightWordIfOnBoundary); |
400 | CharacterOffset startCharacterOffsetOfParagraph(const CharacterOffset&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary); |
401 | CharacterOffset endCharacterOffsetOfParagraph(const CharacterOffset&, EditingBoundaryCrossingRule = CannotCrossEditingBoundary); |
402 | CharacterOffset startCharacterOffsetOfSentence(const CharacterOffset&); |
403 | CharacterOffset endCharacterOffsetOfSentence(const CharacterOffset&); |
404 | CharacterOffset characterOffsetForPoint(const IntPoint&); |
405 | LayoutRect localCaretRectForCharacterOffset(RenderObject*&, const CharacterOffset&); |
406 | bool shouldSkipBoundary(const CharacterOffset&, const CharacterOffset&); |
407 | |
408 | private: |
409 | AccessibilityObject* rootWebArea(); |
410 | |
411 | static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); |
412 | |
413 | AXID getAXID(AccessibilityObject*); |
414 | |
415 | void notificationPostTimerFired(); |
416 | |
417 | void liveRegionChangedNotificationPostTimerFired(); |
418 | |
419 | void focusModalNodeTimerFired(); |
420 | |
421 | void performCacheUpdateTimerFired(); |
422 | |
423 | void postTextStateChangeNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&); |
424 | |
425 | bool enqueuePasswordValueChangeNotification(AccessibilityObject*); |
426 | void passwordNotificationPostTimerFired(); |
427 | |
428 | void handleMenuOpened(Node*); |
429 | void handleLiveRegionCreated(Node*); |
430 | void handleMenuItemSelected(Node*); |
431 | void handleAttributeChange(const QualifiedName&, Element*); |
432 | bool shouldProcessAttributeChange(const QualifiedName&, Element*); |
433 | void selectedChildrenChanged(Node*); |
434 | void selectedChildrenChanged(RenderObject*); |
435 | // Called by a node when text or a text equivalent (e.g. alt) attribute is changed. |
436 | void textChanged(Node*); |
437 | void handleActiveDescendantChanged(Node*); |
438 | void handleAriaRoleChanged(Node*); |
439 | void handleAriaExpandedChange(Node*); |
440 | void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode); |
441 | |
442 | // aria-modal related |
443 | void findModalNodes(); |
444 | void updateCurrentModalNode(); |
445 | bool isNodeVisible(Node*) const; |
446 | void handleModalChange(Node*); |
447 | |
448 | Document& m_document; |
449 | HashMap<AXID, RefPtr<AccessibilityObject>> m_objects; |
450 | HashMap<RenderObject*, AXID> m_renderObjectMapping; |
451 | HashMap<Widget*, AXID> m_widgetObjectMapping; |
452 | HashMap<Node*, AXID> m_nodeObjectMapping; |
453 | ListHashSet<Node*> m_textMarkerNodes; |
454 | std::unique_ptr<AXComputedObjectAttributeCache> m_computedObjectAttributeCache; |
455 | WEBCORE_EXPORT static bool gAccessibilityEnabled; |
456 | WEBCORE_EXPORT static bool gAccessibilityEnhancedUserInterfaceEnabled; |
457 | |
458 | HashSet<AXID> m_idsInUse; |
459 | |
460 | Timer m_notificationPostTimer; |
461 | Vector<std::pair<RefPtr<AccessibilityObject>, AXNotification>> m_notificationsToPost; |
462 | |
463 | Timer m_passwordNotificationPostTimer; |
464 | |
465 | ListHashSet<RefPtr<AccessibilityObject>> m_passwordNotificationsToPost; |
466 | |
467 | Timer m_liveRegionChangedPostTimer; |
468 | ListHashSet<RefPtr<AccessibilityObject>> m_liveRegionObjectsSet; |
469 | |
470 | Timer m_focusModalNodeTimer; |
471 | Node* m_currentModalNode; |
472 | ListHashSet<Node*> m_modalNodesSet; |
473 | |
474 | Timer m_performCacheUpdateTimer; |
475 | |
476 | AXTextStateChangeIntent m_textSelectionIntent; |
477 | ListHashSet<Element*> m_deferredRecomputeIsIgnoredList; |
478 | ListHashSet<Node*> m_deferredTextChangedList; |
479 | ListHashSet<Element*> m_deferredSelectedChildredChangedList; |
480 | ListHashSet<RefPtr<AccessibilityObject>> m_deferredChildredChangedList; |
481 | ListHashSet<Node*> m_deferredChildrenChangedNodeList; |
482 | HashMap<Element*, String> m_deferredTextFormControlValue; |
483 | HashMap<Element*, QualifiedName> m_deferredAttributeChange; |
484 | Vector<std::pair<Node*, Node*>> m_deferredFocusedNodeChange; |
485 | bool m_isSynchronizingSelection { false }; |
486 | bool m_performingDeferredCacheUpdate { false }; |
487 | |
488 | #if PLATFORM(GTK) |
489 | ListHashSet<RefPtr<AccessibilityObject>> m_deferredAttachedWrapperObjectList; |
490 | ListHashSet<GRefPtr<AccessibilityObjectWrapper>> m_deferredDetachedWrapperList; |
491 | #endif |
492 | }; |
493 | |
494 | class AXAttributeCacheEnabler |
495 | { |
496 | public: |
497 | explicit AXAttributeCacheEnabler(AXObjectCache *cache); |
498 | ~AXAttributeCacheEnabler(); |
499 | |
500 | #if HAVE(ACCESSIBILITY) |
501 | private: |
502 | AXObjectCache* m_cache; |
503 | #endif |
504 | }; |
505 | |
506 | bool nodeHasRole(Node*, const String& role); |
507 | // This will let you know if aria-hidden was explicitly set to false. |
508 | bool isNodeAriaVisible(Node*); |
509 | |
510 | #if !HAVE(ACCESSIBILITY) |
511 | inline AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID) const { return AccessibilityObjectInclusion::DefaultBehavior; } |
512 | inline AccessibilityReplacedText::AccessibilityReplacedText(const VisibleSelection&) { } |
513 | inline void AccessibilityReplacedText::postTextStateChangeNotification(AXObjectCache*, AXTextEditType, const String&, const VisibleSelection&) { } |
514 | inline void AXComputedObjectAttributeCache::setIgnored(AXID, AccessibilityObjectInclusion) { } |
515 | inline AXObjectCache::AXObjectCache(Document& document) : m_document(document), m_notificationPostTimer(*this, &AXObjectCache::notificationPostTimerFired), m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired), m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired), m_focusModalNodeTimer(*this, &AXObjectCache::focusModalNodeTimerFired), m_performCacheUpdateTimer(*this, &AXObjectCache::performCacheUpdateTimerFired) { } |
516 | inline AXObjectCache::~AXObjectCache() { } |
517 | inline AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page*) { return nullptr; } |
518 | inline AccessibilityObject* AXObjectCache::get(RenderObject*) { return nullptr; } |
519 | inline AccessibilityObject* AXObjectCache::get(Node*) { return nullptr; } |
520 | inline AccessibilityObject* AXObjectCache::get(Widget*) { return nullptr; } |
521 | inline AccessibilityObject* AXObjectCache::getOrCreate(RenderObject*) { return nullptr; } |
522 | inline AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole) { return nullptr; } |
523 | inline AccessibilityObject* AXObjectCache::getOrCreate(Node*) { return nullptr; } |
524 | inline AccessibilityObject* AXObjectCache::getOrCreate(Widget*) { return nullptr; } |
525 | inline AccessibilityObject* AXObjectCache::rootObject() { return nullptr; } |
526 | inline AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame*) { return nullptr; } |
527 | inline bool nodeHasRole(Node*, const String&) { return false; } |
528 | inline void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates() { } |
529 | inline void AXObjectCache::stopCachingComputedObjectAttributes() { } |
530 | inline bool isNodeAriaVisible(Node*) { return true; } |
531 | inline const Element* AXObjectCache::rootAXEditableElement(const Node*) { return nullptr; } |
532 | inline Node* AXObjectCache::modalNode() { return nullptr; } |
533 | inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } |
534 | inline void AXObjectCache::checkedStateChanged(Node*) { } |
535 | inline void AXObjectCache::childrenChanged(AccessibilityObject*) { } |
536 | inline void AXObjectCache::childrenChanged(Node*, Node*) { } |
537 | inline void AXObjectCache::childrenChanged(RenderObject*, RenderObject*) { } |
538 | inline void AXObjectCache::deferFocusedUIElementChangeIfNeeded(Node*, Node*) { } |
539 | inline void AXObjectCache::deferRecomputeIsIgnoredIfNeeded(Element*) { } |
540 | inline void AXObjectCache::deferRecomputeIsIgnored(Element*) { } |
541 | inline void AXObjectCache::deferTextChangedIfNeeded(Node*) { } |
542 | inline void AXObjectCache::deferSelectedChildrenChangedIfNeeded(Element&) { } |
543 | inline void AXObjectCache::deferTextReplacementNotificationForTextControl(HTMLTextFormControlElement&, const String&) { } |
544 | inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { } |
545 | inline void AXObjectCache::focusModalNodeTimerFired() { } |
546 | inline void AXObjectCache::performCacheUpdateTimerFired() { } |
547 | inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { } |
548 | inline void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject*, AXLoadingEvent) { } |
549 | inline void AXObjectCache::handleActiveDescendantChanged(Node*) { } |
550 | inline void AXObjectCache::handleAriaExpandedChange(Node*) { } |
551 | inline void AXObjectCache::handleModalChange(Node*) { } |
552 | inline void AXObjectCache::handleAriaRoleChanged(Node*) { } |
553 | inline void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName&, Element*) { } |
554 | inline void AXObjectCache::handleAttributeChange(const QualifiedName&, Element*) { } |
555 | inline bool AXObjectCache::shouldProcessAttributeChange(const QualifiedName&, Element*) { return false; } |
556 | inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } |
557 | inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } |
558 | inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } |
559 | inline void AXObjectCache::liveRegionChangedNotificationPostTimerFired() { } |
560 | inline void AXObjectCache::notificationPostTimerFired() { } |
561 | inline void AXObjectCache::passwordNotificationPostTimerFired() { } |
562 | inline void AXObjectCache::performDeferredCacheUpdate() { } |
563 | inline void AXObjectCache::postLiveRegionChangeNotification(AccessibilityObject*) { } |
564 | inline void AXObjectCache::postNotification(AccessibilityObject*, Document*, AXNotification, PostTarget, PostType) { } |
565 | inline void AXObjectCache::postNotification(Node*, AXNotification, PostTarget, PostType) { } |
566 | inline void AXObjectCache::postNotification(RenderObject*, AXNotification, PostTarget, PostType) { } |
567 | inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } |
568 | inline void AXObjectCache::postTextReplacementNotification(Node*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&) { } |
569 | inline void AXObjectCache::postTextReplacementNotificationForTextControl(HTMLTextFormControlElement&, const String&, const String&) { } |
570 | inline void AXObjectCache::postTextStateChangeNotification(Node*, AXTextEditType, const String&, const VisiblePosition&) { } |
571 | inline void AXObjectCache::postTextStateChangeNotification(Node*, const AXTextStateChangeIntent&, const VisibleSelection&) { } |
572 | inline void AXObjectCache::recomputeIsIgnored(RenderObject*) { } |
573 | inline void AXObjectCache::textChanged(AccessibilityObject*) { } |
574 | inline void AXObjectCache::textChanged(Node*) { } |
575 | inline void AXObjectCache::updateCacheAfterNodeIsAttached(Node*) { } |
576 | inline RefPtr<Range> AXObjectCache::rangeForNodeContents(Node*) { return nullptr; } |
577 | inline void AXObjectCache::remove(AXID) { } |
578 | inline void AXObjectCache::remove(RenderObject*) { } |
579 | inline void AXObjectCache::remove(Node&) { } |
580 | inline void AXObjectCache::remove(Widget*) { } |
581 | inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } |
582 | inline void AXObjectCache::selectedChildrenChanged(Node*) { } |
583 | inline void AXObjectCache::setIsSynchronizingSelection(bool) { } |
584 | inline void AXObjectCache::setTextSelectionIntent(const AXTextStateChangeIntent&) { } |
585 | inline RefPtr<Range> AXObjectCache::rangeForUnorderedCharacterOffsets(const CharacterOffset&, const CharacterOffset&) { return nullptr; } |
586 | inline IntRect AXObjectCache::absoluteCaretBoundsForCharacterOffset(const CharacterOffset&) { return IntRect(); } |
587 | inline CharacterOffset AXObjectCache::characterOffsetForIndex(int, const AccessibilityObject*) { return CharacterOffset(); } |
588 | inline CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range>, bool, bool) { return CharacterOffset(); } |
589 | inline CharacterOffset AXObjectCache::endCharacterOffsetOfLine(const CharacterOffset&) { return CharacterOffset(); } |
590 | inline CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset&, bool) { return CharacterOffset(); } |
591 | inline CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset&, bool) { return CharacterOffset(); } |
592 | #if PLATFORM(COCOA) |
593 | inline void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject*, const AXTextStateChangeIntent&, const VisibleSelection&) { } |
594 | inline void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject*, AXTextEditType, const String&, const VisiblePosition&) { } |
595 | inline void AXObjectCache::postTextReplacementPlatformNotification(AccessibilityObject*, AXTextEditType, const String&, AXTextEditType, const String&, const VisiblePosition&) { } |
596 | #else |
597 | inline AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType) { return AXTextInserted; } |
598 | inline void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject*, AXTextChange, unsigned, const String&) { } |
599 | #endif |
600 | |
601 | inline AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache*) { } |
602 | inline AXAttributeCacheEnabler::~AXAttributeCacheEnabler() { } |
603 | |
604 | #endif |
605 | |
606 | } // namespace WebCore |
607 | |