AX: crash at WebCore::Range::selectNodeContents(WebCore::Node*, int&)
[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 "TextIterator.h"
85 #include <wtf/DataLog.h>
86
87 #if ENABLE(VIDEO)
88 #include "MediaControlElements.h"
89 #endif
90
91 namespace WebCore {
92
93 using namespace HTMLNames;
94
95 // Post value change notifications for password fields or elements contained in password fields at a 40hz interval to thwart analysis of typing cadence
96 static double AccessibilityPasswordValueChangeNotificationInterval = 0.025;
97 static double AccessibilityLiveRegionChangedNotificationInterval = 0.020;
98
99 AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
100 {
101     HashMap<AXID, CachedAXObjectAttributes>::const_iterator it = m_idMapping.find(id);
102     return it != m_idMapping.end() ? it->value.ignored : DefaultBehavior;
103 }
104
105 void AXComputedObjectAttributeCache::setIgnored(AXID id, AccessibilityObjectInclusion inclusion)
106 {
107     HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
108     if (it != m_idMapping.end())
109         it->value.ignored = inclusion;
110     else {
111         CachedAXObjectAttributes attributes;
112         attributes.ignored = inclusion;
113         m_idMapping.set(id, attributes);
114     }
115 }
116     
117 bool AXObjectCache::gAccessibilityEnabled = false;
118 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
119
120 void AXObjectCache::enableAccessibility()
121 {
122     gAccessibilityEnabled = true;
123 }
124
125 void AXObjectCache::disableAccessibility()
126 {
127     gAccessibilityEnabled = false;
128 }
129
130 void AXObjectCache::setEnhancedUserInterfaceAccessibility(bool flag)
131 {
132     gAccessibilityEnhancedUserInterfaceEnabled = flag;
133 #if PLATFORM(MAC)
134 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
135     if (flag)
136         enableAccessibility();
137 #endif
138 #endif
139 }
140
141 AXObjectCache::AXObjectCache(Document& document)
142     : m_document(document)
143     , m_notificationPostTimer(*this, &AXObjectCache::notificationPostTimerFired)
144     , m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired)
145     , m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired)
146     , m_currentAriaModalNode(nullptr)
147 {
148     findAriaModalNodes();
149 }
150
151 AXObjectCache::~AXObjectCache()
152 {
153     m_notificationPostTimer.stop();
154     m_liveRegionChangedPostTimer.stop();
155
156     for (const auto& object : m_objects.values()) {
157         detachWrapper(object.get(), CacheDestroyed);
158         object->detach(CacheDestroyed);
159         removeAXID(object.get());
160     }
161 }
162
163 void AXObjectCache::findAriaModalNodes()
164 {
165     // Traverse the DOM tree to look for the aria-modal=true nodes.
166     for (Element* element = ElementTraversal::firstWithin(document().rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) {
167         
168         // Must have dialog or alertdialog role
169         if (!nodeHasRole(element, "dialog") && !nodeHasRole(element, "alertdialog"))
170             continue;
171         if (!equalLettersIgnoringASCIICase(element->fastGetAttribute(aria_modalAttr), "true"))
172             continue;
173         
174         m_ariaModalNodesSet.add(element);
175     }
176     
177     // Set the current valid aria-modal node if possible.
178     updateCurrentAriaModalNode();
179 }
180
181 void AXObjectCache::updateCurrentAriaModalNode()
182 {
183     // There might be multiple nodes with aria-modal=true set.
184     // We use this function to pick the one we want.
185     m_currentAriaModalNode = nullptr;
186     if (m_ariaModalNodesSet.isEmpty())
187         return;
188     
189     // We only care about the nodes which are visible.
190     ListHashSet<RefPtr<Node>> visibleNodes;
191     for (auto& object : m_ariaModalNodesSet) {
192         if (isNodeVisible(object))
193             visibleNodes.add(object);
194     }
195     
196     if (visibleNodes.isEmpty())
197         return;
198     
199     // If any of the node are keyboard focused, we want to pick that.
200     Node* focusedNode = document().focusedElement();
201     for (auto& object : visibleNodes) {
202         if (focusedNode != nullptr && focusedNode->isDescendantOf(object.get())) {
203             m_currentAriaModalNode = object.get();
204             break;
205         }
206     }
207     
208     // If none of the nodes are focused, we want to pick the last dialog in the DOM.
209     if (!m_currentAriaModalNode)
210         m_currentAriaModalNode = visibleNodes.last().get();
211 }
212
213 bool AXObjectCache::isNodeVisible(Node* node) const
214 {
215     if (!is<Element>(node))
216         return false;
217     
218     RenderObject* renderer = node->renderer();
219     if (!renderer)
220         return false;
221     const RenderStyle& style = renderer->style();
222     if (style.display() == NONE || style.visibility() != VISIBLE)
223         return false;
224     
225     // We also need to consider aria hidden status.
226     if (!isNodeAriaVisible(node))
227         return false;
228     
229     return true;
230 }
231
232 Node* AXObjectCache::ariaModalNode()
233 {
234     // This function returns the valid aria modal node.
235     if (m_ariaModalNodesSet.isEmpty())
236         return nullptr;
237     
238     // Check the current valid aria modal node first.
239     // Usually when one dialog sets aria-modal=true, that dialog is the one we want.
240     if (isNodeVisible(m_currentAriaModalNode))
241         return m_currentAriaModalNode;
242     
243     // Recompute the valid aria modal node when m_currentAriaModalNode is null or hidden.
244     updateCurrentAriaModalNode();
245     return isNodeVisible(m_currentAriaModalNode) ? m_currentAriaModalNode : nullptr;
246 }
247
248 AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
249 {
250     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
251     // in the list of children for its corresponding image.
252     if (!areaElement)
253         return nullptr;
254     
255     HTMLImageElement* imageElement = areaElement->imageElement();
256     if (!imageElement)
257         return nullptr;
258     
259     AccessibilityObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement);
260     if (!axRenderImage)
261         return nullptr;
262     
263     for (const auto& child : axRenderImage->children()) {
264         if (!is<AccessibilityImageMapLink>(*child))
265             continue;
266         
267         if (downcast<AccessibilityImageMapLink>(*child).areaElement() == areaElement)
268             return child.get();
269     }    
270     
271     return nullptr;
272 }
273     
274 AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
275 {
276     if (!gAccessibilityEnabled)
277         return nullptr;
278
279     // get the focused node in the page
280     Document* focusedDocument = page->focusController().focusedOrMainFrame().document();
281     Element* focusedElement = focusedDocument->focusedElement();
282     if (is<HTMLAreaElement>(focusedElement))
283         return focusedImageMapUIElement(downcast<HTMLAreaElement>(focusedElement));
284
285     AccessibilityObject* obj = focusedDocument->axObjectCache()->getOrCreate(focusedElement ? static_cast<Node*>(focusedElement) : focusedDocument);
286     if (!obj)
287         return nullptr;
288
289     if (obj->shouldFocusActiveDescendant()) {
290         if (AccessibilityObject* descendant = obj->activeDescendant())
291             obj = descendant;
292     }
293
294     // the HTML element, for example, is focusable but has an AX object that is ignored
295     if (obj->accessibilityIsIgnored())
296         obj = obj->parentObjectUnignored();
297
298     return obj;
299 }
300
301 AccessibilityObject* AXObjectCache::get(Widget* widget)
302 {
303     if (!widget)
304         return nullptr;
305         
306     AXID axID = m_widgetObjectMapping.get(widget);
307     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
308     if (!axID)
309         return nullptr;
310     
311     return m_objects.get(axID);    
312 }
313     
314 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
315 {
316     if (!renderer)
317         return nullptr;
318     
319     AXID axID = m_renderObjectMapping.get(renderer);
320     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
321     if (!axID)
322         return nullptr;
323
324     return m_objects.get(axID);    
325 }
326
327 AccessibilityObject* AXObjectCache::get(Node* node)
328 {
329     if (!node)
330         return nullptr;
331
332     AXID renderID = node->renderer() ? m_renderObjectMapping.get(node->renderer()) : 0;
333     ASSERT(!HashTraits<AXID>::isDeletedValue(renderID));
334
335     AXID nodeID = m_nodeObjectMapping.get(node);
336     ASSERT(!HashTraits<AXID>::isDeletedValue(nodeID));
337
338     if (node->renderer() && nodeID && !renderID) {
339         // This can happen if an AccessibilityNodeObject is created for a node that's not
340         // rendered, but later something changes and it gets a renderer (like if it's
341         // reparented).
342         remove(nodeID);
343         return nullptr;
344     }
345
346     if (renderID)
347         return m_objects.get(renderID);
348
349     if (!nodeID)
350         return nullptr;
351
352     return m_objects.get(nodeID);
353 }
354
355 // FIXME: This probably belongs on Node.
356 // FIXME: This should take a const char*, but one caller passes nullAtom.
357 bool nodeHasRole(Node* node, const String& role)
358 {
359     if (!node || !is<Element>(node))
360         return false;
361
362     auto& roleValue = downcast<Element>(*node).fastGetAttribute(roleAttr);
363     if (role.isNull())
364         return roleValue.isEmpty();
365     if (roleValue.isEmpty())
366         return false;
367
368     return SpaceSplitString(roleValue, true).contains(role);
369 }
370
371 static Ref<AccessibilityObject> createFromRenderer(RenderObject* renderer)
372 {
373     // FIXME: How could renderer->node() ever not be an Element?
374     Node* node = renderer->node();
375
376     // If the node is aria role="list" or the aria role is empty and its a
377     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
378     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
379                       || (nodeHasRole(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
380         return AccessibilityList::create(renderer);
381
382     // aria tables
383     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid") || nodeHasRole(node, "table"))
384         return AccessibilityARIAGrid::create(renderer);
385     if (nodeHasRole(node, "row"))
386         return AccessibilityARIAGridRow::create(renderer);
387     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "cell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
388         return AccessibilityARIAGridCell::create(renderer);
389
390     // aria tree
391     if (nodeHasRole(node, "tree"))
392         return AccessibilityTree::create(renderer);
393     if (nodeHasRole(node, "treeitem"))
394         return AccessibilityTreeItem::create(renderer);
395
396 #if ENABLE(VIDEO)
397     // media controls
398     if (node && node->isMediaControlElement())
399         return AccessibilityMediaControl::create(renderer);
400 #endif
401
402     if (is<RenderSVGRoot>(*renderer))
403         return AccessibilitySVGRoot::create(renderer);
404     
405     if (is<RenderBoxModelObject>(*renderer)) {
406         RenderBoxModelObject& cssBox = downcast<RenderBoxModelObject>(*renderer);
407         if (is<RenderListBox>(cssBox))
408             return AccessibilityListBox::create(&downcast<RenderListBox>(cssBox));
409         if (is<RenderMenuList>(cssBox))
410             return AccessibilityMenuList::create(&downcast<RenderMenuList>(cssBox));
411
412         // standard tables
413         if (is<RenderTable>(cssBox))
414             return AccessibilityTable::create(&downcast<RenderTable>(cssBox));
415         if (is<RenderTableRow>(cssBox))
416             return AccessibilityTableRow::create(&downcast<RenderTableRow>(cssBox));
417         if (is<RenderTableCell>(cssBox))
418             return AccessibilityTableCell::create(&downcast<RenderTableCell>(cssBox));
419
420         // progress bar
421         if (is<RenderProgress>(cssBox))
422             return AccessibilityProgressIndicator::create(&downcast<RenderProgress>(cssBox));
423
424 #if ENABLE(METER_ELEMENT)
425         if (is<RenderMeter>(cssBox))
426             return AccessibilityProgressIndicator::create(&downcast<RenderMeter>(cssBox));
427 #endif
428
429         // input type=range
430         if (is<RenderSlider>(cssBox))
431             return AccessibilitySlider::create(&downcast<RenderSlider>(cssBox));
432     }
433
434     return AccessibilityRenderObject::create(renderer);
435 }
436
437 static Ref<AccessibilityObject> createFromNode(Node* node)
438 {
439     return AccessibilityNodeObject::create(node);
440 }
441
442 AccessibilityObject* AXObjectCache::getOrCreate(Widget* widget)
443 {
444     if (!widget)
445         return nullptr;
446
447     if (AccessibilityObject* obj = get(widget))
448         return obj;
449     
450     RefPtr<AccessibilityObject> newObj;
451     if (is<ScrollView>(*widget))
452         newObj = AccessibilityScrollView::create(downcast<ScrollView>(widget));
453     else if (is<Scrollbar>(*widget))
454         newObj = AccessibilityScrollbar::create(downcast<Scrollbar>(widget));
455
456     // Will crash later if we have two objects for the same widget.
457     ASSERT(!get(widget));
458
459     // Catch the case if an (unsupported) widget type is used. Only FrameView and ScrollBar are supported now.
460     ASSERT(newObj);
461     if (!newObj)
462         return nullptr;
463
464     getAXID(newObj.get());
465     
466     m_widgetObjectMapping.set(widget, newObj->axObjectID());
467     m_objects.set(newObj->axObjectID(), newObj);    
468     newObj->init();
469     attachWrapper(newObj.get());
470     return newObj.get();
471 }
472
473 AccessibilityObject* AXObjectCache::getOrCreate(Node* node)
474 {
475     if (!node)
476         return nullptr;
477
478     if (AccessibilityObject* obj = get(node))
479         return obj;
480
481     if (node->renderer())
482         return getOrCreate(node->renderer());
483
484     if (!node->parentElement())
485         return nullptr;
486     
487     // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree.
488     // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes.
489     bool inCanvasSubtree = lineageOfType<HTMLCanvasElement>(*node->parentElement()).first();
490     bool isHidden = isNodeAriaVisible(node);
491
492     bool insideMeterElement = false;
493 #if ENABLE(METER_ELEMENT)
494     insideMeterElement = is<HTMLMeterElement>(*node->parentElement());
495 #endif
496     
497     if (!inCanvasSubtree && !isHidden && !insideMeterElement)
498         return nullptr;
499
500     // Fallback content is only focusable as long as the canvas is displayed and visible.
501     // Update the style before Element::isFocusable() gets called.
502     if (inCanvasSubtree)
503         node->document().updateStyleIfNeeded();
504
505     RefPtr<AccessibilityObject> newObj = createFromNode(node);
506
507     // Will crash later if we have two objects for the same node.
508     ASSERT(!get(node));
509
510     getAXID(newObj.get());
511
512     m_nodeObjectMapping.set(node, newObj->axObjectID());
513     m_objects.set(newObj->axObjectID(), newObj);
514     newObj->init();
515     attachWrapper(newObj.get());
516     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
517     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
518     // it will disappear when this function is finished, leading to a use-after-free.
519     if (newObj->isDetached())
520         return nullptr;
521     
522     return newObj.get();
523 }
524
525 AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
526 {
527     if (!renderer)
528         return nullptr;
529
530     if (AccessibilityObject* obj = get(renderer))
531         return obj;
532
533     RefPtr<AccessibilityObject> newObj = createFromRenderer(renderer);
534
535     // Will crash later if we have two objects for the same renderer.
536     ASSERT(!get(renderer));
537
538     getAXID(newObj.get());
539
540     m_renderObjectMapping.set(renderer, newObj->axObjectID());
541     m_objects.set(newObj->axObjectID(), newObj);
542     newObj->init();
543     attachWrapper(newObj.get());
544     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
545     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
546     // it will disappear when this function is finished, leading to a use-after-free.
547     if (newObj->isDetached())
548         return nullptr;
549     
550     return newObj.get();
551 }
552     
553 AccessibilityObject* AXObjectCache::rootObject()
554 {
555     if (!gAccessibilityEnabled)
556         return nullptr;
557
558     return getOrCreate(m_document.view());
559 }
560
561 AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame* frame)
562 {
563     if (!gAccessibilityEnabled)
564         return nullptr;
565
566     if (!frame)
567         return nullptr;
568     return getOrCreate(frame->view());
569 }    
570     
571 AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
572 {
573     RefPtr<AccessibilityObject> obj = nullptr;
574     
575     // will be filled in...
576     switch (role) {
577     case ListBoxOptionRole:
578         obj = AccessibilityListBoxOption::create();
579         break;
580     case ImageMapLinkRole:
581         obj = AccessibilityImageMapLink::create();
582         break;
583     case ColumnRole:
584         obj = AccessibilityTableColumn::create();
585         break;            
586     case TableHeaderContainerRole:
587         obj = AccessibilityTableHeaderContainer::create();
588         break;   
589     case SliderThumbRole:
590         obj = AccessibilitySliderThumb::create();
591         break;
592     case MenuListPopupRole:
593         obj = AccessibilityMenuListPopup::create();
594         break;
595     case MenuListOptionRole:
596         obj = AccessibilityMenuListOption::create();
597         break;
598     case SpinButtonRole:
599         obj = AccessibilitySpinButton::create();
600         break;
601     case SpinButtonPartRole:
602         obj = AccessibilitySpinButtonPart::create();
603         break;
604     default:
605         obj = nullptr;
606     }
607     
608     if (obj)
609         getAXID(obj.get());
610     else
611         return nullptr;
612
613     m_objects.set(obj->axObjectID(), obj);    
614     obj->init();
615     attachWrapper(obj.get());
616     return obj.get();
617 }
618
619 void AXObjectCache::remove(AXID axID)
620 {
621     if (!axID)
622         return;
623     
624     // first fetch object to operate some cleanup functions on it 
625     AccessibilityObject* obj = m_objects.get(axID);
626     if (!obj)
627         return;
628     
629     detachWrapper(obj, ElementDestroyed);
630     obj->detach(ElementDestroyed, this);
631     removeAXID(obj);
632     
633     // finally remove the object
634     if (!m_objects.take(axID))
635         return;
636     
637     ASSERT(m_objects.size() >= m_idsInUse.size());    
638 }
639     
640 void AXObjectCache::remove(RenderObject* renderer)
641 {
642     if (!renderer)
643         return;
644     
645     AXID axID = m_renderObjectMapping.get(renderer);
646     remove(axID);
647     m_renderObjectMapping.remove(renderer);
648 }
649
650 void AXObjectCache::remove(Node* node)
651 {
652     if (!node)
653         return;
654
655     removeNodeForUse(node);
656
657     // This is all safe even if we didn't have a mapping.
658     AXID axID = m_nodeObjectMapping.get(node);
659     remove(axID);
660     m_nodeObjectMapping.remove(node);
661
662     // Cleanup for aria modal nodes.
663     if (m_currentAriaModalNode == node)
664         m_currentAriaModalNode = nullptr;
665     if (m_ariaModalNodesSet.contains(node))
666         m_ariaModalNodesSet.remove(node);
667     
668     if (node->renderer()) {
669         remove(node->renderer());
670         return;
671     }
672 }
673
674 void AXObjectCache::remove(Widget* view)
675 {
676     if (!view)
677         return;
678         
679     AXID axID = m_widgetObjectMapping.get(view);
680     remove(axID);
681     m_widgetObjectMapping.remove(view);
682 }
683     
684     
685 #if !PLATFORM(WIN)
686 AXID AXObjectCache::platformGenerateAXID() const
687 {
688     static AXID lastUsedID = 0;
689
690     // Generate a new ID.
691     AXID objID = lastUsedID;
692     do {
693         ++objID;
694     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
695
696     lastUsedID = objID;
697
698     return objID;
699 }
700 #endif
701
702 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
703 {
704     // check for already-assigned ID
705     AXID objID = obj->axObjectID();
706     if (objID) {
707         ASSERT(m_idsInUse.contains(objID));
708         return objID;
709     }
710
711     objID = platformGenerateAXID();
712
713     m_idsInUse.add(objID);
714     obj->setAXObjectID(objID);
715     
716     return objID;
717 }
718
719 void AXObjectCache::removeAXID(AccessibilityObject* object)
720 {
721     if (!object)
722         return;
723     
724     AXID objID = object->axObjectID();
725     if (!objID)
726         return;
727     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
728     ASSERT(m_idsInUse.contains(objID));
729     object->setAXObjectID(0);
730     m_idsInUse.remove(objID);
731 }
732
733 void AXObjectCache::textChanged(Node* node)
734 {
735     textChanged(getOrCreate(node));
736 }
737
738 void AXObjectCache::textChanged(RenderObject* renderer)
739 {
740     textChanged(getOrCreate(renderer));
741 }
742
743 void AXObjectCache::textChanged(AccessibilityObject* obj)
744 {
745     if (!obj)
746         return;
747
748     bool parentAlreadyExists = obj->parentObjectIfExists();
749     obj->textChanged();
750     postNotification(obj, obj->document(), AXObjectCache::AXTextChanged);
751     if (parentAlreadyExists)
752         obj->notifyIfIgnoredValueChanged();
753 }
754
755 void AXObjectCache::updateCacheAfterNodeIsAttached(Node* node)
756 {
757     // Calling get() will update the AX object if we had an AccessibilityNodeObject but now we need
758     // an AccessibilityRenderObject, because it was reparented to a location outside of a canvas.
759     get(node);
760 }
761
762 void AXObjectCache::handleMenuOpened(Node* node)
763 {
764     if (!node || !node->renderer() || !nodeHasRole(node, "menu"))
765         return;
766     
767     postNotification(getOrCreate(node), &document(), AXMenuOpened);
768 }
769     
770 void AXObjectCache::handleLiveRegionCreated(Node* node)
771 {
772     if (!is<Element>(node) || !node->renderer())
773         return;
774     
775     Element* element = downcast<Element>(node);
776     String liveRegionStatus = element->fastGetAttribute(aria_liveAttr);
777     if (liveRegionStatus.isEmpty()) {
778         const AtomicString& ariaRole = element->fastGetAttribute(roleAttr);
779         if (!ariaRole.isEmpty())
780             liveRegionStatus = AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityObject::ariaRoleToWebCoreRole(ariaRole));
781     }
782     
783     if (AccessibilityObject::liveRegionStatusIsEnabled(liveRegionStatus))
784         postNotification(getOrCreate(node), &document(), AXLiveRegionCreated);
785 }
786     
787 void AXObjectCache::childrenChanged(Node* node, Node* newChild)
788 {
789     if (newChild) {
790         handleMenuOpened(newChild);
791         handleLiveRegionCreated(newChild);
792     }
793     
794     childrenChanged(get(node));
795 }
796
797 void AXObjectCache::childrenChanged(RenderObject* renderer, RenderObject* newChild)
798 {
799     if (!renderer)
800         return;
801     
802     if (newChild) {
803         handleMenuOpened(newChild->node());
804         handleLiveRegionCreated(newChild->node());
805     }
806     
807     childrenChanged(get(renderer));
808 }
809
810 void AXObjectCache::childrenChanged(AccessibilityObject* obj)
811 {
812     if (!obj)
813         return;
814
815     obj->childrenChanged();
816 }
817     
818 void AXObjectCache::notificationPostTimerFired()
819 {
820     Ref<Document> protectorForCacheOwner(m_document);
821     m_notificationPostTimer.stop();
822     
823     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
824     // when the notification list is cleared at the end. Instead copy this list at the start.
825     auto notifications = WTFMove(m_notificationsToPost);
826     
827     for (const auto& note : notifications) {
828         AccessibilityObject* obj = note.first.get();
829         if (!obj->axObjectID())
830             continue;
831
832         if (!obj->axObjectCache())
833             continue;
834         
835 #ifndef NDEBUG
836         // Make sure none of the render views are in the process of being layed out.
837         // Notifications should only be sent after the renderer has finished
838         if (is<AccessibilityRenderObject>(*obj)) {
839             if (auto* renderer = downcast<AccessibilityRenderObject>(*obj).renderer())
840                 ASSERT(!renderer->view().layoutState());
841         }
842 #endif
843
844         AXNotification notification = note.second;
845         
846         // Ensure that this menu really is a menu. We do this check here so that we don't have to create
847         // the axChildren when the menu is marked as opening.
848         if (notification == AXMenuOpened) {
849             obj->updateChildrenIfNecessary();
850             if (obj->roleValue() != MenuRole)
851                 continue;
852         }
853         
854         postPlatformNotification(obj, notification);
855
856         if (notification == AXChildrenChanged && obj->parentObjectIfExists() && obj->lastKnownIsIgnoredValue() != obj->accessibilityIsIgnored())
857             childrenChanged(obj->parentObject());
858     }
859 }
860
861 void AXObjectCache::passwordNotificationPostTimerFired()
862 {
863 #if PLATFORM(COCOA)
864     m_passwordNotificationPostTimer.stop();
865
866     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
867     // when the notification list is cleared at the end. Instead copy this list at the start.
868     auto notifications = WTFMove(m_passwordNotificationsToPost);
869
870     for (auto& notification : notifications)
871         postTextStateChangePlatformNotification(notification.get(), AXTextEditTypeInsert, " ", VisiblePosition());
872 #endif
873 }
874     
875 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, PostTarget postTarget, PostType postType)
876 {
877     if (!renderer)
878         return;
879     
880     stopCachingComputedObjectAttributes();
881
882     // Get an accessibility object that already exists. One should not be created here
883     // because a render update may be in progress and creating an AX object can re-trigger a layout
884     RefPtr<AccessibilityObject> object = get(renderer);
885     while (!object && renderer) {
886         renderer = renderer->parent();
887         object = get(renderer); 
888     }
889     
890     if (!renderer)
891         return;
892     
893     postNotification(object.get(), &renderer->document(), notification, postTarget, postType);
894 }
895
896 void AXObjectCache::postNotification(Node* node, AXNotification notification, PostTarget postTarget, PostType postType)
897 {
898     if (!node)
899         return;
900     
901     stopCachingComputedObjectAttributes();
902
903     // Get an accessibility object that already exists. One should not be created here
904     // because a render update may be in progress and creating an AX object can re-trigger a layout
905     RefPtr<AccessibilityObject> object = get(node);
906     while (!object && node) {
907         node = node->parentNode();
908         object = get(node);
909     }
910     
911     if (!node)
912         return;
913     
914     postNotification(object.get(), &node->document(), notification, postTarget, postType);
915 }
916
917 void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, PostTarget postTarget, PostType postType)
918 {
919     stopCachingComputedObjectAttributes();
920
921     if (object && postTarget == TargetObservableParent)
922         object = object->observableObject();
923
924     if (!object && document)
925         object = get(document->renderView());
926
927     if (!object)
928         return;
929
930     if (postType == PostAsynchronously) {
931         m_notificationsToPost.append(std::make_pair(object, notification));
932         if (!m_notificationPostTimer.isActive())
933             m_notificationPostTimer.startOneShot(0);
934     } else
935         postPlatformNotification(object, notification);
936 }
937
938 void AXObjectCache::checkedStateChanged(Node* node)
939 {
940     postNotification(node, AXObjectCache::AXCheckedStateChanged);
941 }
942
943 void AXObjectCache::handleMenuItemSelected(Node* node)
944 {
945     if (!node)
946         return;
947     
948     if (!nodeHasRole(node, "menuitem") && !nodeHasRole(node, "menuitemradio") && !nodeHasRole(node, "menuitemcheckbox"))
949         return;
950     
951     if (!downcast<Element>(*node).focused() && !equalLettersIgnoringASCIICase(downcast<Element>(*node).fastGetAttribute(aria_selectedAttr), "true"))
952         return;
953     
954     postNotification(getOrCreate(node), &document(), AXMenuListItemSelected);
955 }
956     
957 void AXObjectCache::handleFocusedUIElementChanged(Node* oldNode, Node* newNode)
958 {
959     handleMenuItemSelected(newNode);
960     platformHandleFocusedUIElementChanged(oldNode, newNode);
961 }
962     
963 void AXObjectCache::selectedChildrenChanged(Node* node)
964 {
965     handleMenuItemSelected(node);
966     
967     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
968     // to find the container which should send out the notification.
969     postNotification(node, AXSelectedChildrenChanged, TargetObservableParent);
970 }
971
972 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
973 {
974     if (renderer)
975         handleMenuItemSelected(renderer->node());
976
977     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
978     // to find the container which should send out the notification.
979     postNotification(renderer, AXSelectedChildrenChanged, TargetObservableParent);
980 }
981
982 #ifndef NDEBUG
983 void AXObjectCache::showIntent(const AXTextStateChangeIntent &intent)
984 {
985     switch (intent.type) {
986     case AXTextStateChangeTypeUnknown:
987         dataLog("Unknown");
988         break;
989     case AXTextStateChangeTypeEdit:
990         dataLog("Edit::");
991         break;
992     case AXTextStateChangeTypeSelectionMove:
993         dataLog("Move::");
994         break;
995     case AXTextStateChangeTypeSelectionExtend:
996         dataLog("Extend::");
997         break;
998     case AXTextStateChangeTypeSelectionBoundary:
999         dataLog("Boundary::");
1000         break;
1001     }
1002     switch (intent.type) {
1003     case AXTextStateChangeTypeUnknown:
1004         break;
1005     case AXTextStateChangeTypeEdit:
1006         switch (intent.change) {
1007         case AXTextEditTypeUnknown:
1008             dataLog("Unknown");
1009             break;
1010         case AXTextEditTypeDelete:
1011             dataLog("Delete");
1012             break;
1013         case AXTextEditTypeInsert:
1014             dataLog("Insert");
1015             break;
1016         case AXTextEditTypeDictation:
1017             dataLog("DictationInsert");
1018             break;
1019         case AXTextEditTypeTyping:
1020             dataLog("TypingInsert");
1021             break;
1022         case AXTextEditTypeCut:
1023             dataLog("Cut");
1024             break;
1025         case AXTextEditTypePaste:
1026             dataLog("Paste");
1027             break;
1028         case AXTextEditTypeAttributesChange:
1029             dataLog("AttributesChange");
1030             break;
1031         }
1032         break;
1033     case AXTextStateChangeTypeSelectionMove:
1034     case AXTextStateChangeTypeSelectionExtend:
1035     case AXTextStateChangeTypeSelectionBoundary:
1036         switch (intent.selection.direction) {
1037         case AXTextSelectionDirectionUnknown:
1038             dataLog("Unknown::");
1039             break;
1040         case AXTextSelectionDirectionBeginning:
1041             dataLog("Beginning::");
1042             break;
1043         case AXTextSelectionDirectionEnd:
1044             dataLog("End::");
1045             break;
1046         case AXTextSelectionDirectionPrevious:
1047             dataLog("Previous::");
1048             break;
1049         case AXTextSelectionDirectionNext:
1050             dataLog("Next::");
1051             break;
1052         case AXTextSelectionDirectionDiscontiguous:
1053             dataLog("Discontiguous::");
1054             break;
1055         }
1056         switch (intent.selection.direction) {
1057         case AXTextSelectionDirectionUnknown:
1058         case AXTextSelectionDirectionBeginning:
1059         case AXTextSelectionDirectionEnd:
1060         case AXTextSelectionDirectionPrevious:
1061         case AXTextSelectionDirectionNext:
1062             switch (intent.selection.granularity) {
1063             case AXTextSelectionGranularityUnknown:
1064                 dataLog("Unknown");
1065                 break;
1066             case AXTextSelectionGranularityCharacter:
1067                 dataLog("Character");
1068                 break;
1069             case AXTextSelectionGranularityWord:
1070                 dataLog("Word");
1071                 break;
1072             case AXTextSelectionGranularityLine:
1073                 dataLog("Line");
1074                 break;
1075             case AXTextSelectionGranularitySentence:
1076                 dataLog("Sentence");
1077                 break;
1078             case AXTextSelectionGranularityParagraph:
1079                 dataLog("Paragraph");
1080                 break;
1081             case AXTextSelectionGranularityPage:
1082                 dataLog("Page");
1083                 break;
1084             case AXTextSelectionGranularityDocument:
1085                 dataLog("Document");
1086                 break;
1087             case AXTextSelectionGranularityAll:
1088                 dataLog("All");
1089                 break;
1090             }
1091             break;
1092         case AXTextSelectionDirectionDiscontiguous:
1093             break;
1094         }
1095         break;
1096     }
1097     dataLog("\n");
1098 }
1099 #endif
1100
1101 void AXObjectCache::setTextSelectionIntent(const AXTextStateChangeIntent& intent)
1102 {
1103     m_textSelectionIntent = intent;
1104 }
1105     
1106 void AXObjectCache::setIsSynchronizingSelection(bool isSynchronizing)
1107 {
1108     m_isSynchronizingSelection = isSynchronizing;
1109 }
1110
1111 static bool isPasswordFieldOrContainedByPasswordField(AccessibilityObject* object)
1112 {
1113     return object && (object->isPasswordField() || object->isContainedByPasswordField());
1114 }
1115
1116 void AXObjectCache::postTextStateChangeNotification(Node* node, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1117 {
1118     if (!node)
1119         return;
1120
1121 #if PLATFORM(COCOA)
1122     stopCachingComputedObjectAttributes();
1123
1124     postTextStateChangeNotification(getOrCreate(node), intent, selection);
1125 #else
1126     postNotification(node->renderer(), AXObjectCache::AXSelectedTextChanged, TargetObservableParent);
1127     UNUSED_PARAM(intent);
1128     UNUSED_PARAM(selection);
1129 #endif
1130 }
1131
1132 void AXObjectCache::postTextStateChangeNotification(const Position& position, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1133 {
1134     Node* node = position.deprecatedNode();
1135     if (!node)
1136         return;
1137
1138     stopCachingComputedObjectAttributes();
1139
1140 #if PLATFORM(COCOA)
1141     AccessibilityObject* object = getOrCreate(node);
1142     if (object && object->accessibilityIsIgnored()) {
1143         if (position.atLastEditingPositionForNode()) {
1144             if (AccessibilityObject* nextSibling = object->nextSiblingUnignored(1))
1145                 object = nextSibling;
1146         } else if (position.atFirstEditingPositionForNode()) {
1147             if (AccessibilityObject* previousSibling = object->previousSiblingUnignored(1))
1148                 object = previousSibling;
1149         }
1150     }
1151
1152     postTextStateChangeNotification(object, intent, selection);
1153 #else
1154     postTextStateChangeNotification(node, intent, selection);
1155 #endif
1156 }
1157
1158 void AXObjectCache::postTextStateChangeNotification(AccessibilityObject* object, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1159 {
1160     stopCachingComputedObjectAttributes();
1161
1162 #if PLATFORM(COCOA)
1163     if (object) {
1164         if (isPasswordFieldOrContainedByPasswordField(object))
1165             return;
1166
1167         if (auto observableObject = object->observableObject())
1168             object = observableObject;
1169     }
1170
1171     const AXTextStateChangeIntent& newIntent = (intent.type == AXTextStateChangeTypeUnknown || (m_isSynchronizingSelection && m_textSelectionIntent.type != AXTextStateChangeTypeUnknown)) ? m_textSelectionIntent : intent;
1172     postTextStateChangePlatformNotification(object, newIntent, selection);
1173 #else
1174     UNUSED_PARAM(object);
1175     UNUSED_PARAM(intent);
1176     UNUSED_PARAM(selection);
1177 #endif
1178
1179     setTextSelectionIntent(AXTextStateChangeIntent());
1180     setIsSynchronizingSelection(false);
1181 }
1182
1183 void AXObjectCache::postTextStateChangeNotification(Node* node, AXTextEditType type, const String& text, const VisiblePosition& position)
1184 {
1185     if (!node)
1186         return;
1187     ASSERT(type != AXTextEditTypeUnknown);
1188
1189     stopCachingComputedObjectAttributes();
1190
1191     AccessibilityObject* object = getOrCreate(node);
1192 #if PLATFORM(COCOA)
1193     if (object) {
1194         if (enqueuePasswordValueChangeNotification(object))
1195             return;
1196         object = object->observableObject();
1197     }
1198
1199     postTextStateChangePlatformNotification(object, type, text, position);
1200 #else
1201     nodeTextChangePlatformNotification(object, textChangeForEditType(type), position.deepEquivalent().deprecatedEditingOffset(), text);
1202 #endif
1203 }
1204
1205 void AXObjectCache::postTextReplacementNotification(Node* node, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition& position)
1206 {
1207     if (!node)
1208         return;
1209     ASSERT(deletionType == AXTextEditTypeDelete);
1210     ASSERT(insertionType == AXTextEditTypeInsert || insertionType == AXTextEditTypeTyping || insertionType == AXTextEditTypeDictation || insertionType == AXTextEditTypePaste);
1211
1212     stopCachingComputedObjectAttributes();
1213
1214     AccessibilityObject* object = getOrCreate(node);
1215 #if PLATFORM(COCOA)
1216     if (object) {
1217         if (enqueuePasswordValueChangeNotification(object))
1218             return;
1219         object = object->observableObject();
1220     }
1221
1222     postTextReplacementPlatformNotification(object, deletionType, deletedText, insertionType, insertedText, position);
1223 #else
1224     nodeTextChangePlatformNotification(object, textChangeForEditType(deletionType), position.deepEquivalent().deprecatedEditingOffset(), deletedText);
1225     nodeTextChangePlatformNotification(object, textChangeForEditType(insertionType), position.deepEquivalent().deprecatedEditingOffset(), insertedText);
1226 #endif
1227 }
1228
1229 bool AXObjectCache::enqueuePasswordValueChangeNotification(AccessibilityObject* object)
1230 {
1231     if (!isPasswordFieldOrContainedByPasswordField(object))
1232         return false;
1233
1234     AccessibilityObject* observableObject = object->observableObject();
1235     if (!observableObject) {
1236         ASSERT_NOT_REACHED();
1237         // return true even though the enqueue didn't happen because this is a password field and caller shouldn't post a notification
1238         return true;
1239     }
1240
1241     m_passwordNotificationsToPost.add(observableObject);
1242     if (!m_passwordNotificationPostTimer.isActive())
1243         m_passwordNotificationPostTimer.startOneShot(AccessibilityPasswordValueChangeNotificationInterval);
1244
1245     return true;
1246 }
1247
1248 void AXObjectCache::frameLoadingEventNotification(Frame* frame, AXLoadingEvent loadingEvent)
1249 {
1250     if (!frame)
1251         return;
1252
1253     // Delegate on the right platform
1254     RenderView* contentRenderer = frame->contentRenderer();
1255     if (!contentRenderer)
1256         return;
1257
1258     AccessibilityObject* obj = getOrCreate(contentRenderer);
1259     frameLoadingEventPlatformNotification(obj, loadingEvent);
1260 }
1261
1262 void AXObjectCache::postLiveRegionChangeNotification(AccessibilityObject* object)
1263 {
1264     if (m_liveRegionChangedPostTimer.isActive())
1265         m_liveRegionChangedPostTimer.stop();
1266
1267     if (!m_liveRegionObjectsSet.contains(object))
1268         m_liveRegionObjectsSet.add(object);
1269
1270     m_liveRegionChangedPostTimer.startOneShot(AccessibilityLiveRegionChangedNotificationInterval);
1271 }
1272
1273 void AXObjectCache::liveRegionChangedNotificationPostTimerFired()
1274 {
1275     m_liveRegionChangedPostTimer.stop();
1276
1277     if (m_liveRegionObjectsSet.isEmpty())
1278         return;
1279
1280     for (auto& object : m_liveRegionObjectsSet)
1281         postNotification(object.get(), object->document(), AXObjectCache::AXLiveRegionChanged);
1282     m_liveRegionObjectsSet.clear();
1283 }
1284
1285 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
1286 {
1287     if (!view)
1288         return;
1289     
1290     // We don't want to create a scroll view from this method, only update an existing one.
1291     if (AccessibilityObject* scrollViewObject = get(view)) {
1292         stopCachingComputedObjectAttributes();
1293         scrollViewObject->updateChildrenIfNecessary();
1294     }
1295 }
1296     
1297 void AXObjectCache::handleAriaExpandedChange(Node* node)
1298 {
1299     if (AccessibilityObject* obj = getOrCreate(node))
1300         obj->handleAriaExpandedChanged();
1301 }
1302     
1303 void AXObjectCache::handleActiveDescendantChanged(Node* node)
1304 {
1305     if (AccessibilityObject* obj = getOrCreate(node))
1306         obj->handleActiveDescendantChanged();
1307 }
1308
1309 void AXObjectCache::handleAriaRoleChanged(Node* node)
1310 {
1311     stopCachingComputedObjectAttributes();
1312
1313     if (AccessibilityObject* obj = getOrCreate(node)) {
1314         obj->updateAccessibilityRole();
1315         obj->notifyIfIgnoredValueChanged();
1316     }
1317 }
1318
1319 void AXObjectCache::handleAttributeChanged(const QualifiedName& attrName, Element* element)
1320 {
1321     if (attrName == roleAttr)
1322         handleAriaRoleChanged(element);
1323     else if (attrName == altAttr || attrName == titleAttr)
1324         textChanged(element);
1325     else if (attrName == forAttr && is<HTMLLabelElement>(*element))
1326         labelChanged(element);
1327
1328     if (!attrName.localName().string().startsWith("aria-"))
1329         return;
1330
1331     if (attrName == aria_activedescendantAttr)
1332         handleActiveDescendantChanged(element);
1333     else if (attrName == aria_busyAttr)
1334         postNotification(element, AXObjectCache::AXElementBusyChanged);
1335     else if (attrName == aria_valuenowAttr || attrName == aria_valuetextAttr)
1336         postNotification(element, AXObjectCache::AXValueChanged);
1337     else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr)
1338         textChanged(element);
1339     else if (attrName == aria_checkedAttr)
1340         checkedStateChanged(element);
1341     else if (attrName == aria_selectedAttr)
1342         selectedChildrenChanged(element);
1343     else if (attrName == aria_expandedAttr)
1344         handleAriaExpandedChange(element);
1345     else if (attrName == aria_hiddenAttr)
1346         childrenChanged(element->parentNode(), element);
1347     else if (attrName == aria_invalidAttr)
1348         postNotification(element, AXObjectCache::AXInvalidStatusChanged);
1349     else if (attrName == aria_modalAttr)
1350         handleAriaModalChange(element);
1351     else
1352         postNotification(element, AXObjectCache::AXAriaAttributeChanged);
1353 }
1354
1355 void AXObjectCache::handleAriaModalChange(Node* node)
1356 {
1357     if (!is<Element>(node))
1358         return;
1359     
1360     if (!nodeHasRole(node, "dialog") && !nodeHasRole(node, "alertdialog"))
1361         return;
1362     
1363     stopCachingComputedObjectAttributes();
1364     if (equalLettersIgnoringASCIICase(downcast<Element>(*node).fastGetAttribute(aria_modalAttr), "true")) {
1365         // Add the newly modified node to the modal nodes set, and set it to be the current valid aria modal node.
1366         // We will recompute the current valid aria modal node in ariaModalNode() when this node is not visible.
1367         m_ariaModalNodesSet.add(node);
1368         m_currentAriaModalNode = node;
1369     } else {
1370         // Remove the node from the modal nodes set. There might be other visible modal nodes, so we recompute here.
1371         m_ariaModalNodesSet.remove(node);
1372         updateCurrentAriaModalNode();
1373     }
1374     startCachingComputedObjectAttributesUntilTreeMutates();
1375 }
1376
1377 void AXObjectCache::labelChanged(Element* element)
1378 {
1379     ASSERT(is<HTMLLabelElement>(*element));
1380     HTMLElement* correspondingControl = downcast<HTMLLabelElement>(*element).control();
1381     textChanged(correspondingControl);
1382 }
1383
1384 void AXObjectCache::recomputeIsIgnored(RenderObject* renderer)
1385 {
1386     if (AccessibilityObject* obj = get(renderer))
1387         obj->notifyIfIgnoredValueChanged();
1388 }
1389
1390 void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates()
1391 {
1392     if (!m_computedObjectAttributeCache)
1393         m_computedObjectAttributeCache = std::make_unique<AXComputedObjectAttributeCache>();
1394 }
1395
1396 void AXObjectCache::stopCachingComputedObjectAttributes()
1397 {
1398     m_computedObjectAttributeCache = nullptr;
1399 }
1400
1401 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
1402 {
1403     if (!isNodeInUse(textMarkerData.node))
1404         return VisiblePosition();
1405     
1406     // FIXME: Accessability should make it clear these are DOM-compliant offsets or store Position objects.
1407     VisiblePosition visiblePos = VisiblePosition(createLegacyEditingPosition(textMarkerData.node, textMarkerData.offset), textMarkerData.affinity);
1408     Position deepPos = visiblePos.deepEquivalent();
1409     if (deepPos.isNull())
1410         return VisiblePosition();
1411     
1412     RenderObject* renderer = deepPos.deprecatedNode()->renderer();
1413     if (!renderer)
1414         return VisiblePosition();
1415     
1416     AXObjectCache* cache = renderer->document().axObjectCache();
1417     if (!cache->isIDinUse(textMarkerData.axID))
1418         return VisiblePosition();
1419     
1420     if (deepPos.deprecatedNode() != textMarkerData.node || deepPos.deprecatedEditingOffset() != textMarkerData.offset)
1421         return VisiblePosition();
1422     
1423     return visiblePos;
1424 }
1425
1426 CharacterOffset AXObjectCache::characterOffsetForTextMarkerData(TextMarkerData& textMarkerData)
1427 {
1428     if (!isNodeInUse(textMarkerData.node))
1429         return CharacterOffset();
1430     
1431     if (textMarkerData.ignored)
1432         return CharacterOffset();
1433     
1434     return CharacterOffset(textMarkerData.node, textMarkerData.characterStartIndex, textMarkerData.characterOffset);
1435 }
1436
1437 CharacterOffset AXObjectCache::traverseToOffsetInRange(RefPtr<Range>range, int offset, bool toNodeEnd, bool stayWithinRange)
1438 {
1439     if (!range)
1440         return CharacterOffset();
1441     
1442     int offsetInCharacter = 0;
1443     int offsetSoFar = 0;
1444     int remaining = 0;
1445     int lastLength = 0;
1446     Node* currentNode = nullptr;
1447     bool finished = false;
1448     int lastStartOffset = 0;
1449     
1450     TextIterator iterator(range.get());
1451     
1452     // When the range has zero length, there might be replaced node or brTag that we need to increment the characterOffset.
1453     if (iterator.atEnd()) {
1454         currentNode = &range->startContainer();
1455         lastStartOffset = range->startOffset();
1456         if (offset > 0 || toNodeEnd) {
1457             if (AccessibilityObject::replacedNodeNeedsCharacter(currentNode) || (currentNode->renderer() && currentNode->renderer()->isBR()))
1458                 offsetSoFar++;
1459             lastLength = offsetSoFar;
1460             
1461             // When going backwards, stayWithinRange is false.
1462             // Here when we don't have any character to move and we are going backwards, we traverse to the previous node.
1463             if (!lastLength && toNodeEnd && !stayWithinRange) {
1464                 if (Node* preNode = previousNode(currentNode))
1465                     return traverseToOffsetInRange(rangeForNodeContents(preNode), offset, toNodeEnd);
1466                 return CharacterOffset();
1467             }
1468         }
1469     }
1470     
1471     for (; !iterator.atEnd(); iterator.advance()) {
1472         int currentLength = iterator.text().length();
1473         
1474         Node& node = iterator.range()->startContainer();
1475         currentNode = &node;
1476         // When currentLength == 0, we check if there's any replaced node.
1477         // If not, we skip the node with no length.
1478         if (!currentLength) {
1479             int subOffset = iterator.range()->startOffset();
1480             Node* childNode = node.traverseToChildAt(subOffset);
1481             if (AccessibilityObject::replacedNodeNeedsCharacter(childNode)) {
1482                 offsetSoFar++;
1483                 currentLength++;
1484                 currentNode = childNode;
1485             } else
1486                 continue;
1487         } else {
1488             // Ignore space, new line, tag node.
1489             if (currentLength == 1 && isSpaceOrNewline(iterator.text()[0]))
1490                 continue;
1491             offsetSoFar += currentLength;
1492         }
1493
1494         lastLength = currentLength;
1495         lastStartOffset = iterator.range()->startOffset();
1496         
1497         // Break early if we have advanced enough characters.
1498         if (!toNodeEnd && offsetSoFar >= offset) {
1499             offsetInCharacter = offset - (offsetSoFar - currentLength);
1500             finished = true;
1501             break;
1502         }
1503     }
1504     
1505     if (!finished) {
1506         offsetInCharacter = lastLength;
1507         if (!toNodeEnd)
1508             remaining = offset - offsetSoFar;
1509     }
1510     
1511     return CharacterOffset(currentNode, lastStartOffset, offsetInCharacter, remaining);
1512 }
1513
1514 int AXObjectCache::lengthForRange(Range* range)
1515 {
1516     if (!range)
1517         return -1;
1518     
1519     int length = 0;
1520     for (TextIterator it(range); !it.atEnd(); it.advance()) {
1521         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1522         if (it.text().length())
1523             length += it.text().length();
1524         else {
1525             // locate the node and starting offset for this replaced range
1526             Node& node = it.range()->startContainer();
1527             int offset = it.range()->startOffset();
1528             if (AccessibilityObject::replacedNodeNeedsCharacter(node.traverseToChildAt(offset)))
1529                 ++length;
1530         }
1531     }
1532         
1533     return length;
1534 }
1535
1536 RefPtr<Range> AXObjectCache::rangeForNodeContents(Node* node)
1537 {
1538     if (!node)
1539         return nullptr;
1540     
1541     Document* document = &node->document();
1542     if (!document)
1543         return nullptr;
1544     RefPtr<Range> range = Range::create(*document);
1545     ExceptionCode ec = 0;
1546     range->selectNodeContents(node, ec);
1547     return ec ? nullptr : range;
1548 }
1549
1550 static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
1551 {
1552     if (characterOffset1.isNull() || characterOffset2.isNull())
1553         return false;
1554     
1555     if (characterOffset1.node == characterOffset2.node)
1556         return characterOffset1.offset <= characterOffset2.offset;
1557     
1558     RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(characterOffset1.node);
1559     RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(characterOffset2.node);
1560     return range1->compareBoundaryPoints(Range::START_TO_START, range2.get(), IGNORE_EXCEPTION) <= 0;
1561 }
1562
1563 static Node* resetNodeAndOffsetForReplacedNode(Node* replacedNode, int& offset, int characterCount)
1564 {
1565     // Use this function to include the replaced node itself in the range we are creating.
1566     if (!replacedNode)
1567         return nullptr;
1568     
1569     RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(replacedNode);
1570     int nodeLength = TextIterator::rangeLength(nodeRange.get());
1571     offset = characterCount <= nodeLength ? replacedNode->computeNodeIndex() : replacedNode->computeNodeIndex() + 1;
1572     return replacedNode->parentNode();
1573 }
1574
1575 static bool isReplacedNodeOrBR(Node* node)
1576 {
1577     return AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag);
1578 }
1579
1580 RefPtr<Range> AXObjectCache::rangeForUnorderedCharacterOffsets(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
1581 {
1582     if (characterOffset1.isNull() || characterOffset2.isNull())
1583         return nullptr;
1584     
1585     bool alreadyInOrder = characterOffsetsInOrder(characterOffset1, characterOffset2);
1586     CharacterOffset startCharacterOffset = alreadyInOrder ? characterOffset1 : characterOffset2;
1587     CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1;
1588     
1589     int startOffset = startCharacterOffset.startIndex + startCharacterOffset.offset;
1590     int endOffset = endCharacterOffset.startIndex + endCharacterOffset.offset;
1591     Node* startNode = startCharacterOffset.node;
1592     Node* endNode = endCharacterOffset.node;
1593     
1594     // Consider the case when the replaced node is at the start/end of the range.
1595     bool startNodeIsReplacedOrBR = isReplacedNodeOrBR(startNode);
1596     bool endNodeIsReplacedOrBR = isReplacedNodeOrBR(endNode);
1597     if (startNodeIsReplacedOrBR || endNodeIsReplacedOrBR) {
1598         // endOffset can be out of bounds sometimes if the node is a replaced node or has brTag and it has no children.
1599         if (startNode == endNode && !startNode->hasChildNodes()) {
1600             RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(startNode);
1601             int nodeLength = TextIterator::rangeLength(nodeRange.get());
1602             if (endCharacterOffset.offset > nodeLength)
1603                 endOffset = endCharacterOffset.startIndex + nodeLength;
1604         } else {
1605             if (startNodeIsReplacedOrBR)
1606                 startNode = resetNodeAndOffsetForReplacedNode(startNode, startOffset, startCharacterOffset.offset);
1607             if (endNodeIsReplacedOrBR)
1608                 endNode = resetNodeAndOffsetForReplacedNode(startNode, endOffset, startCharacterOffset.offset);
1609         }
1610     }
1611     
1612     RefPtr<Range> result = Range::create(m_document);
1613     ExceptionCode ecStart = 0, ecEnd = 0;
1614     result->setStart(startNode, startOffset, ecStart);
1615     result->setEnd(endNode, endOffset, ecEnd);
1616     if (ecStart || ecEnd)
1617         return nullptr;
1618     
1619     return result;
1620 }
1621
1622 void AXObjectCache::setTextMarkerDataWithCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
1623 {
1624     if (characterOffset.isNull())
1625         return;
1626     
1627     Node* domNode = characterOffset.node;
1628     if (is<HTMLInputElement>(*domNode) && downcast<HTMLInputElement>(*domNode).isPasswordField()) {
1629         textMarkerData.ignored = true;
1630         return;
1631     }
1632     
1633     RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
1634     if (!obj)
1635         return;
1636     
1637     // Convert to visible position.
1638     VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(obj.get(), characterOffset);
1639     int vpOffset = 0;
1640     if (!visiblePosition.isNull()) {
1641         Position deepPos = visiblePosition.deepEquivalent();
1642         vpOffset = deepPos.deprecatedEditingOffset();
1643     }
1644     
1645     textMarkerData.axID = obj.get()->axObjectID();
1646     textMarkerData.node = domNode;
1647     textMarkerData.characterOffset = characterOffset.offset;
1648     textMarkerData.characterStartIndex = characterOffset.startIndex;
1649     textMarkerData.offset = vpOffset;
1650     textMarkerData.affinity = visiblePosition.affinity();
1651     
1652     this->setNodeInUse(domNode);
1653 }
1654
1655 void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
1656 {
1657     memset(&textMarkerData, 0, sizeof(TextMarkerData));
1658     
1659     if (!range)
1660         return;
1661     
1662     // If it's end text marker, we want to go to the end of the range, and stay within the range.
1663     bool stayWithinRange = !isStart;
1664     
1665     // Change the start of the range, so the character offset starts from node beginning.
1666     int offset = 0;
1667     Node* node = &range->startContainer();
1668     if (node->offsetInCharacters()) {
1669         CharacterOffset nodeStartOffset = traverseToOffsetInRange(rangeForNodeContents(node), 0, false);
1670         offset = std::max(range->startOffset() - nodeStartOffset.startIndex, 0);
1671         range->setStart(node, nodeStartOffset.startIndex);
1672     }
1673     
1674     CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, !isStart, stayWithinRange);
1675     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
1676 }
1677
1678 void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, Node& node, int offset, bool toNodeEnd)
1679 {
1680     memset(&textMarkerData, 0, sizeof(TextMarkerData));
1681     
1682     Node* domNode = &node;
1683     if (!domNode)
1684         return;
1685     
1686     // If offset <= 0, means we want to go to the previous node.
1687     if (offset <= 0 && !toNodeEnd) {
1688         // Set the offset to the amount of characters we need to go backwards.
1689         offset = - offset + 1;
1690         while (offset > 0 && textMarkerData.characterOffset <= offset) {
1691             offset -= textMarkerData.characterOffset;
1692             domNode = previousNode(domNode);
1693             if (domNode) {
1694                 textMarkerDataForCharacterOffset(textMarkerData, *domNode, 0, true);
1695                 offset--;
1696             } else
1697                 return;
1698         }
1699         if (offset > 0)
1700             textMarkerDataForCharacterOffset(textMarkerData, *domNode, offset, false);
1701         return;
1702     }
1703     
1704     RefPtr<Range> range = rangeForNodeContents(domNode);
1705
1706     // Traverse the offset amount of characters forward and see if there's remaining offsets.
1707     // Keep traversing to the next node when there's remaining offsets.
1708     CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, toNodeEnd);
1709     while (!characterOffset.isNull() && characterOffset.remaining() && !toNodeEnd) {
1710         domNode = nextNode(domNode);
1711         if (!domNode)
1712             return;
1713         range = rangeForNodeContents(domNode);
1714         characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), toNodeEnd);
1715     }
1716     
1717     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
1718 }
1719
1720 Node* AXObjectCache::nextNode(Node* node) const
1721 {
1722     if (!node)
1723         return nullptr;
1724     
1725     return NodeTraversal::nextSkippingChildren(*node);
1726 }
1727
1728 Node* AXObjectCache::previousNode(Node* node) const
1729 {
1730     if (!node)
1731         return nullptr;
1732     
1733     // First child of body shouldn't have previous node.
1734     if (node->parentNode() && node->parentNode()->renderer() && node->parentNode()->renderer()->isBody() && !node->previousSibling())
1735         return nullptr;
1736
1737     return NodeTraversal::previousSkippingChildren(*node);
1738 }
1739
1740 VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(AccessibilityObject* obj, const CharacterOffset& characterOffset)
1741 {
1742     if (!obj)
1743         return VisiblePosition();
1744     
1745     // nextVisiblePosition means advancing one character. Use this to calculate the character offset.
1746     VisiblePositionRange vpRange = obj->visiblePositionRange();
1747     VisiblePosition start = vpRange.start;
1748     VisiblePosition result = start;
1749     for (int i = 0; i < characterOffset.offset; i++)
1750         result = obj->nextVisiblePosition(result);
1751     
1752     return result;
1753 }
1754
1755 CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(AccessibilityObject* obj, const VisiblePosition& visiblePos)
1756 {
1757     if (!obj)
1758         return 0;
1759     
1760     // Use nextVisiblePosition to calculate how many characters we need to traverse to the current position.
1761     Position deepPos = visiblePos.deepEquivalent();
1762     VisiblePositionRange vpRange = obj->visiblePositionRange();
1763     VisiblePosition vp = vpRange.start;
1764     int characterOffset = 0;
1765     Position vpDeepPos = vp.deepEquivalent();
1766     
1767     VisiblePosition previousVisiblePos;
1768     while (!vpDeepPos.isNull() && !deepPos.equals(vpDeepPos)) {
1769         previousVisiblePos = vp;
1770         vp = obj->nextVisiblePosition(vp);
1771         vpDeepPos = vp.deepEquivalent();
1772         // Sometimes nextVisiblePosition will give the same VisiblePostion,
1773         // we break here to avoid infinite loop.
1774         if (vpDeepPos.equals(previousVisiblePos.deepEquivalent()))
1775             break;
1776         characterOffset++;
1777     }
1778     
1779     return traverseToOffsetInRange(rangeForNodeContents(obj->node()), characterOffset, false);
1780 }
1781
1782 AccessibilityObject* AXObjectCache::accessibilityObjectForTextMarkerData(TextMarkerData& textMarkerData)
1783 {
1784     if (!isNodeInUse(textMarkerData.node))
1785         return nullptr;
1786     
1787     Node* domNode = textMarkerData.node;
1788     return this->getOrCreate(domNode);
1789 }
1790
1791 void AXObjectCache::textMarkerDataForVisiblePosition(TextMarkerData& textMarkerData, const VisiblePosition& visiblePos)
1792 {
1793     // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
1794     // This also allows callers to check for failure by looking at textMarkerData upon return.
1795     memset(&textMarkerData, 0, sizeof(TextMarkerData));
1796     
1797     if (visiblePos.isNull())
1798         return;
1799     
1800     Position deepPos = visiblePos.deepEquivalent();
1801     Node* domNode = deepPos.deprecatedNode();
1802     ASSERT(domNode);
1803     if (!domNode)
1804         return;
1805     
1806     if (is<HTMLInputElement>(*domNode) && downcast<HTMLInputElement>(*domNode).isPasswordField())
1807         return;
1808     
1809     // find or create an accessibility object for this node
1810     AXObjectCache* cache = domNode->document().axObjectCache();
1811     RefPtr<AccessibilityObject> obj = cache->getOrCreate(domNode);
1812     
1813     textMarkerData.axID = obj.get()->axObjectID();
1814     textMarkerData.node = domNode;
1815     textMarkerData.offset = deepPos.deprecatedEditingOffset();
1816     textMarkerData.affinity = visiblePos.affinity();
1817     
1818     // convert to character offset
1819     CharacterOffset characterOffset = characterOffsetFromVisiblePosition(obj.get(), visiblePos);
1820     textMarkerData.characterOffset = characterOffset.offset;
1821     textMarkerData.characterStartIndex = characterOffset.startIndex;
1822     
1823     cache->setNodeInUse(domNode);
1824 }
1825
1826 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
1827 {
1828     const Element* result = node->rootEditableElement();
1829     const Element* element = is<Element>(*node) ? downcast<Element>(node) : node->parentElement();
1830
1831     for (; element; element = element->parentElement()) {
1832         if (nodeIsTextControl(element))
1833             result = element;
1834     }
1835
1836     return result;
1837 }
1838
1839 void AXObjectCache::clearTextMarkerNodesInUse(Document* document)
1840 {
1841     if (!document)
1842         return;
1843     
1844     // Check each node to see if it's inside the document being deleted, of if it no longer belongs to a document.
1845     HashSet<Node*> nodesToDelete;
1846     for (const auto& node : m_textMarkerNodes) {
1847         if (!node->inDocument() || &(node)->document() == document)
1848             nodesToDelete.add(node);
1849     }
1850     
1851     for (const auto& node : nodesToDelete)
1852         m_textMarkerNodes.remove(node);
1853 }
1854     
1855 bool AXObjectCache::nodeIsTextControl(const Node* node)
1856 {
1857     if (!node)
1858         return false;
1859
1860     const AccessibilityObject* axObject = getOrCreate(const_cast<Node*>(node));
1861     return axObject && axObject->isTextControl();
1862 }
1863     
1864 bool isNodeAriaVisible(Node* node)
1865 {
1866     if (!node)
1867         return false;
1868
1869     // ARIA Node visibility is controlled by aria-hidden
1870     //  1) if aria-hidden=true, the whole subtree is hidden
1871     //  2) if aria-hidden=false, and the object is rendered, there's no effect
1872     //  3) if aria-hidden=false, and the object is NOT rendered, then it must have
1873     //     aria-hidden=false on each parent until it gets to a rendered object
1874     //  3b) a text node inherits a parents aria-hidden value
1875     bool requiresAriaHiddenFalse = !node->renderer();
1876     bool ariaHiddenFalsePresent = false;
1877     for (Node* testNode = node; testNode; testNode = testNode->parentNode()) {
1878         if (is<Element>(*testNode)) {
1879             const AtomicString& ariaHiddenValue = downcast<Element>(*testNode).fastGetAttribute(aria_hiddenAttr);
1880             if (equalLettersIgnoringASCIICase(ariaHiddenValue, "true"))
1881                 return false;
1882             
1883             bool ariaHiddenFalse = equalLettersIgnoringASCIICase(ariaHiddenValue, "false");
1884             if (!testNode->renderer() && !ariaHiddenFalse)
1885                 return false;
1886             if (!ariaHiddenFalsePresent && ariaHiddenFalse)
1887                 ariaHiddenFalsePresent = true;
1888         }
1889     }
1890     
1891     return !requiresAriaHiddenFalse || ariaHiddenFalsePresent;
1892 }
1893
1894 AccessibilityObject* AXObjectCache::rootWebArea()
1895 {
1896     AccessibilityObject* rootObject = this->rootObject();
1897     if (!rootObject || !rootObject->isAccessibilityScrollView())
1898         return nullptr;
1899     return downcast<AccessibilityScrollView>(*rootObject).webAreaObject();
1900 }
1901
1902 AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache)
1903     : m_cache(cache)
1904 {
1905     if (m_cache)
1906         m_cache->startCachingComputedObjectAttributesUntilTreeMutates();
1907 }
1908     
1909 AXAttributeCacheEnabler::~AXAttributeCacheEnabler()
1910 {
1911     if (m_cache)
1912         m_cache->stopCachingComputedObjectAttributes();
1913 }
1914
1915 #if !PLATFORM(COCOA)
1916 AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType type)
1917 {
1918     switch (type) {
1919     case AXTextEditTypeCut:
1920     case AXTextEditTypeDelete:
1921         return AXTextDeleted;
1922     case AXTextEditTypeInsert:
1923     case AXTextEditTypeDictation:
1924     case AXTextEditTypeTyping:
1925     case AXTextEditTypePaste:
1926         return AXTextInserted;
1927     case AXTextEditTypeAttributesChange:
1928         return AXTextAttributesChanged;
1929     case AXTextEditTypeUnknown:
1930         break;
1931     }
1932     ASSERT_NOT_REACHED();
1933     return AXTextInserted;
1934 }
1935 #endif
1936     
1937 } // namespace WebCore
1938
1939 #endif // HAVE(ACCESSIBILITY)