AX: VoiceOver unable to access content in malformed trees
[WebKit-https.git] / Source / WebCore / accessibility / AXObjectCache.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30
31 #if HAVE(ACCESSIBILITY)
32
33 #include "AXObjectCache.h"
34
35 #include "AccessibilityARIAGrid.h"
36 #include "AccessibilityARIAGridCell.h"
37 #include "AccessibilityARIAGridRow.h"
38 #include "AccessibilityImageMapLink.h"
39 #include "AccessibilityList.h"
40 #include "AccessibilityListBox.h"
41 #include "AccessibilityListBoxOption.h"
42 #include "AccessibilityMediaControls.h"
43 #include "AccessibilityMenuList.h"
44 #include "AccessibilityMenuListOption.h"
45 #include "AccessibilityMenuListPopup.h"
46 #include "AccessibilityProgressIndicator.h"
47 #include "AccessibilityRenderObject.h"
48 #include "AccessibilitySVGRoot.h"
49 #include "AccessibilityScrollView.h"
50 #include "AccessibilityScrollbar.h"
51 #include "AccessibilitySlider.h"
52 #include "AccessibilitySpinButton.h"
53 #include "AccessibilityTable.h"
54 #include "AccessibilityTableCell.h"
55 #include "AccessibilityTableColumn.h"
56 #include "AccessibilityTableHeaderContainer.h"
57 #include "AccessibilityTableRow.h"
58 #include "AccessibilityTree.h"
59 #include "AccessibilityTreeItem.h"
60 #include "Document.h"
61 #include "Editor.h"
62 #include "ElementIterator.h"
63 #include "FocusController.h"
64 #include "Frame.h"
65 #include "HTMLAreaElement.h"
66 #include "HTMLCanvasElement.h"
67 #include "HTMLImageElement.h"
68 #include "HTMLInputElement.h"
69 #include "HTMLLabelElement.h"
70 #include "HTMLMeterElement.h"
71 #include "HTMLNames.h"
72 #include "Page.h"
73 #include "RenderListBox.h"
74 #include "RenderMenuList.h"
75 #include "RenderMeter.h"
76 #include "RenderProgress.h"
77 #include "RenderSVGRoot.h"
78 #include "RenderSlider.h"
79 #include "RenderTable.h"
80 #include "RenderTableCell.h"
81 #include "RenderTableRow.h"
82 #include "RenderView.h"
83 #include "ScrollView.h"
84 #include <wtf/PassRefPtr.h>
85
86 #if ENABLE(VIDEO)
87 #include "MediaControlElements.h"
88 #endif
89
90 namespace WebCore {
91
92 using namespace HTMLNames;
93
94 // Post value change notifications for password fields or elements contained in password fields at a 40hz interval to thwart analysis of typing cadence
95 static double AccessibilityPasswordValueChangeNotificationInterval = 0.025;
96 static double AccessibilityLiveRegionChangedNotificationInterval = 0.020;
97
98 AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
99 {
100     HashMap<AXID, CachedAXObjectAttributes>::const_iterator it = m_idMapping.find(id);
101     return it != m_idMapping.end() ? it->value.ignored : DefaultBehavior;
102 }
103
104 void AXComputedObjectAttributeCache::setIgnored(AXID id, AccessibilityObjectInclusion inclusion)
105 {
106     HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
107     if (it != m_idMapping.end())
108         it->value.ignored = inclusion;
109     else {
110         CachedAXObjectAttributes attributes;
111         attributes.ignored = inclusion;
112         m_idMapping.set(id, attributes);
113     }
114 }
115     
116 bool AXObjectCache::gAccessibilityEnabled = false;
117 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
118
119 void AXObjectCache::enableAccessibility()
120 {
121     gAccessibilityEnabled = true;
122 }
123
124 void AXObjectCache::disableAccessibility()
125 {
126     gAccessibilityEnabled = false;
127 }
128
129 void AXObjectCache::setEnhancedUserInterfaceAccessibility(bool flag)
130 {
131     gAccessibilityEnhancedUserInterfaceEnabled = flag;
132 }
133
134 AXObjectCache::AXObjectCache(Document& document)
135     : m_document(document)
136     , m_notificationPostTimer(*this, &AXObjectCache::notificationPostTimerFired)
137     , m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired)
138     , m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired)
139 {
140 }
141
142 AXObjectCache::~AXObjectCache()
143 {
144     m_notificationPostTimer.stop();
145     m_liveRegionChangedPostTimer.stop();
146
147     for (const auto& object : m_objects.values()) {
148         detachWrapper(object.get(), CacheDestroyed);
149         object->detach(CacheDestroyed);
150         removeAXID(object.get());
151     }
152 }
153
154 AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
155 {
156     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
157     // in the list of children for its corresponding image.
158     if (!areaElement)
159         return nullptr;
160     
161     HTMLImageElement* imageElement = areaElement->imageElement();
162     if (!imageElement)
163         return nullptr;
164     
165     AccessibilityObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement);
166     if (!axRenderImage)
167         return nullptr;
168     
169     for (const auto& child : axRenderImage->children()) {
170         if (!is<AccessibilityImageMapLink>(*child))
171             continue;
172         
173         if (downcast<AccessibilityImageMapLink>(*child).areaElement() == areaElement)
174             return child.get();
175     }    
176     
177     return nullptr;
178 }
179     
180 AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
181 {
182     if (!gAccessibilityEnabled)
183         return nullptr;
184
185     // get the focused node in the page
186     Document* focusedDocument = page->focusController().focusedOrMainFrame().document();
187     Element* focusedElement = focusedDocument->focusedElement();
188     if (is<HTMLAreaElement>(focusedElement))
189         return focusedImageMapUIElement(downcast<HTMLAreaElement>(focusedElement));
190
191     AccessibilityObject* obj = focusedDocument->axObjectCache()->getOrCreate(focusedElement ? static_cast<Node*>(focusedElement) : focusedDocument);
192     if (!obj)
193         return nullptr;
194
195     if (obj->shouldFocusActiveDescendant()) {
196         if (AccessibilityObject* descendant = obj->activeDescendant())
197             obj = descendant;
198     }
199
200     // the HTML element, for example, is focusable but has an AX object that is ignored
201     if (obj->accessibilityIsIgnored())
202         obj = obj->parentObjectUnignored();
203
204     return obj;
205 }
206
207 AccessibilityObject* AXObjectCache::get(Widget* widget)
208 {
209     if (!widget)
210         return nullptr;
211         
212     AXID axID = m_widgetObjectMapping.get(widget);
213     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
214     if (!axID)
215         return nullptr;
216     
217     return m_objects.get(axID);    
218 }
219     
220 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
221 {
222     if (!renderer)
223         return nullptr;
224     
225     AXID axID = m_renderObjectMapping.get(renderer);
226     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
227     if (!axID)
228         return nullptr;
229
230     return m_objects.get(axID);    
231 }
232
233 AccessibilityObject* AXObjectCache::get(Node* node)
234 {
235     if (!node)
236         return nullptr;
237
238     AXID renderID = node->renderer() ? m_renderObjectMapping.get(node->renderer()) : 0;
239     ASSERT(!HashTraits<AXID>::isDeletedValue(renderID));
240
241     AXID nodeID = m_nodeObjectMapping.get(node);
242     ASSERT(!HashTraits<AXID>::isDeletedValue(nodeID));
243
244     if (node->renderer() && nodeID && !renderID) {
245         // This can happen if an AccessibilityNodeObject is created for a node that's not
246         // rendered, but later something changes and it gets a renderer (like if it's
247         // reparented).
248         remove(nodeID);
249         return nullptr;
250     }
251
252     if (renderID)
253         return m_objects.get(renderID);
254
255     if (!nodeID)
256         return nullptr;
257
258     return m_objects.get(nodeID);
259 }
260
261 // FIXME: This probably belongs on Node.
262 // FIXME: This should take a const char*, but one caller passes nullAtom.
263 bool nodeHasRole(Node* node, const String& role)
264 {
265     if (!node || !is<Element>(node))
266         return false;
267
268     auto& roleValue = downcast<Element>(*node).fastGetAttribute(roleAttr);
269     if (role.isNull())
270         return roleValue.isEmpty();
271     if (roleValue.isEmpty())
272         return false;
273
274     return SpaceSplitString(roleValue, true).contains(role);
275 }
276
277 static Ref<AccessibilityObject> createFromRenderer(RenderObject* renderer)
278 {
279     // FIXME: How could renderer->node() ever not be an Element?
280     Node* node = renderer->node();
281
282     // If the node is aria role="list" or the aria role is empty and its a
283     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
284     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
285                       || (nodeHasRole(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
286         return AccessibilityList::create(renderer);
287
288     // aria tables
289     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid") || nodeHasRole(node, "table"))
290         return AccessibilityARIAGrid::create(renderer);
291     if (nodeHasRole(node, "row"))
292         return AccessibilityARIAGridRow::create(renderer);
293     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "cell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
294         return AccessibilityARIAGridCell::create(renderer);
295
296     // aria tree
297     if (nodeHasRole(node, "tree"))
298         return AccessibilityTree::create(renderer);
299     if (nodeHasRole(node, "treeitem"))
300         return AccessibilityTreeItem::create(renderer);
301
302 #if ENABLE(VIDEO)
303     // media controls
304     if (node && node->isMediaControlElement())
305         return AccessibilityMediaControl::create(renderer);
306 #endif
307
308     if (is<RenderSVGRoot>(*renderer))
309         return AccessibilitySVGRoot::create(renderer);
310     
311     if (is<RenderBoxModelObject>(*renderer)) {
312         RenderBoxModelObject& cssBox = downcast<RenderBoxModelObject>(*renderer);
313         if (is<RenderListBox>(cssBox))
314             return AccessibilityListBox::create(&downcast<RenderListBox>(cssBox));
315         if (is<RenderMenuList>(cssBox))
316             return AccessibilityMenuList::create(&downcast<RenderMenuList>(cssBox));
317
318         // standard tables
319         if (is<RenderTable>(cssBox))
320             return AccessibilityTable::create(&downcast<RenderTable>(cssBox));
321         if (is<RenderTableRow>(cssBox))
322             return AccessibilityTableRow::create(&downcast<RenderTableRow>(cssBox));
323         if (is<RenderTableCell>(cssBox))
324             return AccessibilityTableCell::create(&downcast<RenderTableCell>(cssBox));
325
326         // progress bar
327         if (is<RenderProgress>(cssBox))
328             return AccessibilityProgressIndicator::create(&downcast<RenderProgress>(cssBox));
329
330 #if ENABLE(METER_ELEMENT)
331         if (is<RenderMeter>(cssBox))
332             return AccessibilityProgressIndicator::create(&downcast<RenderMeter>(cssBox));
333 #endif
334
335         // input type=range
336         if (is<RenderSlider>(cssBox))
337             return AccessibilitySlider::create(&downcast<RenderSlider>(cssBox));
338     }
339
340     return AccessibilityRenderObject::create(renderer);
341 }
342
343 static Ref<AccessibilityObject> createFromNode(Node* node)
344 {
345     return AccessibilityNodeObject::create(node);
346 }
347
348 AccessibilityObject* AXObjectCache::getOrCreate(Widget* widget)
349 {
350     if (!widget)
351         return nullptr;
352
353     if (AccessibilityObject* obj = get(widget))
354         return obj;
355     
356     RefPtr<AccessibilityObject> newObj;
357     if (is<ScrollView>(*widget))
358         newObj = AccessibilityScrollView::create(downcast<ScrollView>(widget));
359     else if (is<Scrollbar>(*widget))
360         newObj = AccessibilityScrollbar::create(downcast<Scrollbar>(widget));
361
362     // Will crash later if we have two objects for the same widget.
363     ASSERT(!get(widget));
364
365     // Catch the case if an (unsupported) widget type is used. Only FrameView and ScrollBar are supported now.
366     ASSERT(newObj);
367     if (!newObj)
368         return nullptr;
369
370     getAXID(newObj.get());
371     
372     m_widgetObjectMapping.set(widget, newObj->axObjectID());
373     m_objects.set(newObj->axObjectID(), newObj);    
374     newObj->init();
375     attachWrapper(newObj.get());
376     return newObj.get();
377 }
378
379 AccessibilityObject* AXObjectCache::getOrCreate(Node* node)
380 {
381     if (!node)
382         return nullptr;
383
384     if (AccessibilityObject* obj = get(node))
385         return obj;
386
387     if (node->renderer())
388         return getOrCreate(node->renderer());
389
390     if (!node->parentElement())
391         return nullptr;
392     
393     // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree.
394     // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes.
395     bool inCanvasSubtree = lineageOfType<HTMLCanvasElement>(*node->parentElement()).first();
396     bool isHidden = isNodeAriaVisible(node);
397
398     bool insideMeterElement = false;
399 #if ENABLE(METER_ELEMENT)
400     insideMeterElement = is<HTMLMeterElement>(*node->parentElement());
401 #endif
402     
403     if (!inCanvasSubtree && !isHidden && !insideMeterElement)
404         return nullptr;
405
406     // Fallback content is only focusable as long as the canvas is displayed and visible.
407     // Update the style before Element::isFocusable() gets called.
408     if (inCanvasSubtree)
409         node->document().updateStyleIfNeeded();
410
411     RefPtr<AccessibilityObject> newObj = createFromNode(node);
412
413     // Will crash later if we have two objects for the same node.
414     ASSERT(!get(node));
415
416     getAXID(newObj.get());
417
418     m_nodeObjectMapping.set(node, newObj->axObjectID());
419     m_objects.set(newObj->axObjectID(), newObj);
420     newObj->init();
421     attachWrapper(newObj.get());
422     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
423     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
424     // it will disappear when this function is finished, leading to a use-after-free.
425     if (newObj->isDetached())
426         return nullptr;
427     
428     return newObj.get();
429 }
430
431 AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
432 {
433     if (!renderer)
434         return nullptr;
435
436     if (AccessibilityObject* obj = get(renderer))
437         return obj;
438
439     RefPtr<AccessibilityObject> newObj = createFromRenderer(renderer);
440
441     // Will crash later if we have two objects for the same renderer.
442     ASSERT(!get(renderer));
443
444     getAXID(newObj.get());
445
446     m_renderObjectMapping.set(renderer, newObj->axObjectID());
447     m_objects.set(newObj->axObjectID(), newObj);
448     newObj->init();
449     attachWrapper(newObj.get());
450     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
451     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
452     // it will disappear when this function is finished, leading to a use-after-free.
453     if (newObj->isDetached())
454         return nullptr;
455     
456     return newObj.get();
457 }
458     
459 AccessibilityObject* AXObjectCache::rootObject()
460 {
461     if (!gAccessibilityEnabled)
462         return nullptr;
463
464     return getOrCreate(m_document.view());
465 }
466
467 AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame* frame)
468 {
469     if (!gAccessibilityEnabled)
470         return nullptr;
471
472     if (!frame)
473         return nullptr;
474     return getOrCreate(frame->view());
475 }    
476     
477 AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
478 {
479     RefPtr<AccessibilityObject> obj = nullptr;
480     
481     // will be filled in...
482     switch (role) {
483     case ListBoxOptionRole:
484         obj = AccessibilityListBoxOption::create();
485         break;
486     case ImageMapLinkRole:
487         obj = AccessibilityImageMapLink::create();
488         break;
489     case ColumnRole:
490         obj = AccessibilityTableColumn::create();
491         break;            
492     case TableHeaderContainerRole:
493         obj = AccessibilityTableHeaderContainer::create();
494         break;   
495     case SliderThumbRole:
496         obj = AccessibilitySliderThumb::create();
497         break;
498     case MenuListPopupRole:
499         obj = AccessibilityMenuListPopup::create();
500         break;
501     case MenuListOptionRole:
502         obj = AccessibilityMenuListOption::create();
503         break;
504     case SpinButtonRole:
505         obj = AccessibilitySpinButton::create();
506         break;
507     case SpinButtonPartRole:
508         obj = AccessibilitySpinButtonPart::create();
509         break;
510     default:
511         obj = nullptr;
512     }
513     
514     if (obj)
515         getAXID(obj.get());
516     else
517         return nullptr;
518
519     m_objects.set(obj->axObjectID(), obj);    
520     obj->init();
521     attachWrapper(obj.get());
522     return obj.get();
523 }
524
525 void AXObjectCache::remove(AXID axID)
526 {
527     if (!axID)
528         return;
529     
530     // first fetch object to operate some cleanup functions on it 
531     AccessibilityObject* obj = m_objects.get(axID);
532     if (!obj)
533         return;
534     
535     detachWrapper(obj, ElementDestroyed);
536     obj->detach(ElementDestroyed, this);
537     removeAXID(obj);
538     
539     // finally remove the object
540     if (!m_objects.take(axID))
541         return;
542     
543     ASSERT(m_objects.size() >= m_idsInUse.size());    
544 }
545     
546 void AXObjectCache::remove(RenderObject* renderer)
547 {
548     if (!renderer)
549         return;
550     
551     AXID axID = m_renderObjectMapping.get(renderer);
552     remove(axID);
553     m_renderObjectMapping.remove(renderer);
554 }
555
556 void AXObjectCache::remove(Node* node)
557 {
558     if (!node)
559         return;
560
561     removeNodeForUse(node);
562
563     // This is all safe even if we didn't have a mapping.
564     AXID axID = m_nodeObjectMapping.get(node);
565     remove(axID);
566     m_nodeObjectMapping.remove(node);
567
568     if (node->renderer()) {
569         remove(node->renderer());
570         return;
571     }
572 }
573
574 void AXObjectCache::remove(Widget* view)
575 {
576     if (!view)
577         return;
578         
579     AXID axID = m_widgetObjectMapping.get(view);
580     remove(axID);
581     m_widgetObjectMapping.remove(view);
582 }
583     
584     
585 #if !PLATFORM(WIN)
586 AXID AXObjectCache::platformGenerateAXID() const
587 {
588     static AXID lastUsedID = 0;
589
590     // Generate a new ID.
591     AXID objID = lastUsedID;
592     do {
593         ++objID;
594     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
595
596     lastUsedID = objID;
597
598     return objID;
599 }
600 #endif
601
602 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
603 {
604     // check for already-assigned ID
605     AXID objID = obj->axObjectID();
606     if (objID) {
607         ASSERT(m_idsInUse.contains(objID));
608         return objID;
609     }
610
611     objID = platformGenerateAXID();
612
613     m_idsInUse.add(objID);
614     obj->setAXObjectID(objID);
615     
616     return objID;
617 }
618
619 void AXObjectCache::removeAXID(AccessibilityObject* object)
620 {
621     if (!object)
622         return;
623     
624     AXID objID = object->axObjectID();
625     if (!objID)
626         return;
627     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
628     ASSERT(m_idsInUse.contains(objID));
629     object->setAXObjectID(0);
630     m_idsInUse.remove(objID);
631 }
632
633 void AXObjectCache::textChanged(Node* node)
634 {
635     textChanged(getOrCreate(node));
636 }
637
638 void AXObjectCache::textChanged(RenderObject* renderer)
639 {
640     textChanged(getOrCreate(renderer));
641 }
642
643 void AXObjectCache::textChanged(AccessibilityObject* obj)
644 {
645     if (!obj)
646         return;
647
648     bool parentAlreadyExists = obj->parentObjectIfExists();
649     obj->textChanged();
650     postNotification(obj, obj->document(), AXObjectCache::AXTextChanged);
651     if (parentAlreadyExists)
652         obj->notifyIfIgnoredValueChanged();
653 }
654
655 void AXObjectCache::updateCacheAfterNodeIsAttached(Node* node)
656 {
657     // Calling get() will update the AX object if we had an AccessibilityNodeObject but now we need
658     // an AccessibilityRenderObject, because it was reparented to a location outside of a canvas.
659     get(node);
660 }
661
662 void AXObjectCache::handleMenuOpened(Node* node)
663 {
664     if (!node || !node->renderer() || !nodeHasRole(node, "menu"))
665         return;
666     
667     postNotification(getOrCreate(node), &document(), AXMenuOpened);
668 }
669     
670 void AXObjectCache::handleLiveRegionCreated(Node* node)
671 {
672     if (!is<Element>(node) || !node->renderer())
673         return;
674     
675     Element* element = downcast<Element>(node);
676     String liveRegionStatus = element->fastGetAttribute(aria_liveAttr);
677     if (liveRegionStatus.isEmpty()) {
678         const AtomicString& ariaRole = element->fastGetAttribute(roleAttr);
679         if (!ariaRole.isEmpty())
680             liveRegionStatus = AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityObject::ariaRoleToWebCoreRole(ariaRole));
681     }
682     
683     if (AccessibilityObject::liveRegionStatusIsEnabled(liveRegionStatus))
684         postNotification(getOrCreate(node), &document(), AXLiveRegionCreated);
685 }
686     
687 void AXObjectCache::childrenChanged(Node* node, Node* newChild)
688 {
689     if (newChild) {
690         handleMenuOpened(newChild);
691         handleLiveRegionCreated(newChild);
692     }
693     
694     childrenChanged(get(node));
695 }
696
697 void AXObjectCache::childrenChanged(RenderObject* renderer, RenderObject* newChild)
698 {
699     if (!renderer)
700         return;
701     
702     if (newChild) {
703         handleMenuOpened(newChild->node());
704         handleLiveRegionCreated(newChild->node());
705     }
706     
707     childrenChanged(get(renderer));
708 }
709
710 void AXObjectCache::childrenChanged(AccessibilityObject* obj)
711 {
712     if (!obj)
713         return;
714
715     obj->childrenChanged();
716 }
717     
718 void AXObjectCache::notificationPostTimerFired()
719 {
720     Ref<Document> protectorForCacheOwner(m_document);
721     m_notificationPostTimer.stop();
722     
723     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
724     // when the notification list is cleared at the end. Instead copy this list at the start.
725     auto notifications = WTF::move(m_notificationsToPost);
726     
727     for (const auto& note : notifications) {
728         AccessibilityObject* obj = note.first.get();
729         if (!obj->axObjectID())
730             continue;
731
732         if (!obj->axObjectCache())
733             continue;
734         
735 #ifndef NDEBUG
736         // Make sure none of the render views are in the process of being layed out.
737         // Notifications should only be sent after the renderer has finished
738         if (is<AccessibilityRenderObject>(*obj)) {
739             if (auto* renderer = downcast<AccessibilityRenderObject>(*obj).renderer())
740                 ASSERT(!renderer->view().layoutState());
741         }
742 #endif
743
744         AXNotification notification = note.second;
745         
746         // Ensure that this menu really is a menu. We do this check here so that we don't have to create
747         // the axChildren when the menu is marked as opening.
748         if (notification == AXMenuOpened) {
749             obj->updateChildrenIfNecessary();
750             if (obj->roleValue() != MenuRole)
751                 continue;
752         }
753         
754         postPlatformNotification(obj, notification);
755
756         if (notification == AXChildrenChanged && obj->parentObjectIfExists() && obj->lastKnownIsIgnoredValue() != obj->accessibilityIsIgnored())
757             childrenChanged(obj->parentObject());
758     }
759 }
760
761 void AXObjectCache::passwordNotificationPostTimerFired()
762 {
763 #if PLATFORM(COCOA)
764     m_passwordNotificationPostTimer.stop();
765
766     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
767     // when the notification list is cleared at the end. Instead copy this list at the start.
768     auto notifications = WTF::move(m_passwordNotificationsToPost);
769
770     for (auto& notification : notifications)
771         postTextStateChangePlatformNotification(notification.get(), AXTextEditTypeInsert, " ", VisiblePosition());
772 #endif
773 }
774     
775 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, PostTarget postTarget, PostType postType)
776 {
777     if (!renderer)
778         return;
779     
780     stopCachingComputedObjectAttributes();
781
782     // Get an accessibility object that already exists. One should not be created here
783     // because a render update may be in progress and creating an AX object can re-trigger a layout
784     RefPtr<AccessibilityObject> object = get(renderer);
785     while (!object && renderer) {
786         renderer = renderer->parent();
787         object = get(renderer); 
788     }
789     
790     if (!renderer)
791         return;
792     
793     postNotification(object.get(), &renderer->document(), notification, postTarget, postType);
794 }
795
796 void AXObjectCache::postNotification(Node* node, AXNotification notification, PostTarget postTarget, PostType postType)
797 {
798     if (!node)
799         return;
800     
801     stopCachingComputedObjectAttributes();
802
803     // Get an accessibility object that already exists. One should not be created here
804     // because a render update may be in progress and creating an AX object can re-trigger a layout
805     RefPtr<AccessibilityObject> object = get(node);
806     while (!object && node) {
807         node = node->parentNode();
808         object = get(node);
809     }
810     
811     if (!node)
812         return;
813     
814     postNotification(object.get(), &node->document(), notification, postTarget, postType);
815 }
816
817 void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, PostTarget postTarget, PostType postType)
818 {
819     stopCachingComputedObjectAttributes();
820
821     if (object && postTarget == TargetObservableParent)
822         object = object->observableObject();
823
824     if (!object && document)
825         object = get(document->renderView());
826
827     if (!object)
828         return;
829
830     if (postType == PostAsynchronously) {
831         m_notificationsToPost.append(std::make_pair(object, notification));
832         if (!m_notificationPostTimer.isActive())
833             m_notificationPostTimer.startOneShot(0);
834     } else
835         postPlatformNotification(object, notification);
836 }
837
838 void AXObjectCache::checkedStateChanged(Node* node)
839 {
840     postNotification(node, AXObjectCache::AXCheckedStateChanged);
841 }
842
843 void AXObjectCache::handleMenuItemSelected(Node* node)
844 {
845     if (!node)
846         return;
847     
848     if (!nodeHasRole(node, "menuitem") && !nodeHasRole(node, "menuitemradio") && !nodeHasRole(node, "menuitemcheckbox"))
849         return;
850     
851     if (!downcast<Element>(*node).focused() && !equalIgnoringCase(downcast<Element>(*node).fastGetAttribute(aria_selectedAttr), "true"))
852         return;
853     
854     postNotification(getOrCreate(node), &document(), AXMenuListItemSelected);
855 }
856     
857 void AXObjectCache::handleFocusedUIElementChanged(Node* oldNode, Node* newNode)
858 {
859     handleMenuItemSelected(newNode);
860     platformHandleFocusedUIElementChanged(oldNode, newNode);
861 }
862     
863 void AXObjectCache::selectedChildrenChanged(Node* node)
864 {
865     handleMenuItemSelected(node);
866     
867     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
868     // to find the container which should send out the notification.
869     postNotification(node, AXSelectedChildrenChanged, TargetObservableParent);
870 }
871
872 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
873 {
874     if (renderer)
875         handleMenuItemSelected(renderer->node());
876
877     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
878     // to find the container which should send out the notification.
879     postNotification(renderer, AXSelectedChildrenChanged, TargetObservableParent);
880 }
881
882 #ifndef NDEBUG
883 void AXObjectCache::showIntent(const AXTextStateChangeIntent &intent)
884 {
885     switch (intent.type) {
886     case AXTextStateChangeTypeUnknown:
887         dataLog("Unknown");
888         break;
889     case AXTextStateChangeTypeEdit:
890         dataLog("Edit::");
891         break;
892     case AXTextStateChangeTypeSelectionMove:
893         dataLog("Move::");
894         break;
895     case AXTextStateChangeTypeSelectionExtend:
896         dataLog("Extend::");
897         break;
898     }
899     switch (intent.type) {
900     case AXTextStateChangeTypeUnknown:
901         break;
902     case AXTextStateChangeTypeEdit:
903         switch (intent.change) {
904         case AXTextEditTypeUnknown:
905             dataLog("Unknown");
906             break;
907         case AXTextEditTypeDelete:
908             dataLog("Delete");
909             break;
910         case AXTextEditTypeInsert:
911             dataLog("Insert");
912             break;
913         case AXTextEditTypeDictation:
914             dataLog("DictationInsert");
915             break;
916         case AXTextEditTypeTyping:
917             dataLog("TypingInsert");
918             break;
919         case AXTextEditTypeCut:
920             dataLog("Cut");
921             break;
922         case AXTextEditTypePaste:
923             dataLog("Paste");
924             break;
925         case AXTextEditTypeAttributesChange:
926             dataLog("AttributesChange");
927             break;
928         }
929         break;
930     case AXTextStateChangeTypeSelectionMove:
931     case AXTextStateChangeTypeSelectionExtend:
932         switch (intent.selection.direction) {
933         case AXTextSelectionDirectionUnknown:
934             dataLog("Unknown::");
935             break;
936         case AXTextSelectionDirectionBeginning:
937             dataLog("Beginning::");
938             break;
939         case AXTextSelectionDirectionEnd:
940             dataLog("End::");
941             break;
942         case AXTextSelectionDirectionPrevious:
943             dataLog("Previous::");
944             break;
945         case AXTextSelectionDirectionNext:
946             dataLog("Next::");
947             break;
948         case AXTextSelectionDirectionDiscontiguous:
949             dataLog("Discontiguous::");
950             break;
951         }
952         switch (intent.selection.direction) {
953         case AXTextSelectionDirectionUnknown:
954         case AXTextSelectionDirectionBeginning:
955         case AXTextSelectionDirectionEnd:
956         case AXTextSelectionDirectionPrevious:
957         case AXTextSelectionDirectionNext:
958             switch (intent.selection.granularity) {
959             case AXTextSelectionGranularityUnknown:
960                 dataLog("Unknown");
961                 break;
962             case AXTextSelectionGranularityCharacter:
963                 dataLog("Character");
964                 break;
965             case AXTextSelectionGranularityWord:
966                 dataLog("Word");
967                 break;
968             case AXTextSelectionGranularityLine:
969                 dataLog("Line");
970                 break;
971             case AXTextSelectionGranularitySentence:
972                 dataLog("Sentence");
973                 break;
974             case AXTextSelectionGranularityParagraph:
975                 dataLog("Paragraph");
976                 break;
977             case AXTextSelectionGranularityPage:
978                 dataLog("Page");
979                 break;
980             case AXTextSelectionGranularityDocument:
981                 dataLog("Document");
982                 break;
983             case AXTextSelectionGranularityAll:
984                 dataLog("All");
985                 break;
986             }
987             break;
988         case AXTextSelectionDirectionDiscontiguous:
989             break;
990         }
991         break;
992     }
993     dataLog("\n");
994 }
995 #endif
996
997 void AXObjectCache::setTextSelectionIntent(const AXTextStateChangeIntent& intent)
998 {
999     m_textSelectionIntent = intent;
1000 }
1001     
1002 void AXObjectCache::setIsSynchronizingSelection(bool isSynchronizing)
1003 {
1004     m_isSynchronizingSelection = isSynchronizing;
1005 }
1006
1007 static bool isPasswordFieldOrContainedByPasswordField(AccessibilityObject* object)
1008 {
1009     return object && (object->isPasswordField() || object->isContainedByPasswordField());
1010 }
1011
1012 void AXObjectCache::postTextStateChangeNotification(Node* node, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1013 {
1014     if (!node)
1015         return;
1016
1017 #if PLATFORM(COCOA)
1018     stopCachingComputedObjectAttributes();
1019
1020     postTextStateChangeNotification(getOrCreate(node), intent, selection);
1021 #else
1022     postNotification(node->renderer(), AXObjectCache::AXSelectedTextChanged, TargetObservableParent);
1023     UNUSED_PARAM(intent);
1024     UNUSED_PARAM(selection);
1025 #endif
1026 }
1027
1028 void AXObjectCache::postTextStateChangeNotification(const Position& position, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1029 {
1030     Node* node = position.deprecatedNode();
1031     if (!node)
1032         return;
1033
1034     stopCachingComputedObjectAttributes();
1035
1036 #if PLATFORM(COCOA)
1037     AccessibilityObject* object = getOrCreate(node);
1038     if (object && object->accessibilityIsIgnored()) {
1039         if (position.atLastEditingPositionForNode()) {
1040             if (AccessibilityObject* nextSibling = object->nextSiblingUnignored(1))
1041                 object = nextSibling;
1042         } else if (position.atFirstEditingPositionForNode()) {
1043             if (AccessibilityObject* previousSibling = object->previousSiblingUnignored(1))
1044                 object = previousSibling;
1045         }
1046     }
1047
1048     postTextStateChangeNotification(object, intent, selection);
1049 #else
1050     postTextStateChangeNotification(node, intent, selection);
1051 #endif
1052 }
1053
1054 void AXObjectCache::postTextStateChangeNotification(AccessibilityObject* object, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1055 {
1056     stopCachingComputedObjectAttributes();
1057
1058 #if PLATFORM(COCOA)
1059     if (object) {
1060         if (isPasswordFieldOrContainedByPasswordField(object))
1061             return;
1062
1063         if (auto observableObject = object->observableObject())
1064             object = observableObject;
1065     }
1066
1067     const AXTextStateChangeIntent& newIntent = (intent.type == AXTextStateChangeTypeUnknown || (m_isSynchronizingSelection && m_textSelectionIntent.type != AXTextStateChangeTypeUnknown)) ? m_textSelectionIntent : intent;
1068     postTextStateChangePlatformNotification(object, newIntent, selection);
1069 #else
1070     UNUSED_PARAM(object);
1071     UNUSED_PARAM(intent);
1072     UNUSED_PARAM(selection);
1073 #endif
1074
1075     setTextSelectionIntent(AXTextStateChangeIntent());
1076     setIsSynchronizingSelection(false);
1077 }
1078
1079 void AXObjectCache::postTextStateChangeNotification(Node* node, AXTextEditType type, const String& text, const VisiblePosition& position)
1080 {
1081     if (!node)
1082         return;
1083     ASSERT(type != AXTextEditTypeUnknown);
1084
1085     stopCachingComputedObjectAttributes();
1086
1087     AccessibilityObject* object = getOrCreate(node);
1088 #if PLATFORM(COCOA)
1089     if (object) {
1090         if (enqueuePasswordValueChangeNotification(object))
1091             return;
1092         object = object->observableObject();
1093     }
1094
1095     postTextStateChangePlatformNotification(object, type, text, position);
1096 #else
1097     nodeTextChangePlatformNotification(object, textChangeForEditType(type), position.deepEquivalent().deprecatedEditingOffset(), text);
1098 #endif
1099 }
1100
1101 void AXObjectCache::postTextReplacementNotification(Node* node, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition& position)
1102 {
1103     if (!node)
1104         return;
1105     ASSERT(deletionType == AXTextEditTypeDelete);
1106     ASSERT(insertionType == AXTextEditTypeInsert || insertionType == AXTextEditTypeTyping || insertionType == AXTextEditTypeDictation || insertionType == AXTextEditTypePaste);
1107
1108     stopCachingComputedObjectAttributes();
1109
1110     AccessibilityObject* object = getOrCreate(node);
1111 #if PLATFORM(COCOA)
1112     if (object) {
1113         if (enqueuePasswordValueChangeNotification(object))
1114             return;
1115         object = object->observableObject();
1116     }
1117
1118     postTextReplacementPlatformNotification(object, deletionType, deletedText, insertionType, insertedText, position);
1119 #else
1120     nodeTextChangePlatformNotification(object, textChangeForEditType(deletionType), position.deepEquivalent().deprecatedEditingOffset(), deletedText);
1121     nodeTextChangePlatformNotification(object, textChangeForEditType(insertionType), position.deepEquivalent().deprecatedEditingOffset(), insertedText);
1122 #endif
1123 }
1124
1125 bool AXObjectCache::enqueuePasswordValueChangeNotification(AccessibilityObject* object)
1126 {
1127     if (!isPasswordFieldOrContainedByPasswordField(object))
1128         return false;
1129
1130     AccessibilityObject* observableObject = object->observableObject();
1131     if (!observableObject) {
1132         ASSERT_NOT_REACHED();
1133         // return true even though the enqueue didn't happen because this is a password field and caller shouldn't post a notification
1134         return true;
1135     }
1136
1137     m_passwordNotificationsToPost.add(observableObject);
1138     if (!m_passwordNotificationPostTimer.isActive())
1139         m_passwordNotificationPostTimer.startOneShot(AccessibilityPasswordValueChangeNotificationInterval);
1140
1141     return true;
1142 }
1143
1144 void AXObjectCache::frameLoadingEventNotification(Frame* frame, AXLoadingEvent loadingEvent)
1145 {
1146     if (!frame)
1147         return;
1148
1149     // Delegate on the right platform
1150     RenderView* contentRenderer = frame->contentRenderer();
1151     if (!contentRenderer)
1152         return;
1153
1154     AccessibilityObject* obj = getOrCreate(contentRenderer);
1155     frameLoadingEventPlatformNotification(obj, loadingEvent);
1156 }
1157
1158 void AXObjectCache::postLiveRegionChangeNotification(AccessibilityObject* object)
1159 {
1160     if (m_liveRegionChangedPostTimer.isActive())
1161         m_liveRegionChangedPostTimer.stop();
1162
1163     if (!m_liveRegionObjectsSet.contains(object))
1164         m_liveRegionObjectsSet.add(object);
1165
1166     m_liveRegionChangedPostTimer.startOneShot(AccessibilityLiveRegionChangedNotificationInterval);
1167 }
1168
1169 void AXObjectCache::liveRegionChangedNotificationPostTimerFired()
1170 {
1171     m_liveRegionChangedPostTimer.stop();
1172
1173     if (m_liveRegionObjectsSet.isEmpty())
1174         return;
1175
1176     for (auto& object : m_liveRegionObjectsSet)
1177         postNotification(object.get(), object->document(), AXObjectCache::AXLiveRegionChanged);
1178     m_liveRegionObjectsSet.clear();
1179 }
1180
1181 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
1182 {
1183     if (!view)
1184         return;
1185     
1186     // We don't want to create a scroll view from this method, only update an existing one.
1187     if (AccessibilityObject* scrollViewObject = get(view)) {
1188         stopCachingComputedObjectAttributes();
1189         scrollViewObject->updateChildrenIfNecessary();
1190     }
1191 }
1192     
1193 void AXObjectCache::handleAriaExpandedChange(Node* node)
1194 {
1195     if (AccessibilityObject* obj = getOrCreate(node))
1196         obj->handleAriaExpandedChanged();
1197 }
1198     
1199 void AXObjectCache::handleActiveDescendantChanged(Node* node)
1200 {
1201     if (AccessibilityObject* obj = getOrCreate(node))
1202         obj->handleActiveDescendantChanged();
1203 }
1204
1205 void AXObjectCache::handleAriaRoleChanged(Node* node)
1206 {
1207     stopCachingComputedObjectAttributes();
1208
1209     if (AccessibilityObject* obj = getOrCreate(node)) {
1210         obj->updateAccessibilityRole();
1211         obj->notifyIfIgnoredValueChanged();
1212     }
1213 }
1214
1215 void AXObjectCache::handleAttributeChanged(const QualifiedName& attrName, Element* element)
1216 {
1217     if (attrName == roleAttr)
1218         handleAriaRoleChanged(element);
1219     else if (attrName == altAttr || attrName == titleAttr)
1220         textChanged(element);
1221     else if (attrName == forAttr && is<HTMLLabelElement>(*element))
1222         labelChanged(element);
1223
1224     if (!attrName.localName().string().startsWith("aria-"))
1225         return;
1226
1227     if (attrName == aria_activedescendantAttr)
1228         handleActiveDescendantChanged(element);
1229     else if (attrName == aria_busyAttr)
1230         postNotification(element, AXObjectCache::AXElementBusyChanged);
1231     else if (attrName == aria_valuenowAttr || attrName == aria_valuetextAttr)
1232         postNotification(element, AXObjectCache::AXValueChanged);
1233     else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr)
1234         textChanged(element);
1235     else if (attrName == aria_checkedAttr)
1236         checkedStateChanged(element);
1237     else if (attrName == aria_selectedAttr)
1238         selectedChildrenChanged(element);
1239     else if (attrName == aria_expandedAttr)
1240         handleAriaExpandedChange(element);
1241     else if (attrName == aria_hiddenAttr)
1242         childrenChanged(element->parentNode(), element);
1243     else if (attrName == aria_invalidAttr)
1244         postNotification(element, AXObjectCache::AXInvalidStatusChanged);
1245     else
1246         postNotification(element, AXObjectCache::AXAriaAttributeChanged);
1247 }
1248
1249 void AXObjectCache::labelChanged(Element* element)
1250 {
1251     ASSERT(is<HTMLLabelElement>(*element));
1252     HTMLElement* correspondingControl = downcast<HTMLLabelElement>(*element).control();
1253     textChanged(correspondingControl);
1254 }
1255
1256 void AXObjectCache::recomputeIsIgnored(RenderObject* renderer)
1257 {
1258     if (AccessibilityObject* obj = get(renderer))
1259         obj->notifyIfIgnoredValueChanged();
1260 }
1261
1262 void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates()
1263 {
1264     if (!m_computedObjectAttributeCache)
1265         m_computedObjectAttributeCache = std::make_unique<AXComputedObjectAttributeCache>();
1266 }
1267
1268 void AXObjectCache::stopCachingComputedObjectAttributes()
1269 {
1270     m_computedObjectAttributeCache = nullptr;
1271 }
1272
1273 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
1274 {
1275     if (!isNodeInUse(textMarkerData.node))
1276         return VisiblePosition();
1277     
1278     // FIXME: Accessability should make it clear these are DOM-compliant offsets or store Position objects.
1279     VisiblePosition visiblePos = VisiblePosition(createLegacyEditingPosition(textMarkerData.node, textMarkerData.offset), textMarkerData.affinity);
1280     Position deepPos = visiblePos.deepEquivalent();
1281     if (deepPos.isNull())
1282         return VisiblePosition();
1283     
1284     RenderObject* renderer = deepPos.deprecatedNode()->renderer();
1285     if (!renderer)
1286         return VisiblePosition();
1287     
1288     AXObjectCache* cache = renderer->document().axObjectCache();
1289     if (!cache->isIDinUse(textMarkerData.axID))
1290         return VisiblePosition();
1291     
1292     if (deepPos.deprecatedNode() != textMarkerData.node || deepPos.deprecatedEditingOffset() != textMarkerData.offset)
1293         return VisiblePosition();
1294     
1295     return visiblePos;
1296 }
1297
1298 void AXObjectCache::textMarkerDataForVisiblePosition(TextMarkerData& textMarkerData, const VisiblePosition& visiblePos)
1299 {
1300     // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
1301     // This also allows callers to check for failure by looking at textMarkerData upon return.
1302     memset(&textMarkerData, 0, sizeof(TextMarkerData));
1303     
1304     if (visiblePos.isNull())
1305         return;
1306     
1307     Position deepPos = visiblePos.deepEquivalent();
1308     Node* domNode = deepPos.deprecatedNode();
1309     ASSERT(domNode);
1310     if (!domNode)
1311         return;
1312     
1313     if (domNode->isHTMLElement()) {
1314         HTMLInputElement* inputElement = domNode->toInputElement();
1315         if (inputElement && inputElement->isPasswordField())
1316             return;
1317     }
1318     
1319     // find or create an accessibility object for this node
1320     AXObjectCache* cache = domNode->document().axObjectCache();
1321     RefPtr<AccessibilityObject> obj = cache->getOrCreate(domNode);
1322     
1323     textMarkerData.axID = obj.get()->axObjectID();
1324     textMarkerData.node = domNode;
1325     textMarkerData.offset = deepPos.deprecatedEditingOffset();
1326     textMarkerData.affinity = visiblePos.affinity();   
1327     
1328     cache->setNodeInUse(domNode);
1329 }
1330
1331 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
1332 {
1333     const Element* result = node->rootEditableElement();
1334     const Element* element = is<Element>(*node) ? downcast<Element>(node) : node->parentElement();
1335
1336     for (; element; element = element->parentElement()) {
1337         if (nodeIsTextControl(element))
1338             result = element;
1339     }
1340
1341     return result;
1342 }
1343
1344 void AXObjectCache::clearTextMarkerNodesInUse(Document* document)
1345 {
1346     if (!document)
1347         return;
1348     
1349     // Check each node to see if it's inside the document being deleted, of if it no longer belongs to a document.
1350     HashSet<Node*> nodesToDelete;
1351     for (const auto& node : m_textMarkerNodes) {
1352         if (!node->inDocument() || &(node)->document() == document)
1353             nodesToDelete.add(node);
1354     }
1355     
1356     for (const auto& node : nodesToDelete)
1357         m_textMarkerNodes.remove(node);
1358 }
1359     
1360 bool AXObjectCache::nodeIsTextControl(const Node* node)
1361 {
1362     if (!node)
1363         return false;
1364
1365     const AccessibilityObject* axObject = getOrCreate(const_cast<Node*>(node));
1366     return axObject && axObject->isTextControl();
1367 }
1368     
1369 bool isNodeAriaVisible(Node* node)
1370 {
1371     if (!node)
1372         return false;
1373
1374     // ARIA Node visibility is controlled by aria-hidden
1375     //  1) if aria-hidden=true, the whole subtree is hidden
1376     //  2) if aria-hidden=false, and the object is rendered, there's no effect
1377     //  3) if aria-hidden=false, and the object is NOT rendered, then it must have
1378     //     aria-hidden=false on each parent until it gets to a rendered object
1379     //  3b) a text node inherits a parents aria-hidden value
1380     bool requiresAriaHiddenFalse = !node->renderer();
1381     bool ariaHiddenFalsePresent = false;
1382     for (Node* testNode = node; testNode; testNode = testNode->parentNode()) {
1383         if (is<Element>(*testNode)) {
1384             const AtomicString& ariaHiddenValue = downcast<Element>(*testNode).fastGetAttribute(aria_hiddenAttr);
1385             if (equalIgnoringCase(ariaHiddenValue, "true"))
1386                 return false;
1387             
1388             bool ariaHiddenFalse = equalIgnoringCase(ariaHiddenValue, "false");
1389             if (!testNode->renderer() && !ariaHiddenFalse)
1390                 return false;
1391             if (!ariaHiddenFalsePresent && ariaHiddenFalse)
1392                 ariaHiddenFalsePresent = true;
1393         }
1394     }
1395     
1396     return !requiresAriaHiddenFalse || ariaHiddenFalsePresent;
1397 }
1398
1399 AccessibilityObject* AXObjectCache::rootWebArea()
1400 {
1401     AccessibilityObject* rootObject = this->rootObject();
1402     if (!rootObject || !rootObject->isAccessibilityScrollView())
1403         return nullptr;
1404     return downcast<AccessibilityScrollView>(*rootObject).webAreaObject();
1405 }
1406
1407 AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache)
1408     : m_cache(cache)
1409 {
1410     if (m_cache)
1411         m_cache->startCachingComputedObjectAttributesUntilTreeMutates();
1412 }
1413     
1414 AXAttributeCacheEnabler::~AXAttributeCacheEnabler()
1415 {
1416     if (m_cache)
1417         m_cache->stopCachingComputedObjectAttributes();
1418 }
1419
1420 #if !PLATFORM(COCOA)
1421 AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType type)
1422 {
1423     switch (type) {
1424     case AXTextEditTypeCut:
1425     case AXTextEditTypeDelete:
1426         return AXTextDeleted;
1427     case AXTextEditTypeInsert:
1428     case AXTextEditTypeDictation:
1429     case AXTextEditTypeTyping:
1430     case AXTextEditTypePaste:
1431         return AXTextInserted;
1432     case AXTextEditTypeAttributesChange:
1433         return AXTextAttributesChanged;
1434     case AXTextEditTypeUnknown:
1435         break;
1436     }
1437     ASSERT_NOT_REACHED();
1438     return AXTextInserted;
1439 }
1440 #endif
1441     
1442 } // namespace WebCore
1443
1444 #endif // HAVE(ACCESSIBILITY)