Crash under WebCore::AXObjectCache::handleMenuItemSelected
[WebKit-https.git] / Source / WebCore / accessibility / AXObjectCache.cpp
1 /*
2  * Copyright (C) 2008-2017 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 "AccessibilityAttachment.h"
39 #include "AccessibilityImageMapLink.h"
40 #include "AccessibilityLabel.h"
41 #include "AccessibilityList.h"
42 #include "AccessibilityListBox.h"
43 #include "AccessibilityListBoxOption.h"
44 #include "AccessibilityMathMLElement.h"
45 #include "AccessibilityMediaControls.h"
46 #include "AccessibilityMediaObject.h"
47 #include "AccessibilityMenuList.h"
48 #include "AccessibilityMenuListOption.h"
49 #include "AccessibilityMenuListPopup.h"
50 #include "AccessibilityProgressIndicator.h"
51 #include "AccessibilityRenderObject.h"
52 #include "AccessibilitySVGElement.h"
53 #include "AccessibilitySVGRoot.h"
54 #include "AccessibilityScrollView.h"
55 #include "AccessibilityScrollbar.h"
56 #include "AccessibilitySlider.h"
57 #include "AccessibilitySpinButton.h"
58 #include "AccessibilityTable.h"
59 #include "AccessibilityTableCell.h"
60 #include "AccessibilityTableColumn.h"
61 #include "AccessibilityTableHeaderContainer.h"
62 #include "AccessibilityTableRow.h"
63 #include "AccessibilityTree.h"
64 #include "AccessibilityTreeItem.h"
65 #include "Document.h"
66 #include "Editing.h"
67 #include "Editor.h"
68 #include "ElementIterator.h"
69 #include "FocusController.h"
70 #include "Frame.h"
71 #include "HTMLAreaElement.h"
72 #include "HTMLCanvasElement.h"
73 #include "HTMLImageElement.h"
74 #include "HTMLInputElement.h"
75 #include "HTMLLabelElement.h"
76 #include "HTMLMeterElement.h"
77 #include "HTMLNames.h"
78 #include "HTMLParserIdioms.h"
79 #include "HTMLTextFormControlElement.h"
80 #include "InlineElementBox.h"
81 #include "MathMLElement.h"
82 #include "Page.h"
83 #include "RenderAttachment.h"
84 #include "RenderLineBreak.h"
85 #include "RenderListBox.h"
86 #include "RenderMathMLOperator.h"
87 #include "RenderMenuList.h"
88 #include "RenderMeter.h"
89 #include "RenderProgress.h"
90 #include "RenderSVGRoot.h"
91 #include "RenderSlider.h"
92 #include "RenderTable.h"
93 #include "RenderTableCell.h"
94 #include "RenderTableRow.h"
95 #include "RenderView.h"
96 #include "SVGElement.h"
97 #include "ScriptDisallowedScope.h"
98 #include "ScrollView.h"
99 #include "TextBoundaries.h"
100 #include "TextControlInnerElements.h"
101 #include "TextIterator.h"
102 #include <wtf/DataLog.h>
103 #include <wtf/SetForScope.h>
104
105 #if ENABLE(VIDEO)
106 #include "MediaControlElements.h"
107 #endif
108
109 #if COMPILER(MSVC)
110 // See https://msdn.microsoft.com/en-us/library/1wea5zwe.aspx
111 #pragma warning(disable: 4701)
112 #endif
113
114 namespace WebCore {
115
116 using namespace HTMLNames;
117
118 // Post value change notifications for password fields or elements contained in password fields at a 40hz interval to thwart analysis of typing cadence
119 static const Seconds accessibilityPasswordValueChangeNotificationInterval { 25_ms };
120 static const Seconds accessibilityLiveRegionChangedNotificationInterval { 20_ms };
121 static const Seconds accessibilityFocusModalNodeNotificationInterval { 50_ms };
122     
123 static bool rendererNeedsDeferredUpdate(const RenderObject& renderer)
124 {
125     ASSERT(!renderer.beingDestroyed());
126     auto& document = renderer.document();
127     return renderer.needsLayout() || document.needsStyleRecalc() || document.inRenderTreeUpdate() || (document.view() && document.view()->layoutContext().isInRenderTreeLayout());
128 }
129
130 static bool nodeAndRendererAreValid(Node* node)
131 {
132     if (!node)
133         return false;
134     
135     auto* renderer = node->renderer();
136     return renderer && !renderer->beingDestroyed();
137 }
138     
139 AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
140 {
141     auto it = m_idMapping.find(id);
142     return it != m_idMapping.end() ? it->value.ignored : AccessibilityObjectInclusion::DefaultBehavior;
143 }
144
145 void AXComputedObjectAttributeCache::setIgnored(AXID id, AccessibilityObjectInclusion inclusion)
146 {
147     HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
148     if (it != m_idMapping.end())
149         it->value.ignored = inclusion;
150     else {
151         CachedAXObjectAttributes attributes;
152         attributes.ignored = inclusion;
153         m_idMapping.set(id, attributes);
154     }
155 }
156
157 AccessibilityReplacedText::AccessibilityReplacedText(const VisibleSelection& selection)
158 {
159     if (AXObjectCache::accessibilityEnabled()) {
160         m_replacedRange.startIndex.value = indexForVisiblePosition(selection.start(), m_replacedRange.startIndex.scope);
161         if (selection.isRange()) {
162             m_replacedText = AccessibilityObject::stringForVisiblePositionRange(selection);
163             m_replacedRange.endIndex.value = indexForVisiblePosition(selection.end(), m_replacedRange.endIndex.scope);
164         } else
165             m_replacedRange.endIndex = m_replacedRange.startIndex;
166     }
167 }
168
169 void AccessibilityReplacedText::postTextStateChangeNotification(AXObjectCache* cache, AXTextEditType type, const String& text, const VisibleSelection& selection)
170 {
171     if (!cache)
172         return;
173     if (!AXObjectCache::accessibilityEnabled())
174         return;
175
176     VisiblePosition position = selection.start();
177     auto* node = highestEditableRoot(position.deepEquivalent(), HasEditableAXRole);
178     if (m_replacedText.length())
179         cache->postTextReplacementNotification(node, AXTextEditTypeDelete, m_replacedText, type, text, position);
180     else
181         cache->postTextStateChangeNotification(node, type, text, position);
182 }
183
184 bool AXObjectCache::gAccessibilityEnabled = false;
185 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
186
187 void AXObjectCache::enableAccessibility()
188 {
189     gAccessibilityEnabled = true;
190 }
191
192 void AXObjectCache::disableAccessibility()
193 {
194     gAccessibilityEnabled = false;
195 }
196
197 void AXObjectCache::setEnhancedUserInterfaceAccessibility(bool flag)
198 {
199     gAccessibilityEnhancedUserInterfaceEnabled = flag;
200 #if PLATFORM(MAC)
201     if (flag)
202         enableAccessibility();
203 #endif
204 }
205
206 AXObjectCache::AXObjectCache(Document& document)
207     : m_document(document)
208     , m_notificationPostTimer(*this, &AXObjectCache::notificationPostTimerFired)
209     , m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired)
210     , m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired)
211     , m_focusModalNodeTimer(*this, &AXObjectCache::focusModalNodeTimerFired)
212     , m_currentModalNode(nullptr)
213 {
214     findModalNodes();
215 }
216
217 AXObjectCache::~AXObjectCache()
218 {
219     m_notificationPostTimer.stop();
220     m_liveRegionChangedPostTimer.stop();
221     m_focusModalNodeTimer.stop();
222
223     for (const auto& object : m_objects.values()) {
224         detachWrapper(object.get(), AccessibilityDetachmentType::CacheDestroyed);
225         object->detach(AccessibilityDetachmentType::CacheDestroyed);
226         object->setAXObjectID(0);
227     }
228 }
229
230 void AXObjectCache::findModalNodes()
231 {
232     // Traverse the DOM tree to look for the aria-modal=true nodes.
233     for (Element* element = ElementTraversal::firstWithin(document().rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) {
234         
235         // Must have dialog or alertdialog role
236         if (!nodeHasRole(element, "dialog") && !nodeHasRole(element, "alertdialog"))
237             continue;
238         if (!equalLettersIgnoringASCIICase(element->attributeWithoutSynchronization(aria_modalAttr), "true"))
239             continue;
240         
241         m_modalNodesSet.add(element);
242     }
243     
244     // Set the current valid aria-modal node if possible.
245     updateCurrentModalNode();
246 }
247
248 void AXObjectCache::updateCurrentModalNode()
249 {
250     // There might be multiple nodes with aria-modal=true set.
251     // We use this function to pick the one we want.
252     m_currentModalNode = nullptr;
253     if (m_modalNodesSet.isEmpty())
254         return;
255     
256     // We only care about the nodes which are visible.
257     ListHashSet<RefPtr<Node>> visibleNodes;
258     for (auto& object : m_modalNodesSet) {
259         if (isNodeVisible(object))
260             visibleNodes.add(object);
261     }
262     
263     if (visibleNodes.isEmpty())
264         return;
265     
266     // If any of the node are keyboard focused, we want to pick that.
267     Node* focusedNode = document().focusedElement();
268     for (auto& object : visibleNodes) {
269         if (focusedNode != nullptr && focusedNode->isDescendantOf(object.get())) {
270             m_currentModalNode = object.get();
271             break;
272         }
273     }
274     
275     // If none of the nodes are focused, we want to pick the last dialog in the DOM.
276     if (!m_currentModalNode)
277         m_currentModalNode = visibleNodes.last().get();
278 }
279
280 bool AXObjectCache::isNodeVisible(Node* node) const
281 {
282     if (!is<Element>(node))
283         return false;
284     
285     RenderObject* renderer = node->renderer();
286     if (!renderer)
287         return false;
288     const RenderStyle& style = renderer->style();
289     if (style.display() == DisplayType::None || style.visibility() != Visibility::Visible)
290         return false;
291     
292     // We also need to consider aria hidden status.
293     if (!isNodeAriaVisible(node))
294         return false;
295     
296     return true;
297 }
298
299 Node* AXObjectCache::modalNode()
300 {
301     // This function returns the valid aria modal node.
302     if (m_modalNodesSet.isEmpty())
303         return nullptr;
304     
305     // Check the current valid aria modal node first.
306     // Usually when one dialog sets aria-modal=true, that dialog is the one we want.
307     if (isNodeVisible(m_currentModalNode))
308         return m_currentModalNode;
309     
310     // Recompute the valid aria modal node when m_currentModalNode is null or hidden.
311     updateCurrentModalNode();
312     return isNodeVisible(m_currentModalNode) ? m_currentModalNode : nullptr;
313 }
314
315 AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
316 {
317     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
318     // in the list of children for its corresponding image.
319     if (!areaElement)
320         return nullptr;
321     
322     HTMLImageElement* imageElement = areaElement->imageElement();
323     if (!imageElement)
324         return nullptr;
325     
326     AccessibilityObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement);
327     if (!axRenderImage)
328         return nullptr;
329     
330     for (const auto& child : axRenderImage->children()) {
331         if (!is<AccessibilityImageMapLink>(*child))
332             continue;
333         
334         if (downcast<AccessibilityImageMapLink>(*child).areaElement() == areaElement)
335             return child.get();
336     }    
337     
338     return nullptr;
339 }
340     
341 AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
342 {
343     if (!gAccessibilityEnabled)
344         return nullptr;
345
346     // get the focused node in the page
347     Document* focusedDocument = page->focusController().focusedOrMainFrame().document();
348     Element* focusedElement = focusedDocument->focusedElement();
349     if (is<HTMLAreaElement>(focusedElement))
350         return focusedImageMapUIElement(downcast<HTMLAreaElement>(focusedElement));
351
352     AccessibilityObject* obj = focusedDocument->axObjectCache()->getOrCreate(focusedElement ? static_cast<Node*>(focusedElement) : focusedDocument);
353     if (!obj)
354         return nullptr;
355
356     if (obj->shouldFocusActiveDescendant()) {
357         if (AccessibilityObject* descendant = obj->activeDescendant())
358             obj = descendant;
359     }
360
361     // the HTML element, for example, is focusable but has an AX object that is ignored
362     if (obj->accessibilityIsIgnored())
363         obj = obj->parentObjectUnignored();
364
365     return obj;
366 }
367
368 AccessibilityObject* AXObjectCache::get(Widget* widget)
369 {
370     if (!widget)
371         return nullptr;
372         
373     AXID axID = m_widgetObjectMapping.get(widget);
374     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
375     if (!axID)
376         return nullptr;
377     
378     return m_objects.get(axID);    
379 }
380     
381 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
382 {
383     if (!renderer)
384         return nullptr;
385     
386     AXID axID = m_renderObjectMapping.get(renderer);
387     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
388     if (!axID)
389         return nullptr;
390
391     return m_objects.get(axID);    
392 }
393
394 AccessibilityObject* AXObjectCache::get(Node* node)
395 {
396     if (!node)
397         return nullptr;
398
399     AXID renderID = node->renderer() ? m_renderObjectMapping.get(node->renderer()) : 0;
400     ASSERT(!HashTraits<AXID>::isDeletedValue(renderID));
401
402     AXID nodeID = m_nodeObjectMapping.get(node);
403     ASSERT(!HashTraits<AXID>::isDeletedValue(nodeID));
404
405     if (node->renderer() && nodeID && !renderID) {
406         // This can happen if an AccessibilityNodeObject is created for a node that's not
407         // rendered, but later something changes and it gets a renderer (like if it's
408         // reparented).
409         remove(nodeID);
410         return nullptr;
411     }
412
413     if (renderID)
414         return m_objects.get(renderID);
415
416     if (!nodeID)
417         return nullptr;
418
419     return m_objects.get(nodeID);
420 }
421
422 // FIXME: This probably belongs on Node.
423 // FIXME: This should take a const char*, but one caller passes nullAtom().
424 bool nodeHasRole(Node* node, const String& role)
425 {
426     if (!node || !is<Element>(node))
427         return false;
428
429     auto& roleValue = downcast<Element>(*node).attributeWithoutSynchronization(roleAttr);
430     if (role.isNull())
431         return roleValue.isEmpty();
432     if (roleValue.isEmpty())
433         return false;
434
435     return SpaceSplitString(roleValue, true).contains(role);
436 }
437
438 static Ref<AccessibilityObject> createFromRenderer(RenderObject* renderer)
439 {
440     // FIXME: How could renderer->node() ever not be an Element?
441     Node* node = renderer->node();
442
443     // If the node is aria role="list" or the aria role is empty and its a
444     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
445     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
446                       || (nodeHasRole(node, nullAtom()) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
447         return AccessibilityList::create(renderer);
448
449     // aria tables
450     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid") || nodeHasRole(node, "table"))
451         return AccessibilityARIAGrid::create(renderer);
452     if (nodeHasRole(node, "row"))
453         return AccessibilityARIAGridRow::create(renderer);
454     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "cell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
455         return AccessibilityARIAGridCell::create(renderer);
456
457     // aria tree
458     if (nodeHasRole(node, "tree"))
459         return AccessibilityTree::create(renderer);
460     if (nodeHasRole(node, "treeitem"))
461         return AccessibilityTreeItem::create(renderer);
462
463     if (node && is<HTMLLabelElement>(node) && nodeHasRole(node, nullAtom()))
464         return AccessibilityLabel::create(renderer);
465
466 #if PLATFORM(IOS)
467     if (is<HTMLMediaElement>(node) && nodeHasRole(node, nullAtom()))
468         return AccessibilityMediaObject::create(renderer);
469 #endif
470
471 #if ENABLE(VIDEO)
472     // media controls
473     if (node && node->isMediaControlElement())
474         return AccessibilityMediaControl::create(renderer);
475 #endif
476
477     if (is<RenderSVGRoot>(*renderer))
478         return AccessibilitySVGRoot::create(renderer);
479     
480     if (is<SVGElement>(node))
481         return AccessibilitySVGElement::create(renderer);
482
483 #if ENABLE(MATHML)
484     // The mfenced element creates anonymous RenderMathMLOperators which should be treated
485     // as MathML elements and assigned the MathElementRole so that platform logic regarding
486     // inclusion and role mapping is not bypassed.
487     bool isAnonymousOperator = renderer->isAnonymous() && is<RenderMathMLOperator>(*renderer);
488     if (isAnonymousOperator || is<MathMLElement>(node))
489         return AccessibilityMathMLElement::create(renderer, isAnonymousOperator);
490 #endif
491
492     if (is<RenderBoxModelObject>(*renderer)) {
493         RenderBoxModelObject& cssBox = downcast<RenderBoxModelObject>(*renderer);
494         if (is<RenderListBox>(cssBox))
495             return AccessibilityListBox::create(&downcast<RenderListBox>(cssBox));
496         if (is<RenderMenuList>(cssBox))
497             return AccessibilityMenuList::create(&downcast<RenderMenuList>(cssBox));
498
499         // standard tables
500         if (is<RenderTable>(cssBox))
501             return AccessibilityTable::create(&downcast<RenderTable>(cssBox));
502         if (is<RenderTableRow>(cssBox))
503             return AccessibilityTableRow::create(&downcast<RenderTableRow>(cssBox));
504         if (is<RenderTableCell>(cssBox))
505             return AccessibilityTableCell::create(&downcast<RenderTableCell>(cssBox));
506
507         // progress bar
508         if (is<RenderProgress>(cssBox))
509             return AccessibilityProgressIndicator::create(&downcast<RenderProgress>(cssBox));
510
511 #if ENABLE(ATTACHMENT_ELEMENT)
512         if (is<RenderAttachment>(cssBox))
513             return AccessibilityAttachment::create(&downcast<RenderAttachment>(cssBox));
514 #endif
515 #if ENABLE(METER_ELEMENT)
516         if (is<RenderMeter>(cssBox))
517             return AccessibilityProgressIndicator::create(&downcast<RenderMeter>(cssBox));
518 #endif
519
520         // input type=range
521         if (is<RenderSlider>(cssBox))
522             return AccessibilitySlider::create(&downcast<RenderSlider>(cssBox));
523     }
524
525     return AccessibilityRenderObject::create(renderer);
526 }
527
528 static Ref<AccessibilityObject> createFromNode(Node* node)
529 {
530     return AccessibilityNodeObject::create(node);
531 }
532
533 AccessibilityObject* AXObjectCache::getOrCreate(Widget* widget)
534 {
535     if (!widget)
536         return nullptr;
537
538     if (AccessibilityObject* obj = get(widget))
539         return obj;
540     
541     RefPtr<AccessibilityObject> newObj;
542     if (is<ScrollView>(*widget))
543         newObj = AccessibilityScrollView::create(downcast<ScrollView>(widget));
544     else if (is<Scrollbar>(*widget))
545         newObj = AccessibilityScrollbar::create(downcast<Scrollbar>(widget));
546
547     // Will crash later if we have two objects for the same widget.
548     ASSERT(!get(widget));
549
550     // Catch the case if an (unsupported) widget type is used. Only FrameView and ScrollBar are supported now.
551     ASSERT(newObj);
552     if (!newObj)
553         return nullptr;
554
555     getAXID(newObj.get());
556     
557     m_widgetObjectMapping.set(widget, newObj->axObjectID());
558     m_objects.set(newObj->axObjectID(), newObj);    
559     newObj->init();
560     attachWrapper(newObj.get());
561     return newObj.get();
562 }
563
564 AccessibilityObject* AXObjectCache::getOrCreate(Node* node)
565 {
566     if (!node)
567         return nullptr;
568
569     if (AccessibilityObject* obj = get(node))
570         return obj;
571
572     if (node->renderer())
573         return getOrCreate(node->renderer());
574
575     if (!node->parentElement())
576         return nullptr;
577     
578     // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree.
579     // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes.
580     bool inCanvasSubtree = lineageOfType<HTMLCanvasElement>(*node->parentElement()).first();
581     bool isHidden = isNodeAriaVisible(node);
582
583     bool insideMeterElement = false;
584 #if ENABLE(METER_ELEMENT)
585     insideMeterElement = is<HTMLMeterElement>(*node->parentElement());
586 #endif
587     
588     if (!inCanvasSubtree && !isHidden && !insideMeterElement)
589         return nullptr;
590
591     // Fallback content is only focusable as long as the canvas is displayed and visible.
592     // Update the style before Element::isFocusable() gets called.
593     if (inCanvasSubtree)
594         node->document().updateStyleIfNeeded();
595
596     RefPtr<AccessibilityObject> newObj = createFromNode(node);
597
598     // Will crash later if we have two objects for the same node.
599     ASSERT(!get(node));
600
601     getAXID(newObj.get());
602
603     m_nodeObjectMapping.set(node, newObj->axObjectID());
604     m_objects.set(newObj->axObjectID(), newObj);
605     newObj->init();
606     attachWrapper(newObj.get());
607     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
608     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
609     // it will disappear when this function is finished, leading to a use-after-free.
610     if (newObj->isDetached())
611         return nullptr;
612     
613     return newObj.get();
614 }
615
616 AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
617 {
618     if (!renderer)
619         return nullptr;
620
621     if (AccessibilityObject* obj = get(renderer))
622         return obj;
623
624     RefPtr<AccessibilityObject> newObj = createFromRenderer(renderer);
625
626     // Will crash later if we have two objects for the same renderer.
627     ASSERT(!get(renderer));
628
629     getAXID(newObj.get());
630
631     m_renderObjectMapping.set(renderer, newObj->axObjectID());
632     m_objects.set(newObj->axObjectID(), newObj);
633     newObj->init();
634     attachWrapper(newObj.get());
635     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
636     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
637     // it will disappear when this function is finished, leading to a use-after-free.
638     if (newObj->isDetached())
639         return nullptr;
640     
641     return newObj.get();
642 }
643     
644 AccessibilityObject* AXObjectCache::rootObject()
645 {
646     if (!gAccessibilityEnabled)
647         return nullptr;
648
649     return getOrCreate(m_document.view());
650 }
651
652 AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame* frame)
653 {
654     if (!gAccessibilityEnabled)
655         return nullptr;
656
657     if (!frame)
658         return nullptr;
659     return getOrCreate(frame->view());
660 }    
661     
662 AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
663 {
664     RefPtr<AccessibilityObject> obj = nullptr;
665     
666     // will be filled in...
667     switch (role) {
668     case AccessibilityRole::ListBoxOption:
669         obj = AccessibilityListBoxOption::create();
670         break;
671     case AccessibilityRole::ImageMapLink:
672         obj = AccessibilityImageMapLink::create();
673         break;
674     case AccessibilityRole::Column:
675         obj = AccessibilityTableColumn::create();
676         break;            
677     case AccessibilityRole::TableHeaderContainer:
678         obj = AccessibilityTableHeaderContainer::create();
679         break;   
680     case AccessibilityRole::SliderThumb:
681         obj = AccessibilitySliderThumb::create();
682         break;
683     case AccessibilityRole::MenuListPopup:
684         obj = AccessibilityMenuListPopup::create();
685         break;
686     case AccessibilityRole::MenuListOption:
687         obj = AccessibilityMenuListOption::create();
688         break;
689     case AccessibilityRole::SpinButton:
690         obj = AccessibilitySpinButton::create();
691         break;
692     case AccessibilityRole::SpinButtonPart:
693         obj = AccessibilitySpinButtonPart::create();
694         break;
695     default:
696         obj = nullptr;
697     }
698     
699     if (obj)
700         getAXID(obj.get());
701     else
702         return nullptr;
703
704     m_objects.set(obj->axObjectID(), obj);    
705     obj->init();
706     attachWrapper(obj.get());
707     return obj.get();
708 }
709
710 void AXObjectCache::remove(AXID axID)
711 {
712     if (!axID)
713         return;
714
715     auto object = m_objects.take(axID);
716     if (!object)
717         return;
718
719     detachWrapper(object.get(), AccessibilityDetachmentType::ElementDestroyed);
720     object->detach(AccessibilityDetachmentType::ElementDestroyed, this);
721     object->setAXObjectID(0);
722
723     m_idsInUse.remove(axID);
724
725     ASSERT(m_objects.size() >= m_idsInUse.size());
726 }
727     
728 void AXObjectCache::remove(RenderObject* renderer)
729 {
730     if (!renderer)
731         return;
732     remove(m_renderObjectMapping.take(renderer));
733 }
734
735 void AXObjectCache::remove(Node& node)
736 {
737     if (is<Element>(node)) {
738         m_deferredRecomputeIsIgnoredList.remove(downcast<Element>(&node));
739         m_deferredSelectedChildredChangedList.remove(downcast<Element>(&node));
740         m_deferredTextFormControlValue.remove(downcast<Element>(&node));
741         m_deferredAttributeChange.remove(downcast<Element>(&node));
742     }
743     m_deferredTextChangedList.remove(&node);
744     // Remove the entry if the new focused node is being removed.
745     m_deferredFocusedNodeChange.removeAllMatching([&node](auto& entry) -> bool {
746         return entry.second == &node;
747     });
748     removeNodeForUse(node);
749
750     remove(m_nodeObjectMapping.take(&node));
751
752     if (m_currentModalNode == &node)
753         m_currentModalNode = nullptr;
754     m_modalNodesSet.remove(&node);
755
756     remove(node.renderer());
757 }
758
759 void AXObjectCache::remove(Widget* view)
760 {
761     if (!view)
762         return;
763     remove(m_widgetObjectMapping.take(view));
764 }
765     
766     
767 #if !PLATFORM(WIN)
768 AXID AXObjectCache::platformGenerateAXID() const
769 {
770     static AXID lastUsedID = 0;
771
772     // Generate a new ID.
773     AXID objID = lastUsedID;
774     do {
775         ++objID;
776     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
777
778     lastUsedID = objID;
779
780     return objID;
781 }
782 #endif
783
784 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
785 {
786     // check for already-assigned ID
787     AXID objID = obj->axObjectID();
788     if (objID) {
789         ASSERT(m_idsInUse.contains(objID));
790         return objID;
791     }
792
793     objID = platformGenerateAXID();
794
795     m_idsInUse.add(objID);
796     obj->setAXObjectID(objID);
797     
798     return objID;
799 }
800
801 void AXObjectCache::textChanged(Node* node)
802 {
803     textChanged(getOrCreate(node));
804 }
805
806 void AXObjectCache::textChanged(AccessibilityObject* obj)
807 {
808     if (!obj)
809         return;
810
811     bool parentAlreadyExists = obj->parentObjectIfExists();
812     obj->textChanged();
813     postNotification(obj, obj->document(), AXObjectCache::AXTextChanged);
814     if (parentAlreadyExists)
815         obj->notifyIfIgnoredValueChanged();
816 }
817
818 void AXObjectCache::updateCacheAfterNodeIsAttached(Node* node)
819 {
820     // Calling get() will update the AX object if we had an AccessibilityNodeObject but now we need
821     // an AccessibilityRenderObject, because it was reparented to a location outside of a canvas.
822     get(node);
823 }
824
825 void AXObjectCache::handleMenuOpened(Node* node)
826 {
827     if (!node || !node->renderer() || !nodeHasRole(node, "menu"))
828         return;
829     
830     postNotification(getOrCreate(node), &document(), AXMenuOpened);
831 }
832     
833 void AXObjectCache::handleLiveRegionCreated(Node* node)
834 {
835     if (!is<Element>(node) || !node->renderer())
836         return;
837     
838     Element* element = downcast<Element>(node);
839     String liveRegionStatus = element->attributeWithoutSynchronization(aria_liveAttr);
840     if (liveRegionStatus.isEmpty()) {
841         const AtomicString& ariaRole = element->attributeWithoutSynchronization(roleAttr);
842         if (!ariaRole.isEmpty())
843             liveRegionStatus = AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityObject::ariaRoleToWebCoreRole(ariaRole));
844     }
845     
846     if (AccessibilityObject::liveRegionStatusIsEnabled(liveRegionStatus))
847         postNotification(getOrCreate(node), &document(), AXLiveRegionCreated);
848 }
849     
850 void AXObjectCache::childrenChanged(Node* node, Node* newChild)
851 {
852     if (newChild) {
853         handleMenuOpened(newChild);
854         handleLiveRegionCreated(newChild);
855     }
856
857     childrenChanged(get(node));
858 }
859
860 void AXObjectCache::childrenChanged(RenderObject* renderer, RenderObject* newChild)
861 {
862     if (!renderer)
863         return;
864
865     // FIXME: Refactor the code to avoid calling updateLayout in this call stack.
866     ScriptDisallowedScope::LayoutAssertionDisableScope disableScope;
867     
868     if (newChild) {
869         handleMenuOpened(newChild->node());
870         handleLiveRegionCreated(newChild->node());
871     }
872     
873     childrenChanged(get(renderer));
874 }
875
876 void AXObjectCache::childrenChanged(AccessibilityObject* obj)
877 {
878     if (!obj)
879         return;
880
881     obj->childrenChanged();
882 }
883     
884 void AXObjectCache::notificationPostTimerFired()
885 {
886     Ref<Document> protectorForCacheOwner(m_document);
887     m_notificationPostTimer.stop();
888     
889     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
890     // when the notification list is cleared at the end. Instead copy this list at the start.
891     auto notifications = WTFMove(m_notificationsToPost);
892     
893     for (const auto& note : notifications) {
894         AccessibilityObject* obj = note.first.get();
895         if (!obj->axObjectID())
896             continue;
897
898         if (!obj->axObjectCache())
899             continue;
900         
901 #ifndef NDEBUG
902         // Make sure none of the render views are in the process of being layed out.
903         // Notifications should only be sent after the renderer has finished
904         if (is<AccessibilityRenderObject>(*obj)) {
905             if (auto* renderer = downcast<AccessibilityRenderObject>(*obj).renderer())
906                 ASSERT(!renderer->view().frameView().layoutContext().layoutState());
907         }
908 #endif
909
910         AXNotification notification = note.second;
911         
912         // Ensure that this menu really is a menu. We do this check here so that we don't have to create
913         // the axChildren when the menu is marked as opening.
914         if (notification == AXMenuOpened) {
915             obj->updateChildrenIfNecessary();
916             if (obj->roleValue() != AccessibilityRole::Menu)
917                 continue;
918         }
919         
920         postPlatformNotification(obj, notification);
921
922         if (notification == AXChildrenChanged && obj->parentObjectIfExists() && obj->lastKnownIsIgnoredValue() != obj->accessibilityIsIgnored())
923             childrenChanged(obj->parentObject());
924     }
925 }
926
927 void AXObjectCache::passwordNotificationPostTimerFired()
928 {
929 #if PLATFORM(COCOA)
930     m_passwordNotificationPostTimer.stop();
931
932     // In tests, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
933     // when the notification list is cleared at the end. Instead copy this list at the start.
934     auto notifications = WTFMove(m_passwordNotificationsToPost);
935
936     for (auto& notification : notifications)
937         postTextStateChangePlatformNotification(notification.get(), AXTextEditTypeInsert, " ", VisiblePosition());
938 #endif
939 }
940     
941 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, PostTarget postTarget, PostType postType)
942 {
943     if (!renderer)
944         return;
945     
946     stopCachingComputedObjectAttributes();
947
948     // Get an accessibility object that already exists. One should not be created here
949     // because a render update may be in progress and creating an AX object can re-trigger a layout
950     RefPtr<AccessibilityObject> object = get(renderer);
951     while (!object && renderer) {
952         renderer = renderer->parent();
953         object = get(renderer); 
954     }
955     
956     if (!renderer)
957         return;
958     
959     postNotification(object.get(), &renderer->document(), notification, postTarget, postType);
960 }
961
962 void AXObjectCache::postNotification(Node* node, AXNotification notification, PostTarget postTarget, PostType postType)
963 {
964     if (!node)
965         return;
966     
967     stopCachingComputedObjectAttributes();
968
969     // Get an accessibility object that already exists. One should not be created here
970     // because a render update may be in progress and creating an AX object can re-trigger a layout
971     RefPtr<AccessibilityObject> object = get(node);
972     while (!object && node) {
973         node = node->parentNode();
974         object = get(node);
975     }
976     
977     if (!node)
978         return;
979     
980     postNotification(object.get(), &node->document(), notification, postTarget, postType);
981 }
982
983 void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, PostTarget postTarget, PostType postType)
984 {
985     stopCachingComputedObjectAttributes();
986
987     if (object && postTarget == TargetObservableParent)
988         object = object->observableObject();
989
990     if (!object && document)
991         object = get(document->renderView());
992
993     if (!object)
994         return;
995
996     if (postType == PostAsynchronously) {
997         m_notificationsToPost.append(std::make_pair(object, notification));
998         if (!m_notificationPostTimer.isActive())
999             m_notificationPostTimer.startOneShot(0_s);
1000     } else
1001         postPlatformNotification(object, notification);
1002 }
1003
1004 void AXObjectCache::checkedStateChanged(Node* node)
1005 {
1006     postNotification(node, AXObjectCache::AXCheckedStateChanged);
1007 }
1008
1009 void AXObjectCache::handleMenuItemSelected(Node* node)
1010 {
1011     if (!node)
1012         return;
1013     
1014     if (!nodeHasRole(node, "menuitem") && !nodeHasRole(node, "menuitemradio") && !nodeHasRole(node, "menuitemcheckbox"))
1015         return;
1016     
1017     if (!downcast<Element>(*node).focused() && !equalLettersIgnoringASCIICase(downcast<Element>(*node).attributeWithoutSynchronization(aria_selectedAttr), "true"))
1018         return;
1019     
1020     postNotification(getOrCreate(node), &document(), AXMenuListItemSelected);
1021 }
1022     
1023 void AXObjectCache::deferFocusedUIElementChangeIfNeeded(Node* oldNode, Node* newNode)
1024 {
1025     if (nodeAndRendererAreValid(newNode) && rendererNeedsDeferredUpdate(*newNode->renderer()))
1026         m_deferredFocusedNodeChange.append({ oldNode, newNode });
1027     else
1028         handleFocusedUIElementChanged(oldNode, newNode);
1029 }
1030     
1031 void AXObjectCache::handleFocusedUIElementChanged(Node* oldNode, Node* newNode)
1032 {
1033     handleMenuItemSelected(newNode);
1034     platformHandleFocusedUIElementChanged(oldNode, newNode);
1035 }
1036     
1037 void AXObjectCache::selectedChildrenChanged(Node* node)
1038 {
1039     handleMenuItemSelected(node);
1040     
1041     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
1042     // to find the container which should send out the notification.
1043     postNotification(node, AXSelectedChildrenChanged, TargetObservableParent);
1044 }
1045
1046 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
1047 {
1048     if (renderer)
1049         handleMenuItemSelected(renderer->node());
1050
1051     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
1052     // to find the container which should send out the notification.
1053     postNotification(renderer, AXSelectedChildrenChanged, TargetObservableParent);
1054 }
1055
1056 #ifndef NDEBUG
1057 void AXObjectCache::showIntent(const AXTextStateChangeIntent &intent)
1058 {
1059     switch (intent.type) {
1060     case AXTextStateChangeTypeUnknown:
1061         dataLog("Unknown");
1062         break;
1063     case AXTextStateChangeTypeEdit:
1064         dataLog("Edit::");
1065         break;
1066     case AXTextStateChangeTypeSelectionMove:
1067         dataLog("Move::");
1068         break;
1069     case AXTextStateChangeTypeSelectionExtend:
1070         dataLog("Extend::");
1071         break;
1072     case AXTextStateChangeTypeSelectionBoundary:
1073         dataLog("Boundary::");
1074         break;
1075     }
1076     switch (intent.type) {
1077     case AXTextStateChangeTypeUnknown:
1078         break;
1079     case AXTextStateChangeTypeEdit:
1080         switch (intent.change) {
1081         case AXTextEditTypeUnknown:
1082             dataLog("Unknown");
1083             break;
1084         case AXTextEditTypeDelete:
1085             dataLog("Delete");
1086             break;
1087         case AXTextEditTypeInsert:
1088             dataLog("Insert");
1089             break;
1090         case AXTextEditTypeDictation:
1091             dataLog("DictationInsert");
1092             break;
1093         case AXTextEditTypeTyping:
1094             dataLog("TypingInsert");
1095             break;
1096         case AXTextEditTypeCut:
1097             dataLog("Cut");
1098             break;
1099         case AXTextEditTypePaste:
1100             dataLog("Paste");
1101             break;
1102         case AXTextEditTypeAttributesChange:
1103             dataLog("AttributesChange");
1104             break;
1105         }
1106         break;
1107     case AXTextStateChangeTypeSelectionMove:
1108     case AXTextStateChangeTypeSelectionExtend:
1109     case AXTextStateChangeTypeSelectionBoundary:
1110         switch (intent.selection.direction) {
1111         case AXTextSelectionDirectionUnknown:
1112             dataLog("Unknown::");
1113             break;
1114         case AXTextSelectionDirectionBeginning:
1115             dataLog("Beginning::");
1116             break;
1117         case AXTextSelectionDirectionEnd:
1118             dataLog("End::");
1119             break;
1120         case AXTextSelectionDirectionPrevious:
1121             dataLog("Previous::");
1122             break;
1123         case AXTextSelectionDirectionNext:
1124             dataLog("Next::");
1125             break;
1126         case AXTextSelectionDirectionDiscontiguous:
1127             dataLog("Discontiguous::");
1128             break;
1129         }
1130         switch (intent.selection.direction) {
1131         case AXTextSelectionDirectionUnknown:
1132         case AXTextSelectionDirectionBeginning:
1133         case AXTextSelectionDirectionEnd:
1134         case AXTextSelectionDirectionPrevious:
1135         case AXTextSelectionDirectionNext:
1136             switch (intent.selection.granularity) {
1137             case AXTextSelectionGranularityUnknown:
1138                 dataLog("Unknown");
1139                 break;
1140             case AXTextSelectionGranularityCharacter:
1141                 dataLog("Character");
1142                 break;
1143             case AXTextSelectionGranularityWord:
1144                 dataLog("Word");
1145                 break;
1146             case AXTextSelectionGranularityLine:
1147                 dataLog("Line");
1148                 break;
1149             case AXTextSelectionGranularitySentence:
1150                 dataLog("Sentence");
1151                 break;
1152             case AXTextSelectionGranularityParagraph:
1153                 dataLog("Paragraph");
1154                 break;
1155             case AXTextSelectionGranularityPage:
1156                 dataLog("Page");
1157                 break;
1158             case AXTextSelectionGranularityDocument:
1159                 dataLog("Document");
1160                 break;
1161             case AXTextSelectionGranularityAll:
1162                 dataLog("All");
1163                 break;
1164             }
1165             break;
1166         case AXTextSelectionDirectionDiscontiguous:
1167             break;
1168         }
1169         break;
1170     }
1171     dataLog("\n");
1172 }
1173 #endif
1174
1175 void AXObjectCache::setTextSelectionIntent(const AXTextStateChangeIntent& intent)
1176 {
1177     m_textSelectionIntent = intent;
1178 }
1179     
1180 void AXObjectCache::setIsSynchronizingSelection(bool isSynchronizing)
1181 {
1182     m_isSynchronizingSelection = isSynchronizing;
1183 }
1184
1185 static bool isPasswordFieldOrContainedByPasswordField(AccessibilityObject* object)
1186 {
1187     return object && (object->isPasswordField() || object->isContainedByPasswordField());
1188 }
1189
1190 void AXObjectCache::postTextStateChangeNotification(Node* node, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1191 {
1192     if (!node)
1193         return;
1194
1195 #if PLATFORM(COCOA)
1196     stopCachingComputedObjectAttributes();
1197
1198     postTextStateChangeNotification(getOrCreate(node), intent, selection);
1199 #else
1200     postNotification(node->renderer(), AXObjectCache::AXSelectedTextChanged, TargetObservableParent);
1201     UNUSED_PARAM(intent);
1202     UNUSED_PARAM(selection);
1203 #endif
1204 }
1205
1206 void AXObjectCache::postTextStateChangeNotification(const Position& position, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1207 {
1208     Node* node = position.deprecatedNode();
1209     if (!node)
1210         return;
1211
1212     stopCachingComputedObjectAttributes();
1213
1214 #if PLATFORM(COCOA)
1215     AccessibilityObject* object = getOrCreate(node);
1216     if (object && object->accessibilityIsIgnored()) {
1217         if (position.atLastEditingPositionForNode()) {
1218             if (AccessibilityObject* nextSibling = object->nextSiblingUnignored(1))
1219                 object = nextSibling;
1220         } else if (position.atFirstEditingPositionForNode()) {
1221             if (AccessibilityObject* previousSibling = object->previousSiblingUnignored(1))
1222                 object = previousSibling;
1223         }
1224     }
1225
1226     postTextStateChangeNotification(object, intent, selection);
1227 #else
1228     postTextStateChangeNotification(node, intent, selection);
1229 #endif
1230 }
1231
1232 void AXObjectCache::postTextStateChangeNotification(AccessibilityObject* object, const AXTextStateChangeIntent& intent, const VisibleSelection& selection)
1233 {
1234     stopCachingComputedObjectAttributes();
1235
1236 #if PLATFORM(COCOA)
1237     if (object) {
1238         if (isPasswordFieldOrContainedByPasswordField(object))
1239             return;
1240
1241         if (auto observableObject = object->observableObject())
1242             object = observableObject;
1243     }
1244
1245     const AXTextStateChangeIntent& newIntent = (intent.type == AXTextStateChangeTypeUnknown || (m_isSynchronizingSelection && m_textSelectionIntent.type != AXTextStateChangeTypeUnknown)) ? m_textSelectionIntent : intent;
1246     postTextStateChangePlatformNotification(object, newIntent, selection);
1247 #else
1248     UNUSED_PARAM(object);
1249     UNUSED_PARAM(intent);
1250     UNUSED_PARAM(selection);
1251 #endif
1252
1253     setTextSelectionIntent(AXTextStateChangeIntent());
1254     setIsSynchronizingSelection(false);
1255 }
1256
1257 void AXObjectCache::postTextStateChangeNotification(Node* node, AXTextEditType type, const String& text, const VisiblePosition& position)
1258 {
1259     if (!node)
1260         return;
1261     if (type == AXTextEditTypeUnknown)
1262         return;
1263
1264     stopCachingComputedObjectAttributes();
1265
1266     AccessibilityObject* object = getOrCreate(node);
1267 #if PLATFORM(COCOA)
1268     if (object) {
1269         if (enqueuePasswordValueChangeNotification(object))
1270             return;
1271         object = object->observableObject();
1272     }
1273
1274     postTextStateChangePlatformNotification(object, type, text, position);
1275 #else
1276     nodeTextChangePlatformNotification(object, textChangeForEditType(type), position.deepEquivalent().deprecatedEditingOffset(), text);
1277 #endif
1278 }
1279
1280 void AXObjectCache::postTextReplacementNotification(Node* node, AXTextEditType deletionType, const String& deletedText, AXTextEditType insertionType, const String& insertedText, const VisiblePosition& position)
1281 {
1282     if (!node)
1283         return;
1284     if (deletionType != AXTextEditTypeDelete)
1285         return;
1286     if (!(insertionType == AXTextEditTypeInsert || insertionType == AXTextEditTypeTyping || insertionType == AXTextEditTypeDictation || insertionType == AXTextEditTypePaste))
1287         return;
1288
1289     stopCachingComputedObjectAttributes();
1290
1291     AccessibilityObject* object = getOrCreate(node);
1292 #if PLATFORM(COCOA)
1293     if (object) {
1294         if (enqueuePasswordValueChangeNotification(object))
1295             return;
1296         object = object->observableObject();
1297     }
1298
1299     postTextReplacementPlatformNotification(object, deletionType, deletedText, insertionType, insertedText, position);
1300 #else
1301     nodeTextChangePlatformNotification(object, textChangeForEditType(deletionType), position.deepEquivalent().deprecatedEditingOffset(), deletedText);
1302     nodeTextChangePlatformNotification(object, textChangeForEditType(insertionType), position.deepEquivalent().deprecatedEditingOffset(), insertedText);
1303 #endif
1304 }
1305
1306 void AXObjectCache::postTextReplacementNotificationForTextControl(HTMLTextFormControlElement& textControl, const String& deletedText, const String& insertedText)
1307 {
1308     stopCachingComputedObjectAttributes();
1309
1310     AccessibilityObject* object = getOrCreate(&textControl);
1311 #if PLATFORM(COCOA)
1312     if (object) {
1313         if (enqueuePasswordValueChangeNotification(object))
1314             return;
1315         object = object->observableObject();
1316     }
1317
1318     postTextReplacementPlatformNotificationForTextControl(object, deletedText, insertedText, textControl);
1319 #else
1320     nodeTextChangePlatformNotification(object, textChangeForEditType(AXTextEditTypeDelete), 0, deletedText);
1321     nodeTextChangePlatformNotification(object, textChangeForEditType(AXTextEditTypeInsert), 0, insertedText);
1322 #endif
1323 }
1324
1325 bool AXObjectCache::enqueuePasswordValueChangeNotification(AccessibilityObject* object)
1326 {
1327     if (!isPasswordFieldOrContainedByPasswordField(object))
1328         return false;
1329
1330     AccessibilityObject* observableObject = object->observableObject();
1331     if (!observableObject) {
1332         ASSERT_NOT_REACHED();
1333         // return true even though the enqueue didn't happen because this is a password field and caller shouldn't post a notification
1334         return true;
1335     }
1336
1337     m_passwordNotificationsToPost.add(observableObject);
1338     if (!m_passwordNotificationPostTimer.isActive())
1339         m_passwordNotificationPostTimer.startOneShot(accessibilityPasswordValueChangeNotificationInterval);
1340
1341     return true;
1342 }
1343
1344 void AXObjectCache::frameLoadingEventNotification(Frame* frame, AXLoadingEvent loadingEvent)
1345 {
1346     if (!frame)
1347         return;
1348
1349     // Delegate on the right platform
1350     RenderView* contentRenderer = frame->contentRenderer();
1351     if (!contentRenderer)
1352         return;
1353
1354     AccessibilityObject* obj = getOrCreate(contentRenderer);
1355     frameLoadingEventPlatformNotification(obj, loadingEvent);
1356 }
1357
1358 void AXObjectCache::postLiveRegionChangeNotification(AccessibilityObject* object)
1359 {
1360     if (m_liveRegionChangedPostTimer.isActive())
1361         m_liveRegionChangedPostTimer.stop();
1362
1363     if (!m_liveRegionObjectsSet.contains(object))
1364         m_liveRegionObjectsSet.add(object);
1365
1366     m_liveRegionChangedPostTimer.startOneShot(accessibilityLiveRegionChangedNotificationInterval);
1367 }
1368
1369 void AXObjectCache::liveRegionChangedNotificationPostTimerFired()
1370 {
1371     m_liveRegionChangedPostTimer.stop();
1372
1373     if (m_liveRegionObjectsSet.isEmpty())
1374         return;
1375
1376     for (auto& object : m_liveRegionObjectsSet)
1377         postNotification(object.get(), object->document(), AXObjectCache::AXLiveRegionChanged);
1378     m_liveRegionObjectsSet.clear();
1379 }
1380
1381 static AccessibilityObject* firstFocusableChild(AccessibilityObject* obj)
1382 {
1383     if (!obj)
1384         return nullptr;
1385     
1386     for (auto* child = obj->firstChild(); child; child = child->nextSibling()) {
1387         if (child->canSetFocusAttribute())
1388             return child;
1389         if (AccessibilityObject* focusable = firstFocusableChild(child))
1390             return focusable;
1391     }
1392     return nullptr;
1393 }
1394
1395 void AXObjectCache::focusModalNode()
1396 {
1397     if (m_focusModalNodeTimer.isActive())
1398         m_focusModalNodeTimer.stop();
1399     
1400     m_focusModalNodeTimer.startOneShot(accessibilityFocusModalNodeNotificationInterval);
1401 }
1402
1403 void AXObjectCache::focusModalNodeTimerFired()
1404 {
1405     if (!m_currentModalNode)
1406         return;
1407     
1408     // Don't set focus if we are already focusing onto some element within
1409     // the dialog.
1410     if (m_currentModalNode->contains(document().focusedElement()))
1411         return;
1412     
1413     if (AccessibilityObject* currentModalNodeObject = getOrCreate(m_currentModalNode)) {
1414         if (AccessibilityObject* focusable = firstFocusableChild(currentModalNodeObject))
1415             focusable->setFocused(true);
1416     }
1417 }
1418
1419 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
1420 {
1421     if (!view)
1422         return;
1423     
1424     // We don't want to create a scroll view from this method, only update an existing one.
1425     if (AccessibilityObject* scrollViewObject = get(view)) {
1426         stopCachingComputedObjectAttributes();
1427         scrollViewObject->updateChildrenIfNecessary();
1428     }
1429 }
1430     
1431 void AXObjectCache::handleAriaExpandedChange(Node* node)
1432 {
1433     if (AccessibilityObject* obj = get(node))
1434         obj->handleAriaExpandedChanged();
1435 }
1436     
1437 void AXObjectCache::handleActiveDescendantChanged(Node* node)
1438 {
1439     if (AccessibilityObject* obj = getOrCreate(node))
1440         obj->handleActiveDescendantChanged();
1441 }
1442
1443 void AXObjectCache::handleAriaRoleChanged(Node* node)
1444 {
1445     stopCachingComputedObjectAttributes();
1446
1447     // Don't make an AX object unless it's needed
1448     if (AccessibilityObject* obj = get(node)) {
1449         obj->updateAccessibilityRole();
1450         obj->notifyIfIgnoredValueChanged();
1451     }
1452 }
1453
1454 void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName& attrName, Element* element)
1455 {
1456     if (nodeAndRendererAreValid(element) && rendererNeedsDeferredUpdate(*element->renderer()))
1457         m_deferredAttributeChange.add(element, attrName);
1458     else
1459         handleAttributeChange(attrName, element);
1460 }
1461     
1462 bool AXObjectCache::shouldProcessAttributeChange(const QualifiedName& attrName, Element* element)
1463 {
1464     if (!element)
1465         return false;
1466     
1467     // aria-modal ends up affecting sub-trees that are being shown/hidden so it's likely that
1468     // an AT would not have accessed this node yet.
1469     if (attrName == aria_modalAttr)
1470         return true;
1471     
1472     // If an AXObject has yet to be created, then there's no need to process attribute changes.
1473     // Some of these notifications are processed on the parent, so allow that to proceed as well
1474     if (get(element) || get(element->parentNode()))
1475         return true;
1476
1477     return false;
1478 }
1479     
1480 void AXObjectCache::handleAttributeChange(const QualifiedName& attrName, Element* element)
1481 {
1482     if (!shouldProcessAttributeChange(attrName, element))
1483         return;
1484     
1485     if (attrName == roleAttr)
1486         handleAriaRoleChanged(element);
1487     else if (attrName == altAttr || attrName == titleAttr)
1488         textChanged(element);
1489     else if (attrName == forAttr && is<HTMLLabelElement>(*element))
1490         labelChanged(element);
1491
1492     if (!attrName.localName().string().startsWith("aria-"))
1493         return;
1494
1495     if (attrName == aria_activedescendantAttr)
1496         handleActiveDescendantChanged(element);
1497     else if (attrName == aria_busyAttr)
1498         postNotification(element, AXObjectCache::AXElementBusyChanged);
1499     else if (attrName == aria_valuenowAttr || attrName == aria_valuetextAttr)
1500         postNotification(element, AXObjectCache::AXValueChanged);
1501     else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr)
1502         textChanged(element);
1503     else if (attrName == aria_checkedAttr)
1504         checkedStateChanged(element);
1505     else if (attrName == aria_selectedAttr)
1506         selectedChildrenChanged(element);
1507     else if (attrName == aria_expandedAttr)
1508         handleAriaExpandedChange(element);
1509     else if (attrName == aria_hiddenAttr)
1510         childrenChanged(element->parentNode(), element);
1511     else if (attrName == aria_invalidAttr)
1512         postNotification(element, AXObjectCache::AXInvalidStatusChanged);
1513     else if (attrName == aria_modalAttr)
1514         handleModalChange(element);
1515     else if (attrName == aria_currentAttr)
1516         postNotification(element, AXObjectCache::AXCurrentChanged);
1517     else if (attrName == aria_disabledAttr)
1518         postNotification(element, AXObjectCache::AXDisabledStateChanged);
1519     else if (attrName == aria_pressedAttr)
1520         postNotification(element, AXObjectCache::AXPressedStateChanged);
1521     else if (attrName == aria_readonlyAttr)
1522         postNotification(element, AXObjectCache::AXReadOnlyStatusChanged);
1523     else if (attrName == aria_requiredAttr)
1524         postNotification(element, AXObjectCache::AXRequiredStatusChanged);
1525     else
1526         postNotification(element, AXObjectCache::AXAriaAttributeChanged);
1527 }
1528
1529 void AXObjectCache::handleModalChange(Node* node)
1530 {
1531     if (!is<Element>(node))
1532         return;
1533     
1534     if (!nodeHasRole(node, "dialog") && !nodeHasRole(node, "alertdialog"))
1535         return;
1536     
1537     stopCachingComputedObjectAttributes();
1538     if (equalLettersIgnoringASCIICase(downcast<Element>(*node).attributeWithoutSynchronization(aria_modalAttr), "true")) {
1539         // Add the newly modified node to the modal nodes set, and set it to be the current valid aria modal node.
1540         // We will recompute the current valid aria modal node in modalNode() when this node is not visible.
1541         m_modalNodesSet.add(node);
1542         m_currentModalNode = node;
1543     } else {
1544         // Remove the node from the modal nodes set. There might be other visible modal nodes, so we recompute here.
1545         m_modalNodesSet.remove(node);
1546         updateCurrentModalNode();
1547     }
1548     if (m_currentModalNode)
1549         focusModalNode();
1550     
1551     startCachingComputedObjectAttributesUntilTreeMutates();
1552 }
1553
1554 void AXObjectCache::labelChanged(Element* element)
1555 {
1556     ASSERT(is<HTMLLabelElement>(*element));
1557     auto correspondingControl = downcast<HTMLLabelElement>(*element).control();
1558     deferTextChangedIfNeeded(correspondingControl.get());
1559 }
1560
1561 void AXObjectCache::recomputeIsIgnored(RenderObject* renderer)
1562 {
1563     if (AccessibilityObject* obj = get(renderer))
1564         obj->notifyIfIgnoredValueChanged();
1565 }
1566
1567 void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates()
1568 {
1569     if (!m_computedObjectAttributeCache)
1570         m_computedObjectAttributeCache = std::make_unique<AXComputedObjectAttributeCache>();
1571 }
1572
1573 void AXObjectCache::stopCachingComputedObjectAttributes()
1574 {
1575     m_computedObjectAttributeCache = nullptr;
1576 }
1577
1578 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
1579 {
1580     if (!isNodeInUse(textMarkerData.node))
1581         return VisiblePosition();
1582     
1583     // FIXME: Accessability should make it clear these are DOM-compliant offsets or store Position objects.
1584     VisiblePosition visiblePos = VisiblePosition(createLegacyEditingPosition(textMarkerData.node, textMarkerData.offset), textMarkerData.affinity);
1585     Position deepPos = visiblePos.deepEquivalent();
1586     if (deepPos.isNull())
1587         return VisiblePosition();
1588     
1589     RenderObject* renderer = deepPos.deprecatedNode()->renderer();
1590     if (!renderer)
1591         return VisiblePosition();
1592     
1593     AXObjectCache* cache = renderer->document().axObjectCache();
1594     if (!cache->m_idsInUse.contains(textMarkerData.axID))
1595         return VisiblePosition();
1596
1597     return visiblePos;
1598 }
1599
1600 CharacterOffset AXObjectCache::characterOffsetForTextMarkerData(TextMarkerData& textMarkerData)
1601 {
1602     if (!isNodeInUse(textMarkerData.node))
1603         return CharacterOffset();
1604     
1605     if (textMarkerData.ignored)
1606         return CharacterOffset();
1607     
1608     CharacterOffset result = CharacterOffset(textMarkerData.node, textMarkerData.characterStartIndex, textMarkerData.characterOffset);
1609     // When we are at a line wrap and the VisiblePosition is upstream, it means the text marker is at the end of the previous line.
1610     // We use the previous CharacterOffset so that it will match the Range.
1611     if (textMarkerData.affinity == UPSTREAM)
1612         return previousCharacterOffset(result, false);
1613     return result;
1614 }
1615
1616 CharacterOffset AXObjectCache::traverseToOffsetInRange(RefPtr<Range>range, int offset, TraverseOption option, bool stayWithinRange)
1617 {
1618     if (!range)
1619         return CharacterOffset();
1620     
1621     bool toNodeEnd = option & TraverseOptionToNodeEnd;
1622     bool validateOffset = option & TraverseOptionValidateOffset;
1623     bool doNotEnterTextControls = option & TraverseOptionDoNotEnterTextControls;
1624     
1625     int offsetInCharacter = 0;
1626     int cumulativeOffset = 0;
1627     int remaining = 0;
1628     int lastLength = 0;
1629     Node* currentNode = nullptr;
1630     bool finished = false;
1631     int lastStartOffset = 0;
1632     
1633     TextIterator iterator(range.get(), doNotEnterTextControls ? TextIteratorDefaultBehavior : TextIteratorEntersTextControls);
1634     
1635     // When the range has zero length, there might be replaced node or brTag that we need to increment the characterOffset.
1636     if (iterator.atEnd()) {
1637         currentNode = &range->startContainer();
1638         lastStartOffset = range->startOffset();
1639         if (offset > 0 || toNodeEnd) {
1640             if (AccessibilityObject::replacedNodeNeedsCharacter(currentNode) || (currentNode->renderer() && currentNode->renderer()->isBR()))
1641                 cumulativeOffset++;
1642             lastLength = cumulativeOffset;
1643             
1644             // When going backwards, stayWithinRange is false.
1645             // Here when we don't have any character to move and we are going backwards, we traverse to the previous node.
1646             if (!lastLength && toNodeEnd && !stayWithinRange) {
1647                 if (Node* preNode = previousNode(currentNode))
1648                     return traverseToOffsetInRange(rangeForNodeContents(preNode), offset, option);
1649                 return CharacterOffset();
1650             }
1651         }
1652     }
1653     
1654     // Sometimes text contents in a node are splitted into several iterations, so that iterator.range()->startOffset()
1655     // might not be the correct character count. Here we use a previousNode object to keep track of that.
1656     Node* previousNode = nullptr;
1657     for (; !iterator.atEnd(); iterator.advance()) {
1658         int currentLength = iterator.text().length();
1659         bool hasReplacedNodeOrBR = false;
1660         
1661         Node& node = iterator.range()->startContainer();
1662         currentNode = &node;
1663         
1664         // When currentLength == 0, we check if there's any replaced node.
1665         // If not, we skip the node with no length.
1666         if (!currentLength) {
1667             int subOffset = iterator.range()->startOffset();
1668             Node* childNode = node.traverseToChildAt(subOffset);
1669             if (AccessibilityObject::replacedNodeNeedsCharacter(childNode)) {
1670                 cumulativeOffset++;
1671                 currentLength++;
1672                 currentNode = childNode;
1673                 hasReplacedNodeOrBR = true;
1674             } else
1675                 continue;
1676         } else {
1677             // Ignore space, new line, tag node.
1678             if (currentLength == 1) {
1679                 if (isHTMLSpace(iterator.text()[0])) {
1680                     // If the node has BR tag, we want to set the currentNode to it.
1681                     int subOffset = iterator.range()->startOffset();
1682                     Node* childNode = node.traverseToChildAt(subOffset);
1683                     if (childNode && childNode->renderer() && childNode->renderer()->isBR()) {
1684                         currentNode = childNode;
1685                         hasReplacedNodeOrBR = true;
1686                     } else if (auto* shadowHost = currentNode->shadowHost()) {
1687                         // Since we are entering text controls, we should set the currentNode
1688                         // to be the shadow host when there's no content.
1689                         if (nodeIsTextControl(shadowHost) && currentNode->isShadowRoot()) {
1690                             currentNode = shadowHost;
1691                             continue;
1692                         }
1693                     } else if (currentNode != previousNode) {
1694                         // We should set the start offset and length for the current node in case this is the last iteration.
1695                         lastStartOffset = 1;
1696                         lastLength = 0;
1697                         continue;
1698                     }
1699                 }
1700             }
1701             cumulativeOffset += currentLength;
1702         }
1703
1704         if (currentNode == previousNode) {
1705             lastLength += currentLength;
1706             lastStartOffset = iterator.range()->endOffset() - lastLength;
1707         }
1708         else {
1709             lastLength = currentLength;
1710             lastStartOffset = hasReplacedNodeOrBR ? 0 : iterator.range()->startOffset();
1711         }
1712         
1713         // Break early if we have advanced enough characters.
1714         bool offsetLimitReached = validateOffset ? cumulativeOffset + lastStartOffset >= offset : cumulativeOffset >= offset;
1715         if (!toNodeEnd && offsetLimitReached) {
1716             offsetInCharacter = validateOffset ? std::max(offset - lastStartOffset, 0) : offset - (cumulativeOffset - lastLength);
1717             finished = true;
1718             break;
1719         }
1720         previousNode = currentNode;
1721     }
1722     
1723     if (!finished) {
1724         offsetInCharacter = lastLength;
1725         if (!toNodeEnd)
1726             remaining = offset - cumulativeOffset;
1727     }
1728     
1729     // Sometimes when we are getting the end CharacterOffset of a line range, the TextIterator will emit an extra space at the end
1730     // and make the character count greater than the Range's end offset.
1731     if (toNodeEnd && currentNode->isTextNode() && currentNode == &range->endContainer() && static_cast<int>(range->endOffset()) < lastStartOffset + offsetInCharacter)
1732         offsetInCharacter = range->endOffset() - lastStartOffset;
1733     
1734     return CharacterOffset(currentNode, lastStartOffset, offsetInCharacter, remaining);
1735 }
1736
1737 int AXObjectCache::lengthForRange(Range* range)
1738 {
1739     if (!range)
1740         return -1;
1741     
1742     int length = 0;
1743     for (TextIterator it(range); !it.atEnd(); it.advance()) {
1744         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1745         if (it.text().length())
1746             length += it.text().length();
1747         else {
1748             // locate the node and starting offset for this replaced range
1749             Node& node = it.range()->startContainer();
1750             int offset = it.range()->startOffset();
1751             if (AccessibilityObject::replacedNodeNeedsCharacter(node.traverseToChildAt(offset)))
1752                 ++length;
1753         }
1754     }
1755         
1756     return length;
1757 }
1758
1759 RefPtr<Range> AXObjectCache::rangeForNodeContents(Node* node)
1760 {
1761     if (!node)
1762         return nullptr;
1763     Document* document = &node->document();
1764     if (!document)
1765         return nullptr;
1766     auto range = Range::create(*document);
1767     if (AccessibilityObject::replacedNodeNeedsCharacter(node)) {
1768         // For replaced nodes without children, the node itself is included in the range.
1769         if (range->selectNode(*node).hasException())
1770             return nullptr;
1771     } else {
1772         if (range->selectNodeContents(*node).hasException())
1773             return nullptr;
1774     }
1775     return WTFMove(range);
1776 }
1777     
1778 RefPtr<Range> AXObjectCache::rangeMatchesTextNearRange(RefPtr<Range> originalRange, const String& matchText)
1779 {
1780     if (!originalRange)
1781         return nullptr;
1782     
1783     // Create a large enough range for searching the text within.
1784     unsigned textLength = matchText.length();
1785     auto startPosition = visiblePositionForPositionWithOffset(originalRange->startPosition(), -textLength);
1786     auto endPosition = visiblePositionForPositionWithOffset(originalRange->startPosition(), 2 * textLength);
1787     
1788     if (startPosition.isNull())
1789         startPosition = firstPositionInOrBeforeNode(&originalRange->startContainer());
1790     if (endPosition.isNull())
1791         endPosition = lastPositionInOrAfterNode(&originalRange->endContainer());
1792     
1793     RefPtr<Range> searchRange = Range::create(m_document, startPosition, endPosition);
1794     if (!searchRange || searchRange->collapsed())
1795         return nullptr;
1796     
1797     RefPtr<Range> range = Range::create(m_document, startPosition, originalRange->startPosition());
1798     unsigned targetOffset = TextIterator::rangeLength(range.get(), true);
1799     return findClosestPlainText(*searchRange.get(), matchText, { }, targetOffset);
1800 }
1801
1802 static bool isReplacedNodeOrBR(Node* node)
1803 {
1804     return node && (AccessibilityObject::replacedNodeNeedsCharacter(node) || node->hasTagName(brTag));
1805 }
1806
1807 static bool characterOffsetsInOrder(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
1808 {
1809     if (characterOffset1.isNull() || characterOffset2.isNull())
1810         return false;
1811     
1812     if (characterOffset1.node == characterOffset2.node)
1813         return characterOffset1.offset <= characterOffset2.offset;
1814     
1815     Node* node1 = characterOffset1.node;
1816     Node* node2 = characterOffset2.node;
1817     if (!node1->offsetInCharacters() && !isReplacedNodeOrBR(node1) && node1->hasChildNodes())
1818         node1 = node1->traverseToChildAt(characterOffset1.offset);
1819     if (!node2->offsetInCharacters() && !isReplacedNodeOrBR(node2) && node2->hasChildNodes())
1820         node2 = node2->traverseToChildAt(characterOffset2.offset);
1821     
1822     if (!node1 || !node2)
1823         return false;
1824     
1825     RefPtr<Range> range1 = AXObjectCache::rangeForNodeContents(node1);
1826     RefPtr<Range> range2 = AXObjectCache::rangeForNodeContents(node2);
1827
1828     if (!range2)
1829         return true;
1830     if (!range1)
1831         return false;
1832     auto result = range1->compareBoundaryPoints(Range::START_TO_START, *range2);
1833     if (result.hasException())
1834         return true;
1835     return result.releaseReturnValue() <= 0;
1836 }
1837
1838 static Node* resetNodeAndOffsetForReplacedNode(Node* replacedNode, int& offset, int characterCount)
1839 {
1840     // Use this function to include the replaced node itself in the range we are creating.
1841     if (!replacedNode)
1842         return nullptr;
1843     
1844     RefPtr<Range> nodeRange = AXObjectCache::rangeForNodeContents(replacedNode);
1845     int nodeLength = TextIterator::rangeLength(nodeRange.get());
1846     offset = characterCount <= nodeLength ? replacedNode->computeNodeIndex() : replacedNode->computeNodeIndex() + 1;
1847     return replacedNode->parentNode();
1848 }
1849
1850 static bool setRangeStartOrEndWithCharacterOffset(Range& range, const CharacterOffset& characterOffset, bool isStart)
1851 {
1852     if (characterOffset.isNull())
1853         return false;
1854     
1855     int offset = characterOffset.startIndex + characterOffset.offset;
1856     Node* node = characterOffset.node;
1857     ASSERT(node);
1858     
1859     bool replacedNodeOrBR = isReplacedNodeOrBR(node);
1860     // For the non text node that has no children, we should create the range with its parent, otherwise the range would be collapsed.
1861     // Example: <div contenteditable="true"></div>, we want the range to include the div element.
1862     bool noChildren = !replacedNodeOrBR && !node->isTextNode() && !node->hasChildNodes();
1863     int characterCount = noChildren ? (isStart ? 0 : 1) : characterOffset.offset;
1864     
1865     if (replacedNodeOrBR || noChildren)
1866         node = resetNodeAndOffsetForReplacedNode(node, offset, characterCount);
1867     
1868     if (!node)
1869         return false;
1870
1871     if (isStart) {
1872         if (range.setStart(*node, offset).hasException())
1873             return false;
1874     } else {
1875         if (range.setEnd(*node, offset).hasException())
1876             return false;
1877     }
1878
1879     return true;
1880 }
1881
1882 RefPtr<Range> AXObjectCache::rangeForUnorderedCharacterOffsets(const CharacterOffset& characterOffset1, const CharacterOffset& characterOffset2)
1883 {
1884     if (characterOffset1.isNull() || characterOffset2.isNull())
1885         return nullptr;
1886     
1887     bool alreadyInOrder = characterOffsetsInOrder(characterOffset1, characterOffset2);
1888     CharacterOffset startCharacterOffset = alreadyInOrder ? characterOffset1 : characterOffset2;
1889     CharacterOffset endCharacterOffset = alreadyInOrder ? characterOffset2 : characterOffset1;
1890     
1891     auto result = Range::create(m_document);
1892     if (!setRangeStartOrEndWithCharacterOffset(result, startCharacterOffset, true))
1893         return nullptr;
1894     if (!setRangeStartOrEndWithCharacterOffset(result, endCharacterOffset, false))
1895         return nullptr;
1896     return WTFMove(result);
1897 }
1898
1899 void AXObjectCache::setTextMarkerDataWithCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
1900 {
1901     if (characterOffset.isNull())
1902         return;
1903     
1904     Node* domNode = characterOffset.node;
1905     if (is<HTMLInputElement>(*domNode) && downcast<HTMLInputElement>(*domNode).isPasswordField()) {
1906         textMarkerData.ignored = true;
1907         return;
1908     }
1909     
1910     RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
1911     if (!obj)
1912         return;
1913     
1914     // Convert to visible position.
1915     VisiblePosition visiblePosition = visiblePositionFromCharacterOffset(characterOffset);
1916     int vpOffset = 0;
1917     if (!visiblePosition.isNull()) {
1918         Position deepPos = visiblePosition.deepEquivalent();
1919         vpOffset = deepPos.deprecatedEditingOffset();
1920     }
1921     
1922     textMarkerData.axID = obj.get()->axObjectID();
1923     textMarkerData.node = domNode;
1924     textMarkerData.characterOffset = characterOffset.offset;
1925     textMarkerData.characterStartIndex = characterOffset.startIndex;
1926     textMarkerData.offset = vpOffset;
1927     textMarkerData.affinity = visiblePosition.affinity();
1928     
1929     this->setNodeInUse(domNode);
1930 }
1931
1932 CharacterOffset AXObjectCache::startOrEndCharacterOffsetForRange(RefPtr<Range> range, bool isStart, bool enterTextControls)
1933 {
1934     if (!range)
1935         return CharacterOffset();
1936     
1937     // When getting the end CharacterOffset at node boundary, we don't want to collapse to the previous node.
1938     if (!isStart && !range->endOffset())
1939         return characterOffsetForNodeAndOffset(range->endContainer(), 0, TraverseOptionIncludeStart);
1940     
1941     // If it's end text marker, we want to go to the end of the range, and stay within the range.
1942     bool stayWithinRange = !isStart;
1943     
1944     Node& endNode = range->endContainer();
1945     if (endNode.offsetInCharacters() && !isStart)
1946         return traverseToOffsetInRange(rangeForNodeContents(&endNode), range->endOffset(), TraverseOptionValidateOffset);
1947     
1948     Ref<Range> copyRange = *range;
1949     // Change the start of the range, so the character offset starts from node beginning.
1950     int offset = 0;
1951     Node& node = copyRange->startContainer();
1952     if (node.offsetInCharacters()) {
1953         CharacterOffset nodeStartOffset = traverseToOffsetInRange(rangeForNodeContents(&node), range->startOffset(), TraverseOptionValidateOffset);
1954         if (isStart)
1955             return nodeStartOffset;
1956         copyRange = Range::create(range->ownerDocument(), &range->startContainer(), 0, &range->endContainer(), range->endOffset());
1957         offset += nodeStartOffset.offset;
1958     }
1959     
1960     TraverseOption options = isStart ? TraverseOptionDefault : TraverseOptionToNodeEnd;
1961     if (!enterTextControls)
1962         options = static_cast<TraverseOption>(options | TraverseOptionDoNotEnterTextControls);
1963     return traverseToOffsetInRange(WTFMove(copyRange), offset, options, stayWithinRange);
1964 }
1965
1966 void AXObjectCache::startOrEndTextMarkerDataForRange(TextMarkerData& textMarkerData, RefPtr<Range> range, bool isStart)
1967 {
1968     // This memory must be zero'd so instances of TextMarkerData can be tested for byte-equivalence.
1969     // Warning: This is risky and bad because TextMarkerData is a nontrivial type.
1970     memset(static_cast<void*>(&textMarkerData), 0, sizeof(TextMarkerData));
1971     
1972     CharacterOffset characterOffset = startOrEndCharacterOffsetForRange(range, isStart);
1973     if (characterOffset.isNull())
1974         return;
1975     
1976     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
1977 }
1978
1979 CharacterOffset AXObjectCache::characterOffsetForNodeAndOffset(Node& node, int offset, TraverseOption option)
1980 {
1981     Node* domNode = &node;
1982     if (!domNode)
1983         return CharacterOffset();
1984     
1985     bool toNodeEnd = option & TraverseOptionToNodeEnd;
1986     bool includeStart = option & TraverseOptionIncludeStart;
1987     
1988     // ignoreStart is used to determine if we should go to previous node or
1989     // stay in current node when offset is 0.
1990     if (!toNodeEnd && (offset < 0 || (!offset && !includeStart))) {
1991         // Set the offset to the amount of characters we need to go backwards.
1992         offset = - offset;
1993         CharacterOffset charOffset = CharacterOffset();
1994         while (offset >= 0 && charOffset.offset <= offset) {
1995             offset -= charOffset.offset;
1996             domNode = previousNode(domNode);
1997             if (domNode) {
1998                 charOffset = characterOffsetForNodeAndOffset(*domNode, 0, TraverseOptionToNodeEnd);
1999             } else
2000                 return CharacterOffset();
2001             if (charOffset.offset == offset)
2002                 break;
2003         }
2004         if (offset > 0)
2005             charOffset = characterOffsetForNodeAndOffset(*charOffset.node, charOffset.offset - offset, TraverseOptionIncludeStart);
2006         return charOffset;
2007     }
2008     
2009     RefPtr<Range> range = rangeForNodeContents(domNode);
2010
2011     // Traverse the offset amount of characters forward and see if there's remaining offsets.
2012     // Keep traversing to the next node when there's remaining offsets.
2013     CharacterOffset characterOffset = traverseToOffsetInRange(range, offset, option);
2014     while (!characterOffset.isNull() && characterOffset.remaining() && !toNodeEnd) {
2015         domNode = nextNode(domNode);
2016         if (!domNode)
2017             return CharacterOffset();
2018         range = rangeForNodeContents(domNode);
2019         characterOffset = traverseToOffsetInRange(range, characterOffset.remaining(), option);
2020     }
2021     
2022     return characterOffset;
2023 }
2024
2025 void AXObjectCache::textMarkerDataForCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
2026 {
2027     // This memory must be zero'd so instances of TextMarkerData can be tested for byte-equivalence.
2028     // Warning: This is risky and bad because TextMarkerData is a nontrivial type.
2029     memset(static_cast<void*>(&textMarkerData), 0, sizeof(TextMarkerData));
2030
2031     setTextMarkerDataWithCharacterOffset(textMarkerData, characterOffset);
2032 }
2033
2034 bool AXObjectCache::shouldSkipBoundary(const CharacterOffset& previous, const CharacterOffset& next)
2035 {
2036     // Match the behavior of VisiblePosition, we should skip the node boundary when there's no visual space or new line character.
2037     if (previous.isNull() || next.isNull())
2038         return false;
2039     
2040     if (previous.node == next.node)
2041         return false;
2042     
2043     if (next.startIndex > 0 || next.offset > 0)
2044         return false;
2045     
2046     CharacterOffset newLine = startCharacterOffsetOfLine(next);
2047     if (next.isEqual(newLine))
2048         return false;
2049     
2050     return true;
2051 }
2052     
2053 void AXObjectCache::textMarkerDataForNextCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
2054 {
2055     CharacterOffset next = characterOffset;
2056     CharacterOffset previous = characterOffset;
2057     bool shouldContinue;
2058     do {
2059         shouldContinue = false;
2060         next = nextCharacterOffset(next, false);
2061         if (shouldSkipBoundary(previous, next))
2062             next = nextCharacterOffset(next, false);
2063         textMarkerDataForCharacterOffset(textMarkerData, next);
2064         
2065         // We should skip next CharactetOffset if it's visually the same.
2066         if (!lengthForRange(rangeForUnorderedCharacterOffsets(previous, next).get()))
2067             shouldContinue = true;
2068         previous = next;
2069     } while (textMarkerData.ignored || shouldContinue);
2070 }
2071
2072 void AXObjectCache::textMarkerDataForPreviousCharacterOffset(TextMarkerData& textMarkerData, const CharacterOffset& characterOffset)
2073 {
2074     CharacterOffset previous = characterOffset;
2075     CharacterOffset next = characterOffset;
2076     bool shouldContinue;
2077     do {
2078         shouldContinue = false;
2079         previous = previousCharacterOffset(previous, false);
2080         textMarkerDataForCharacterOffset(textMarkerData, previous);
2081         
2082         // We should skip previous CharactetOffset if it's visually the same.
2083         if (!lengthForRange(rangeForUnorderedCharacterOffsets(previous, next).get()))
2084             shouldContinue = true;
2085         next = previous;
2086     } while (textMarkerData.ignored || shouldContinue);
2087 }
2088
2089 Node* AXObjectCache::nextNode(Node* node) const
2090 {
2091     if (!node)
2092         return nullptr;
2093     
2094     return NodeTraversal::nextSkippingChildren(*node);
2095 }
2096
2097 Node* AXObjectCache::previousNode(Node* node) const
2098 {
2099     if (!node)
2100         return nullptr;
2101     
2102     // First child of body shouldn't have previous node.
2103     if (node->parentNode() && node->parentNode()->renderer() && node->parentNode()->renderer()->isBody() && !node->previousSibling())
2104         return nullptr;
2105
2106     return NodeTraversal::previousSkippingChildren(*node);
2107 }
2108
2109 VisiblePosition AXObjectCache::visiblePositionFromCharacterOffset(const CharacterOffset& characterOffset)
2110 {
2111     if (characterOffset.isNull())
2112         return VisiblePosition();
2113     
2114     // Create a collapsed range and use that to form a VisiblePosition, so that the case with
2115     // composed characters will be covered.
2116     auto range = rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
2117     return range ? VisiblePosition(range->startPosition()) : VisiblePosition();
2118 }
2119
2120 CharacterOffset AXObjectCache::characterOffsetFromVisiblePosition(const VisiblePosition& visiblePos)
2121 {
2122     if (visiblePos.isNull())
2123         return CharacterOffset();
2124     
2125     Position deepPos = visiblePos.deepEquivalent();
2126     Node* domNode = deepPos.deprecatedNode();
2127     ASSERT(domNode);
2128     
2129     if (domNode->offsetInCharacters())
2130         return traverseToOffsetInRange(rangeForNodeContents(domNode), deepPos.deprecatedEditingOffset(), TraverseOptionValidateOffset);
2131     
2132     RefPtr<AccessibilityObject> obj = this->getOrCreate(domNode);
2133     if (!obj)
2134         return CharacterOffset();
2135     
2136     // Use nextVisiblePosition to calculate how many characters we need to traverse to the current position.
2137     VisiblePositionRange visiblePositionRange = obj->visiblePositionRange();
2138     VisiblePosition visiblePosition = visiblePositionRange.start;
2139     int characterOffset = 0;
2140     Position currentPosition = visiblePosition.deepEquivalent();
2141     
2142     VisiblePosition previousVisiblePos;
2143     while (!currentPosition.isNull() && !deepPos.equals(currentPosition)) {
2144         previousVisiblePos = visiblePosition;
2145         visiblePosition = obj->nextVisiblePosition(visiblePosition);
2146         currentPosition = visiblePosition.deepEquivalent();
2147         Position previousPosition = previousVisiblePos.deepEquivalent();
2148         // Sometimes nextVisiblePosition will give the same VisiblePostion,
2149         // we break here to avoid infinite loop.
2150         if (currentPosition.equals(previousPosition))
2151             break;
2152         characterOffset++;
2153         
2154         // When VisiblePostion moves to next node, it will count the leading line break as
2155         // 1 offset, which we shouldn't include in CharacterOffset.
2156         if (currentPosition.deprecatedNode() != previousPosition.deprecatedNode()) {
2157             if (visiblePosition.characterBefore() == '\n')
2158                 characterOffset--;
2159         } else {
2160             // Sometimes VisiblePosition will move multiple characters, like emoji.
2161             if (currentPosition.deprecatedNode()->offsetInCharacters())
2162                 characterOffset += currentPosition.offsetInContainerNode() - previousPosition.offsetInContainerNode() - 1;
2163         }
2164     }
2165     
2166     // Sometimes when the node is a replaced node and is ignored in accessibility, we get a wrong CharacterOffset from it.
2167     CharacterOffset result = traverseToOffsetInRange(rangeForNodeContents(obj->node()), characterOffset);
2168     if (result.remainingOffset > 0 && !result.isNull() && isRendererReplacedElement(result.node->renderer()))
2169         result.offset += result.remainingOffset;
2170     return result;
2171 }
2172
2173 AccessibilityObject* AXObjectCache::accessibilityObjectForTextMarkerData(TextMarkerData& textMarkerData)
2174 {
2175     if (!isNodeInUse(textMarkerData.node))
2176         return nullptr;
2177     
2178     Node* domNode = textMarkerData.node;
2179     return this->getOrCreate(domNode);
2180 }
2181
2182 std::optional<TextMarkerData> AXObjectCache::textMarkerDataForVisiblePosition(const VisiblePosition& visiblePos)
2183 {
2184     if (visiblePos.isNull())
2185         return std::nullopt;
2186
2187     Position deepPos = visiblePos.deepEquivalent();
2188     Node* domNode = deepPos.deprecatedNode();
2189     ASSERT(domNode);
2190     if (!domNode)
2191         return std::nullopt;
2192
2193     if (is<HTMLInputElement>(*domNode) && downcast<HTMLInputElement>(*domNode).isPasswordField())
2194         return std::nullopt;
2195
2196     // If the visible position has an anchor type referring to a node other than the anchored node, we should
2197     // set the text marker data with CharacterOffset so that the offset will correspond to the node.
2198     CharacterOffset characterOffset = characterOffsetFromVisiblePosition(visiblePos);
2199     if (deepPos.anchorType() == Position::PositionIsAfterAnchor || deepPos.anchorType() == Position::PositionIsAfterChildren) {
2200         TextMarkerData textMarkerData;
2201         textMarkerDataForCharacterOffset(textMarkerData, characterOffset);
2202         return textMarkerData;
2203     }
2204
2205     // find or create an accessibility object for this node
2206     AXObjectCache* cache = domNode->document().axObjectCache();
2207     RefPtr<AccessibilityObject> obj = cache->getOrCreate(domNode);
2208
2209     // This memory must be zero'd so instances of TextMarkerData can be tested for byte-equivalence.
2210     // Warning: This is risky and bad because TextMarkerData is a nontrivial type.
2211     TextMarkerData textMarkerData;
2212     memset(static_cast<void*>(&textMarkerData), 0, sizeof(TextMarkerData));
2213     
2214     textMarkerData.axID = obj.get()->axObjectID();
2215     textMarkerData.node = domNode;
2216     textMarkerData.offset = deepPos.deprecatedEditingOffset();
2217     textMarkerData.affinity = visiblePos.affinity();
2218
2219     textMarkerData.characterOffset = characterOffset.offset;
2220     textMarkerData.characterStartIndex = characterOffset.startIndex;
2221
2222     cache->setNodeInUse(domNode);
2223
2224     return textMarkerData;
2225 }
2226
2227 // This function exits as a performance optimization to avoid a synchronous layout.
2228 std::optional<TextMarkerData> AXObjectCache::textMarkerDataForFirstPositionInTextControl(HTMLTextFormControlElement& textControl)
2229 {
2230     if (is<HTMLInputElement>(textControl) && downcast<HTMLInputElement>(textControl).isPasswordField())
2231         return std::nullopt;
2232
2233     AXObjectCache* cache = textControl.document().axObjectCache();
2234     RefPtr<AccessibilityObject> obj = cache->getOrCreate(&textControl);
2235     if (!obj)
2236         return std::nullopt;
2237
2238     // This memory must be zero'd so instances of TextMarkerData can be tested for byte-equivalence.
2239     // Warning: This is risky and bad because TextMarkerData is a nontrivial type.
2240     TextMarkerData textMarkerData;
2241     memset(static_cast<void*>(&textMarkerData), 0, sizeof(TextMarkerData));
2242     
2243     textMarkerData.axID = obj.get()->axObjectID();
2244     textMarkerData.node = &textControl;
2245
2246     cache->setNodeInUse(&textControl);
2247
2248     return textMarkerData;
2249 }
2250
2251 CharacterOffset AXObjectCache::nextCharacterOffset(const CharacterOffset& characterOffset, bool ignoreNextNodeStart)
2252 {
2253     if (characterOffset.isNull())
2254         return CharacterOffset();
2255     
2256     // We don't always move one 'character' at a time since there might be composed characters.
2257     int nextOffset = Position::uncheckedNextOffset(characterOffset.node, characterOffset.offset);
2258     CharacterOffset next = characterOffsetForNodeAndOffset(*characterOffset.node, nextOffset);
2259     
2260     // To be consistent with VisiblePosition, we should consider the case that current node end to next node start counts 1 offset.
2261     if (!ignoreNextNodeStart && !next.isNull() && !isReplacedNodeOrBR(next.node) && next.node != characterOffset.node) {
2262         int length = TextIterator::rangeLength(rangeForUnorderedCharacterOffsets(characterOffset, next).get());
2263         if (length > nextOffset - characterOffset.offset)
2264             next = characterOffsetForNodeAndOffset(*next.node, 0, TraverseOptionIncludeStart);
2265     }
2266     
2267     return next;
2268 }
2269
2270 CharacterOffset AXObjectCache::previousCharacterOffset(const CharacterOffset& characterOffset, bool ignorePreviousNodeEnd)
2271 {
2272     if (characterOffset.isNull())
2273         return CharacterOffset();
2274     
2275     // To be consistent with VisiblePosition, we should consider the case that current node start to previous node end counts 1 offset.
2276     if (!ignorePreviousNodeEnd && !characterOffset.offset)
2277         return characterOffsetForNodeAndOffset(*characterOffset.node, 0);
2278     
2279     // We don't always move one 'character' a time since there might be composed characters.
2280     int previousOffset = Position::uncheckedPreviousOffset(characterOffset.node, characterOffset.offset);
2281     return characterOffsetForNodeAndOffset(*characterOffset.node, previousOffset, TraverseOptionIncludeStart);
2282 }
2283
2284 CharacterOffset AXObjectCache::startCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
2285 {
2286     if (characterOffset.isNull())
2287         return CharacterOffset();
2288     
2289     CharacterOffset c = characterOffset;
2290     if (side == RightWordIfOnBoundary) {
2291         CharacterOffset endOfParagraph = endCharacterOffsetOfParagraph(c);
2292         if (c.isEqual(endOfParagraph))
2293             return c;
2294         
2295         // We should consider the node boundary that splits words. Otherwise VoiceOver won't see it as space.
2296         c = nextCharacterOffset(characterOffset, false);
2297         if (shouldSkipBoundary(characterOffset, c))
2298             c = nextCharacterOffset(c, false);
2299         if (c.isNull())
2300             return characterOffset;
2301     }
2302     
2303     return previousBoundary(c, startWordBoundary);
2304 }
2305
2306 CharacterOffset AXObjectCache::endCharacterOffsetOfWord(const CharacterOffset& characterOffset, EWordSide side)
2307 {
2308     if (characterOffset.isNull())
2309         return CharacterOffset();
2310     
2311     CharacterOffset c = characterOffset;
2312     if (side == LeftWordIfOnBoundary) {
2313         CharacterOffset startOfParagraph = startCharacterOffsetOfParagraph(c);
2314         if (c.isEqual(startOfParagraph))
2315             return c;
2316         
2317         c = previousCharacterOffset(characterOffset);
2318         if (c.isNull())
2319             return characterOffset;
2320     } else {
2321         CharacterOffset endOfParagraph = endCharacterOffsetOfParagraph(characterOffset);
2322         if (characterOffset.isEqual(endOfParagraph))
2323             return characterOffset;
2324     }
2325     
2326     return nextBoundary(c, endWordBoundary);
2327 }
2328
2329 CharacterOffset AXObjectCache::previousWordStartCharacterOffset(const CharacterOffset& characterOffset)
2330 {
2331     if (characterOffset.isNull())
2332         return CharacterOffset();
2333     
2334     CharacterOffset previousOffset = previousCharacterOffset(characterOffset);
2335     if (previousOffset.isNull())
2336         return CharacterOffset();
2337     
2338     return startCharacterOffsetOfWord(previousOffset, RightWordIfOnBoundary);
2339 }
2340
2341 CharacterOffset AXObjectCache::nextWordEndCharacterOffset(const CharacterOffset& characterOffset)
2342 {
2343     if (characterOffset.isNull())
2344         return CharacterOffset();
2345     
2346     CharacterOffset nextOffset = nextCharacterOffset(characterOffset);
2347     if (nextOffset.isNull())
2348         return CharacterOffset();
2349     
2350     return endCharacterOffsetOfWord(nextOffset, LeftWordIfOnBoundary);
2351 }
2352
2353 RefPtr<Range> AXObjectCache::leftWordRange(const CharacterOffset& characterOffset)
2354 {
2355     CharacterOffset start = startCharacterOffsetOfWord(characterOffset, LeftWordIfOnBoundary);
2356     CharacterOffset end = endCharacterOffsetOfWord(start);
2357     return rangeForUnorderedCharacterOffsets(start, end);
2358 }
2359
2360 RefPtr<Range> AXObjectCache::rightWordRange(const CharacterOffset& characterOffset)
2361 {
2362     CharacterOffset start = startCharacterOffsetOfWord(characterOffset, RightWordIfOnBoundary);
2363     CharacterOffset end = endCharacterOffsetOfWord(start);
2364     return rangeForUnorderedCharacterOffsets(start, end);
2365 }
2366
2367 static UChar32 characterForCharacterOffset(const CharacterOffset& characterOffset)
2368 {
2369     if (characterOffset.isNull() || !characterOffset.node->isTextNode())
2370         return 0;
2371     
2372     UChar32 ch = 0;
2373     unsigned offset = characterOffset.startIndex + characterOffset.offset;
2374     if (offset < characterOffset.node->textContent().length())
2375         U16_NEXT(characterOffset.node->textContent(), offset, characterOffset.node->textContent().length(), ch);
2376     return ch;
2377 }
2378
2379 UChar32 AXObjectCache::characterAfter(const CharacterOffset& characterOffset)
2380 {
2381     return characterForCharacterOffset(nextCharacterOffset(characterOffset));
2382 }
2383
2384 UChar32 AXObjectCache::characterBefore(const CharacterOffset& characterOffset)
2385 {
2386     return characterForCharacterOffset(characterOffset);
2387 }
2388
2389 static bool characterOffsetNodeIsBR(const CharacterOffset& characterOffset)
2390 {
2391     if (characterOffset.isNull())
2392         return false;
2393     
2394     return characterOffset.node->hasTagName(brTag);
2395 }
2396     
2397 static Node* parentEditingBoundary(Node* node)
2398 {
2399     if (!node)
2400         return nullptr;
2401     
2402     Node* documentElement = node->document().documentElement();
2403     if (!documentElement)
2404         return nullptr;
2405     
2406     Node* boundary = node;
2407     while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && node->hasEditableStyle() == boundary->parentNode()->hasEditableStyle())
2408         boundary = boundary->nonShadowBoundaryParentNode();
2409     
2410     return boundary;
2411 }
2412
2413 CharacterOffset AXObjectCache::nextBoundary(const CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
2414 {
2415     if (characterOffset.isNull())
2416         return { };
2417
2418     Node* boundary = parentEditingBoundary(characterOffset.node);
2419     if (!boundary)
2420         return { };
2421
2422     RefPtr<Range> searchRange = rangeForNodeContents(boundary);
2423     if (!searchRange)
2424         return { };
2425
2426     Vector<UChar, 1024> string;
2427     unsigned prefixLength = 0;
2428     
2429     if (requiresContextForWordBoundary(characterAfter(characterOffset))) {
2430         auto backwardsScanRange = boundary->document().createRange();
2431         if (!setRangeStartOrEndWithCharacterOffset(backwardsScanRange, characterOffset, false))
2432             return { };
2433         prefixLength = prefixLengthForRange(backwardsScanRange, string);
2434     }
2435     
2436     if (!setRangeStartOrEndWithCharacterOffset(*searchRange, characterOffset, true))
2437         return { };
2438     CharacterOffset end = startOrEndCharacterOffsetForRange(searchRange, false);
2439     
2440     TextIterator it(searchRange.get(), TextIteratorEmitsObjectReplacementCharacters);
2441     unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
2442     
2443     if (it.atEnd() && next == string.size())
2444         return end;
2445     
2446     // We should consider the node boundary that splits words.
2447     if (searchFunction == endWordBoundary && next - prefixLength == 1)
2448         return nextCharacterOffset(characterOffset, false);
2449     
2450     // The endSentenceBoundary function will include a line break at the end of the sentence.
2451     if (searchFunction == endSentenceBoundary && string[next - 1] == '\n')
2452         next--;
2453     
2454     if (next > prefixLength)
2455         return characterOffsetForNodeAndOffset(*characterOffset.node, characterOffset.offset + next - prefixLength);
2456     
2457     return characterOffset;
2458 }
2459
2460 CharacterOffset AXObjectCache::previousBoundary(const CharacterOffset& characterOffset, BoundarySearchFunction searchFunction)
2461 {
2462     if (characterOffset.isNull())
2463         return CharacterOffset();
2464     
2465     Node* boundary = parentEditingBoundary(characterOffset.node);
2466     if (!boundary)
2467         return CharacterOffset();
2468     
2469     RefPtr<Range> searchRange = rangeForNodeContents(boundary);
2470     Vector<UChar, 1024> string;
2471     unsigned suffixLength = 0;
2472     
2473     if (requiresContextForWordBoundary(characterBefore(characterOffset))) {
2474         auto forwardsScanRange = boundary->document().createRange();
2475         if (forwardsScanRange->setEndAfter(*boundary).hasException())
2476             return { };
2477         if (!setRangeStartOrEndWithCharacterOffset(forwardsScanRange, characterOffset, true))
2478             return { };
2479         suffixLength = suffixLengthForRange(forwardsScanRange, string);
2480     }
2481     
2482     if (!setRangeStartOrEndWithCharacterOffset(*searchRange, characterOffset, false))
2483         return { };
2484     CharacterOffset start = startOrEndCharacterOffsetForRange(searchRange, true);
2485     
2486     SimplifiedBackwardsTextIterator it(*searchRange);
2487     unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
2488     
2489     if (!next)
2490         return it.atEnd() ? start : characterOffset;
2491     
2492     Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
2493     
2494     // SimplifiedBackwardsTextIterator ignores replaced elements.
2495     if (AccessibilityObject::replacedNodeNeedsCharacter(characterOffset.node))
2496         return characterOffsetForNodeAndOffset(*characterOffset.node, 0);
2497     Node* nextSibling = node.nextSibling();
2498     if (&node != characterOffset.node && AccessibilityObject::replacedNodeNeedsCharacter(nextSibling))
2499         return startOrEndCharacterOffsetForRange(rangeForNodeContents(nextSibling), false);
2500     
2501     if ((node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
2502         // The next variable contains a usable index into a text node
2503         if (node.isTextNode())
2504             return traverseToOffsetInRange(rangeForNodeContents(&node), next, TraverseOptionValidateOffset);
2505         return characterOffsetForNodeAndOffset(node, next, TraverseOptionIncludeStart);
2506     }
2507     
2508     int characterCount = characterOffset.offset - (string.size() - suffixLength - next);
2509     // We don't want to go to the previous node if the node is at the start of a new line.
2510     if (characterCount < 0 && (characterOffsetNodeIsBR(characterOffset) || string[string.size() - suffixLength - 1] == '\n'))
2511         characterCount = 0;
2512     return characterOffsetForNodeAndOffset(*characterOffset.node, characterCount, TraverseOptionIncludeStart);
2513 }
2514
2515 CharacterOffset AXObjectCache::startCharacterOffsetOfParagraph(const CharacterOffset& characterOffset, EditingBoundaryCrossingRule boundaryCrossingRule)
2516 {
2517     if (characterOffset.isNull())
2518         return CharacterOffset();
2519     
2520     auto* startNode = characterOffset.node;
2521     
2522     if (isRenderedAsNonInlineTableImageOrHR(startNode))
2523         return startOrEndCharacterOffsetForRange(rangeForNodeContents(startNode), true);
2524     
2525     auto* startBlock = enclosingBlock(startNode);
2526     int offset = characterOffset.startIndex + characterOffset.offset;
2527     auto* highestRoot = highestEditableRoot(firstPositionInOrBeforeNode(startNode));
2528     Position::AnchorType type = Position::PositionIsOffsetInAnchor;
2529     
2530     auto* node = findStartOfParagraph(startNode, highestRoot, startBlock, offset, type, boundaryCrossingRule);
2531     
2532     if (type == Position::PositionIsOffsetInAnchor)
2533         return characterOffsetForNodeAndOffset(*node, offset, TraverseOptionIncludeStart);
2534     
2535     return startOrEndCharacterOffsetForRange(rangeForNodeContents(node), true);
2536 }
2537
2538 CharacterOffset AXObjectCache::endCharacterOffsetOfParagraph(const CharacterOffset& characterOffset, EditingBoundaryCrossingRule boundaryCrossingRule)
2539 {
2540     if (characterOffset.isNull())
2541         return CharacterOffset();
2542     
2543     Node* startNode = characterOffset.node;
2544     if (isRenderedAsNonInlineTableImageOrHR(startNode))
2545         return startOrEndCharacterOffsetForRange(rangeForNodeContents(startNode), false);
2546     
2547     Node* stayInsideBlock = enclosingBlock(startNode);
2548     int offset = characterOffset.startIndex + characterOffset.offset;
2549     Node* highestRoot = highestEditableRoot(firstPositionInOrBeforeNode(startNode));
2550     Position::AnchorType type = Position::PositionIsOffsetInAnchor;
2551     
2552     Node* node = findEndOfParagraph(startNode, highestRoot, stayInsideBlock, offset, type, boundaryCrossingRule);
2553     if (type == Position::PositionIsOffsetInAnchor) {
2554         if (node->isTextNode()) {
2555             CharacterOffset startOffset = startOrEndCharacterOffsetForRange(rangeForNodeContents(node), true);
2556             offset -= startOffset.startIndex;
2557         }
2558         return characterOffsetForNodeAndOffset(*node, offset, TraverseOptionIncludeStart);
2559     }
2560     
2561     return startOrEndCharacterOffsetForRange(rangeForNodeContents(node), false);
2562 }
2563
2564 RefPtr<Range> AXObjectCache::paragraphForCharacterOffset(const CharacterOffset& characterOffset)
2565 {
2566     CharacterOffset start = startCharacterOffsetOfParagraph(characterOffset);
2567     CharacterOffset end = endCharacterOffsetOfParagraph(start);
2568     
2569     return rangeForUnorderedCharacterOffsets(start, end);
2570 }
2571
2572 CharacterOffset AXObjectCache::nextParagraphEndCharacterOffset(const CharacterOffset& characterOffset)
2573 {
2574     // make sure we move off of a paragraph end
2575     CharacterOffset next = nextCharacterOffset(characterOffset);
2576     
2577     // We should skip the following BR node.
2578     if (characterOffsetNodeIsBR(next) && !characterOffsetNodeIsBR(characterOffset))
2579         next = nextCharacterOffset(next);
2580     
2581     return endCharacterOffsetOfParagraph(next);
2582 }
2583
2584 CharacterOffset AXObjectCache::previousParagraphStartCharacterOffset(const CharacterOffset& characterOffset)
2585 {
2586     // make sure we move off of a paragraph start
2587     CharacterOffset previous = previousCharacterOffset(characterOffset);
2588     
2589     // We should skip the preceding BR node.
2590     if (characterOffsetNodeIsBR(previous) && !characterOffsetNodeIsBR(characterOffset))
2591         previous = previousCharacterOffset(previous);
2592     
2593     return startCharacterOffsetOfParagraph(previous);
2594 }
2595
2596 CharacterOffset AXObjectCache::startCharacterOffsetOfSentence(const CharacterOffset& characterOffset)
2597 {
2598     return previousBoundary(characterOffset, startSentenceBoundary);
2599 }
2600
2601 CharacterOffset AXObjectCache::endCharacterOffsetOfSentence(const CharacterOffset& characterOffset)
2602 {
2603     return nextBoundary(characterOffset, endSentenceBoundary);
2604 }
2605
2606 RefPtr<Range> AXObjectCache::sentenceForCharacterOffset(const CharacterOffset& characterOffset)
2607 {
2608     CharacterOffset start = startCharacterOffsetOfSentence(characterOffset);
2609     CharacterOffset end = endCharacterOffsetOfSentence(start);
2610     return rangeForUnorderedCharacterOffsets(start, end);
2611 }
2612
2613 CharacterOffset AXObjectCache::nextSentenceEndCharacterOffset(const CharacterOffset& characterOffset)
2614 {
2615     // Make sure we move off of a sentence end.
2616     return endCharacterOffsetOfSentence(nextCharacterOffset(characterOffset));
2617 }
2618
2619 CharacterOffset AXObjectCache::previousSentenceStartCharacterOffset(const CharacterOffset& characterOffset)
2620 {
2621     // Make sure we move off of a sentence start.
2622     CharacterOffset previous = previousCharacterOffset(characterOffset);
2623     
2624     // We should skip the preceding BR node.
2625     if (characterOffsetNodeIsBR(previous) && !characterOffsetNodeIsBR(characterOffset))
2626         previous = previousCharacterOffset(previous);
2627     
2628     return startCharacterOffsetOfSentence(previous);
2629 }
2630
2631 LayoutRect AXObjectCache::localCaretRectForCharacterOffset(RenderObject*& renderer, const CharacterOffset& characterOffset)
2632 {
2633     if (characterOffset.isNull()) {
2634         renderer = nullptr;
2635         return IntRect();
2636     }
2637     
2638     Node* node = characterOffset.node;
2639     
2640     renderer = node->renderer();
2641     if (!renderer)
2642         return LayoutRect();
2643     
2644     InlineBox* inlineBox = nullptr;
2645     int caretOffset;
2646     // Use a collapsed range to get the position.
2647     RefPtr<Range> range = rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
2648     if (!range)
2649         return IntRect();
2650     
2651     Position startPosition = range->startPosition();
2652     startPosition.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset);
2653     
2654     if (inlineBox)
2655         renderer = &inlineBox->renderer();
2656     
2657     if (is<RenderLineBreak>(renderer) && downcast<RenderLineBreak>(renderer)->inlineBoxWrapper() != inlineBox)
2658         return IntRect();
2659     
2660     return renderer->localCaretRect(inlineBox, caretOffset);
2661 }
2662
2663 IntRect AXObjectCache::absoluteCaretBoundsForCharacterOffset(const CharacterOffset& characterOffset)
2664 {
2665     RenderBlock* caretPainter = nullptr;
2666     
2667     // First compute a rect local to the renderer at the selection start.
2668     RenderObject* renderer = nullptr;
2669     LayoutRect localRect = localCaretRectForCharacterOffset(renderer, characterOffset);
2670     
2671     localRect = localCaretRectInRendererForRect(localRect, characterOffset.node, renderer, caretPainter);
2672     return absoluteBoundsForLocalCaretRect(caretPainter, localRect);
2673 }
2674
2675 CharacterOffset AXObjectCache::characterOffsetForPoint(const IntPoint &point, AccessibilityObject* obj)
2676 {
2677     if (!obj)
2678         return CharacterOffset();
2679     
2680     VisiblePosition vp = obj->visiblePositionForPoint(point);
2681     RefPtr<Range> range = makeRange(vp, vp);
2682     return startOrEndCharacterOffsetForRange(range, true);
2683 }
2684
2685 CharacterOffset AXObjectCache::characterOffsetForPoint(const IntPoint &point)
2686 {
2687     RefPtr<Range> caretRange = m_document.caretRangeFromPoint(LayoutPoint(point));
2688     return startOrEndCharacterOffsetForRange(caretRange, true);
2689 }
2690
2691 CharacterOffset AXObjectCache::characterOffsetForBounds(const IntRect& rect, bool first)
2692 {
2693     if (rect.isEmpty())
2694         return CharacterOffset();
2695     
2696     IntPoint corner = first ? rect.minXMinYCorner() : rect.maxXMaxYCorner();
2697     CharacterOffset characterOffset = characterOffsetForPoint(corner);
2698     
2699     if (rect.contains(absoluteCaretBoundsForCharacterOffset(characterOffset).center()))
2700         return characterOffset;
2701     
2702     // If the initial position is located outside the bounds adjust it incrementally as needed.
2703     CharacterOffset nextCharOffset = nextCharacterOffset(characterOffset, false);
2704     CharacterOffset previousCharOffset = previousCharacterOffset(characterOffset, false);
2705     while (!nextCharOffset.isNull() || !previousCharOffset.isNull()) {
2706         if (rect.contains(absoluteCaretBoundsForCharacterOffset(nextCharOffset).center()))
2707             return nextCharOffset;
2708         if (rect.contains(absoluteCaretBoundsForCharacterOffset(previousCharOffset).center()))
2709             return previousCharOffset;
2710         
2711         nextCharOffset = nextCharacterOffset(nextCharOffset, false);
2712         previousCharOffset = previousCharacterOffset(previousCharOffset, false);
2713     }
2714     
2715     return CharacterOffset();
2716 }
2717
2718 // FIXME: Remove VisiblePosition code after implementing this using CharacterOffset.
2719 CharacterOffset AXObjectCache::endCharacterOffsetOfLine(const CharacterOffset& characterOffset)
2720 {
2721     if (characterOffset.isNull())
2722         return CharacterOffset();
2723     
2724     VisiblePosition vp = visiblePositionFromCharacterOffset(characterOffset);
2725     VisiblePosition endLine = endOfLine(vp);
2726     
2727     return characterOffsetFromVisiblePosition(endLine);
2728 }
2729
2730 CharacterOffset AXObjectCache::startCharacterOffsetOfLine(const CharacterOffset& characterOffset)
2731 {
2732     if (characterOffset.isNull())
2733         return CharacterOffset();
2734     
2735     VisiblePosition vp = visiblePositionFromCharacterOffset(characterOffset);
2736     VisiblePosition startLine = startOfLine(vp);
2737     
2738     return characterOffsetFromVisiblePosition(startLine);
2739 }
2740
2741 CharacterOffset AXObjectCache::characterOffsetForIndex(int index, const AccessibilityObject* obj)
2742 {
2743     if (!obj)
2744         return CharacterOffset();
2745     
2746     VisiblePosition vp = obj->visiblePositionForIndex(index);
2747     CharacterOffset validate = characterOffsetFromVisiblePosition(vp);
2748     // In text control, VisiblePosition always gives the before position of a
2749     // BR node, while CharacterOffset will do the opposite.
2750     if (obj->isTextControl() && characterOffsetNodeIsBR(validate))
2751         validate.offset = 1;
2752     
2753     RefPtr<Range> range = obj->elementRange();
2754     CharacterOffset start = startOrEndCharacterOffsetForRange(range, true, true);
2755     CharacterOffset end = startOrEndCharacterOffsetForRange(range, false, true);
2756     CharacterOffset result = start;
2757     for (int i = 0; i < index; i++) {
2758         if (result.isEqual(validate)) {
2759             // Do not include the new line character, always move the offset to the start of next node.
2760             if ((validate.node->isTextNode() || characterOffsetNodeIsBR(validate))) {
2761                 CharacterOffset next = nextCharacterOffset(validate, false);
2762                 if (!next.isNull() && !next.offset && rootAXEditableElement(next.node) == rootAXEditableElement(validate.node))
2763                     result = next;
2764             }
2765             break;
2766         }
2767         
2768         result = nextCharacterOffset(result, false);
2769         if (result.isEqual(end))
2770             break;
2771     }
2772     return result;
2773 }
2774
2775 int AXObjectCache::indexForCharacterOffset(const CharacterOffset& characterOffset, AccessibilityObject* obj)
2776 {
2777     // Create a collapsed range so that we can get the VisiblePosition from it.
2778     RefPtr<Range> range = rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
2779     if (!range)
2780         return 0;
2781     VisiblePosition vp = range->startPosition();
2782     return obj->indexForVisiblePosition(vp);
2783 }
2784
2785 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
2786 {
2787     const Element* result = node->rootEditableElement();
2788     const Element* element = is<Element>(*node) ? downcast<Element>(node) : node->parentElement();
2789
2790     for (; element; element = element->parentElement()) {
2791         if (nodeIsTextControl(element))
2792             result = element;
2793     }
2794
2795     return result;
2796 }
2797
2798 static void conditionallyAddNodeToFilterList(Node* node, const Document& document, HashSet<Node*>& nodesToRemove)
2799 {
2800     if (node && (!node->isConnected() || &node->document() == &document))
2801         nodesToRemove.add(node);
2802 }
2803     
2804 template<typename T>
2805 static void filterVectorPairForRemoval(const Vector<std::pair<T, T>>& list, const Document& document, HashSet<Node*>& nodesToRemove)
2806 {
2807     for (auto& entry : list) {
2808         conditionallyAddNodeToFilterList(entry.first, document, nodesToRemove);
2809         conditionallyAddNodeToFilterList(entry.second, document, nodesToRemove);
2810     }
2811 }
2812     
2813 template<typename T, typename U>
2814 static void filterMapForRemoval(const HashMap<T, U>& list, const Document& document, HashSet<Node*>& nodesToRemove)
2815 {
2816     for (auto& entry : list)
2817         conditionallyAddNodeToFilterList(entry.key, document, nodesToRemove);
2818 }
2819
2820 template<typename T>
2821 static void filterListForRemoval(const ListHashSet<T>& list, const Document& document, HashSet<Node*>& nodesToRemove)
2822 {
2823     for (auto* node : list)
2824         conditionallyAddNodeToFilterList(node, document, nodesToRemove);
2825 }
2826
2827 void AXObjectCache::prepareForDocumentDestruction(const Document& document)
2828 {
2829     HashSet<Node*> nodesToRemove;
2830     filterListForRemoval(m_textMarkerNodes, document, nodesToRemove);
2831     filterListForRemoval(m_modalNodesSet, document, nodesToRemove);
2832     filterListForRemoval(m_deferredRecomputeIsIgnoredList, document, nodesToRemove);
2833     filterListForRemoval(m_deferredTextChangedList, document, nodesToRemove);
2834     filterListForRemoval(m_deferredSelectedChildredChangedList, document, nodesToRemove);
2835     filterMapForRemoval(m_deferredTextFormControlValue, document, nodesToRemove);
2836     filterMapForRemoval(m_deferredAttributeChange, document, nodesToRemove);
2837     filterVectorPairForRemoval(m_deferredFocusedNodeChange, document, nodesToRemove);
2838
2839     for (auto* node : nodesToRemove)
2840         remove(*node);
2841 }
2842     
2843 bool AXObjectCache::nodeIsTextControl(const Node* node)
2844 {
2845     if (!node)
2846         return false;
2847
2848     const AccessibilityObject* axObject = getOrCreate(const_cast<Node*>(node));
2849     return axObject && axObject->isTextControl();
2850 }
2851     
2852 void AXObjectCache::performDeferredCacheUpdate()
2853 {
2854     if (m_performingDeferredCacheUpdate)
2855         return;
2856
2857     SetForScope<bool> performingDeferredCacheUpdate(m_performingDeferredCacheUpdate, true);
2858     for (auto* node : m_deferredTextChangedList)
2859         textChanged(node);
2860     m_deferredTextChangedList.clear();
2861
2862     for (auto* element : m_deferredRecomputeIsIgnoredList) {
2863         if (auto* renderer = element->renderer())
2864             recomputeIsIgnored(renderer);
2865     }
2866     m_deferredRecomputeIsIgnoredList.clear();
2867     
2868     for (auto* selectElement : m_deferredSelectedChildredChangedList)
2869         selectedChildrenChanged(selectElement);
2870     m_deferredSelectedChildredChangedList.clear();
2871
2872     for (auto& deferredFormControlContext : m_deferredTextFormControlValue) {
2873         auto& textFormControlElement = downcast<HTMLTextFormControlElement>(*deferredFormControlContext.key);
2874         postTextReplacementNotificationForTextControl(textFormControlElement, deferredFormControlContext.value, textFormControlElement.innerTextValue());
2875     }
2876     m_deferredTextFormControlValue.clear();
2877
2878     for (auto& deferredAttributeChangeContext : m_deferredAttributeChange)
2879         handleAttributeChange(deferredAttributeChangeContext.value, deferredAttributeChangeContext.key);
2880     m_deferredAttributeChange.clear();
2881     
2882     for (auto& deferredFocusedChangeContext : m_deferredFocusedNodeChange)
2883         handleFocusedUIElementChanged(deferredFocusedChangeContext.first, deferredFocusedChangeContext.second);
2884     m_deferredFocusedNodeChange.clear();
2885 }
2886     
2887 void AXObjectCache::deferRecomputeIsIgnoredIfNeeded(Element* element)
2888 {
2889     if (!nodeAndRendererAreValid(element))
2890         return;
2891     
2892     if (rendererNeedsDeferredUpdate(*element->renderer())) {
2893         m_deferredRecomputeIsIgnoredList.add(element);
2894         return;
2895     }
2896     recomputeIsIgnored(element->renderer());
2897 }
2898
2899 void AXObjectCache::deferRecomputeIsIgnored(Element* element)
2900 {
2901     if (!nodeAndRendererAreValid(element))
2902         return;
2903
2904     m_deferredRecomputeIsIgnoredList.add(element);
2905 }
2906
2907 void AXObjectCache::deferTextChangedIfNeeded(Node* node)
2908 {
2909     if (!nodeAndRendererAreValid(node))
2910         return;
2911
2912     if (rendererNeedsDeferredUpdate(*node->renderer())) {
2913         m_deferredTextChangedList.add(node);
2914         return;
2915     }
2916     textChanged(node);
2917 }
2918
2919 void AXObjectCache::deferSelectedChildrenChangedIfNeeded(Element& selectElement)
2920 {
2921     if (!nodeAndRendererAreValid(&selectElement))
2922         return;
2923
2924     if (rendererNeedsDeferredUpdate(*selectElement.renderer())) {
2925         m_deferredSelectedChildredChangedList.add(&selectElement);
2926         return;
2927     }
2928     selectedChildrenChanged(&selectElement);
2929 }
2930
2931 void AXObjectCache::deferTextReplacementNotificationForTextControl(HTMLTextFormControlElement& formControlElement, const String& previousValue)
2932 {
2933     auto* renderer = formControlElement.renderer();
2934     if (!renderer)
2935         return;
2936     m_deferredTextFormControlValue.add(&formControlElement, previousValue);
2937 }
2938
2939 bool isNodeAriaVisible(Node* node)
2940 {
2941     if (!node)
2942         return false;
2943
2944     // ARIA Node visibility is controlled by aria-hidden
2945     //  1) if aria-hidden=true, the whole subtree is hidden
2946     //  2) if aria-hidden=false, and the object is rendered, there's no effect
2947     //  3) if aria-hidden=false, and the object is NOT rendered, then it must have
2948     //     aria-hidden=false on each parent until it gets to a rendered object
2949     //  3b) a text node inherits a parents aria-hidden value
2950     bool requiresAriaHiddenFalse = !node->renderer();
2951     bool ariaHiddenFalsePresent = false;
2952     for (Node* testNode = node; testNode; testNode = testNode->parentNode()) {
2953         if (is<Element>(*testNode)) {
2954             const AtomicString& ariaHiddenValue = downcast<Element>(*testNode).attributeWithoutSynchronization(aria_hiddenAttr);
2955             if (equalLettersIgnoringASCIICase(ariaHiddenValue, "true"))
2956                 return false;
2957             
2958             bool ariaHiddenFalse = equalLettersIgnoringASCIICase(ariaHiddenValue, "false");
2959             if (!testNode->renderer() && !ariaHiddenFalse)
2960                 return false;
2961             if (!ariaHiddenFalsePresent && ariaHiddenFalse)
2962                 ariaHiddenFalsePresent = true;
2963             // We should break early when it gets to a rendered object.
2964             if (testNode->renderer())
2965                 break;
2966         }
2967     }
2968     
2969     return !requiresAriaHiddenFalse || ariaHiddenFalsePresent;
2970 }
2971
2972 AccessibilityObject* AXObjectCache::rootWebArea()
2973 {
2974     AccessibilityObject* rootObject = this->rootObject();
2975     if (!rootObject || !rootObject->isAccessibilityScrollView())
2976         return nullptr;
2977     return downcast<AccessibilityScrollView>(*rootObject).webAreaObject();
2978 }
2979
2980 AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache)
2981     : m_cache(cache)
2982 {
2983     if (m_cache)
2984         m_cache->startCachingComputedObjectAttributesUntilTreeMutates();
2985 }
2986     
2987 AXAttributeCacheEnabler::~AXAttributeCacheEnabler()
2988 {
2989     if (m_cache)
2990         m_cache->stopCachingComputedObjectAttributes();
2991 }
2992
2993 #if !PLATFORM(COCOA)
2994 AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType type)
2995 {
2996     switch (type) {
2997     case AXTextEditTypeCut:
2998     case AXTextEditTypeDelete:
2999         return AXTextDeleted;
3000     case AXTextEditTypeInsert:
3001     case AXTextEditTypeDictation:
3002     case AXTextEditTypeTyping:
3003     case AXTextEditTypePaste:
3004         return AXTextInserted;
3005     case AXTextEditTypeAttributesChange:
3006         return AXTextAttributesChanged;
3007     case AXTextEditTypeUnknown:
3008         break;
3009     }
3010     ASSERT_NOT_REACHED();
3011     return AXTextInserted;
3012 }
3013 #endif
3014     
3015 } // namespace WebCore
3016
3017 #endif // HAVE(ACCESSIBILITY)