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