Remove isInCanvasSubtree bit
[WebKit-https.git] / Source / WebCore / accessibility / AXObjectCache.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30
31 #if HAVE(ACCESSIBILITY)
32
33 #include "AXObjectCache.h"
34
35 #include "AccessibilityARIAGrid.h"
36 #include "AccessibilityARIAGridCell.h"
37 #include "AccessibilityARIAGridRow.h"
38 #include "AccessibilityImageMapLink.h"
39 #include "AccessibilityList.h"
40 #include "AccessibilityListBox.h"
41 #include "AccessibilityListBoxOption.h"
42 #include "AccessibilityMediaControls.h"
43 #include "AccessibilityMenuList.h"
44 #include "AccessibilityMenuListOption.h"
45 #include "AccessibilityMenuListPopup.h"
46 #include "AccessibilityProgressIndicator.h"
47 #include "AccessibilityRenderObject.h"
48 #include "AccessibilitySVGRoot.h"
49 #include "AccessibilityScrollView.h"
50 #include "AccessibilityScrollbar.h"
51 #include "AccessibilitySearchFieldButtons.h"
52 #include "AccessibilitySlider.h"
53 #include "AccessibilitySpinButton.h"
54 #include "AccessibilityTable.h"
55 #include "AccessibilityTableCell.h"
56 #include "AccessibilityTableColumn.h"
57 #include "AccessibilityTableHeaderContainer.h"
58 #include "AccessibilityTableRow.h"
59 #include "Document.h"
60 #include "Editor.h"
61 #include "ElementIterator.h"
62 #include "FocusController.h"
63 #include "Frame.h"
64 #include "HTMLAreaElement.h"
65 #include "HTMLCanvasElement.h"
66 #include "HTMLImageElement.h"
67 #include "HTMLInputElement.h"
68 #include "HTMLLabelElement.h"
69 #include "HTMLMeterElement.h"
70 #include "HTMLNames.h"
71 #include "Page.h"
72 #include "RenderListBox.h"
73 #include "RenderMenuList.h"
74 #include "RenderMeter.h"
75 #include "RenderProgress.h"
76 #include "RenderSlider.h"
77 #include "RenderTable.h"
78 #include "RenderTableCell.h"
79 #include "RenderTableRow.h"
80 #include "RenderView.h"
81 #include "ScrollView.h"
82 #include <wtf/PassRefPtr.h>
83
84 #if ENABLE(VIDEO)
85 #include "MediaControlElements.h"
86 #endif
87
88 namespace WebCore {
89
90 using namespace HTMLNames;
91
92 AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
93 {
94     HashMap<AXID, CachedAXObjectAttributes>::const_iterator it = m_idMapping.find(id);
95     return it != m_idMapping.end() ? it->value.ignored : DefaultBehavior;
96 }
97
98 void AXComputedObjectAttributeCache::setIgnored(AXID id, AccessibilityObjectInclusion inclusion)
99 {
100     HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
101     if (it != m_idMapping.end())
102         it->value.ignored = inclusion;
103     else {
104         CachedAXObjectAttributes attributes;
105         attributes.ignored = inclusion;
106         m_idMapping.set(id, attributes);
107     }
108 }
109     
110 bool AXObjectCache::gAccessibilityEnabled = false;
111 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
112
113 void AXObjectCache::enableAccessibility()
114 {
115     gAccessibilityEnabled = true;
116 }
117
118 void AXObjectCache::disableAccessibility()
119 {
120     gAccessibilityEnabled = false;
121 }
122
123 void AXObjectCache::setEnhancedUserInterfaceAccessibility(bool flag)
124 {
125     gAccessibilityEnhancedUserInterfaceEnabled = flag;
126 }
127
128 AXObjectCache::AXObjectCache(Document& document)
129     : m_document(document)
130     , m_notificationPostTimer(this, &AXObjectCache::notificationPostTimerFired)
131 {
132 }
133
134 AXObjectCache::~AXObjectCache()
135 {
136     m_notificationPostTimer.stop();
137
138     for (const auto& object : m_objects.values()) {
139         detachWrapper(object.get(), CacheDestroyed);
140         object->detach(CacheDestroyed);
141         removeAXID(object.get());
142     }
143 }
144
145 AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
146 {
147     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
148     // in the list of children for its corresponding image.
149     if (!areaElement)
150         return nullptr;
151     
152     HTMLImageElement* imageElement = areaElement->imageElement();
153     if (!imageElement)
154         return nullptr;
155     
156     AccessibilityObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement);
157     if (!axRenderImage)
158         return nullptr;
159     
160     for (const auto& child : axRenderImage->children()) {
161         if (!child->isImageMapLink())
162             continue;
163         
164         if (toAccessibilityImageMapLink(child.get())->areaElement() == areaElement)
165             return child.get();
166     }    
167     
168     return nullptr;
169 }
170     
171 AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
172 {
173     if (!gAccessibilityEnabled)
174         return nullptr;
175
176     // get the focused node in the page
177     Document* focusedDocument = page->focusController().focusedOrMainFrame().document();
178     Element* focusedElement = focusedDocument->focusedElement();
179     if (focusedElement && isHTMLAreaElement(focusedElement))
180         return focusedImageMapUIElement(toHTMLAreaElement(focusedElement));
181
182     AccessibilityObject* obj = focusedDocument->axObjectCache()->getOrCreate(focusedElement ? static_cast<Node*>(focusedElement) : focusedDocument);
183     if (!obj)
184         return nullptr;
185
186     if (obj->shouldFocusActiveDescendant()) {
187         if (AccessibilityObject* descendant = obj->activeDescendant())
188             obj = descendant;
189     }
190
191     // the HTML element, for example, is focusable but has an AX object that is ignored
192     if (obj->accessibilityIsIgnored())
193         obj = obj->parentObjectUnignored();
194
195     return obj;
196 }
197
198 AccessibilityObject* AXObjectCache::get(Widget* widget)
199 {
200     if (!widget)
201         return nullptr;
202         
203     AXID axID = m_widgetObjectMapping.get(widget);
204     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
205     if (!axID)
206         return nullptr;
207     
208     return m_objects.get(axID);    
209 }
210     
211 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
212 {
213     if (!renderer)
214         return nullptr;
215     
216     AXID axID = m_renderObjectMapping.get(renderer);
217     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
218     if (!axID)
219         return nullptr;
220
221     return m_objects.get(axID);    
222 }
223
224 AccessibilityObject* AXObjectCache::get(Node* node)
225 {
226     if (!node)
227         return nullptr;
228
229     AXID renderID = node->renderer() ? m_renderObjectMapping.get(node->renderer()) : 0;
230     ASSERT(!HashTraits<AXID>::isDeletedValue(renderID));
231
232     AXID nodeID = m_nodeObjectMapping.get(node);
233     ASSERT(!HashTraits<AXID>::isDeletedValue(nodeID));
234
235     if (node->renderer() && nodeID && !renderID) {
236         // This can happen if an AccessibilityNodeObject is created for a node that's not
237         // rendered, but later something changes and it gets a renderer (like if it's
238         // reparented).
239         remove(nodeID);
240         return nullptr;
241     }
242
243     if (renderID)
244         return m_objects.get(renderID);
245
246     if (!nodeID)
247         return nullptr;
248
249     return m_objects.get(nodeID);
250 }
251
252 // FIXME: This probably belongs on Node.
253 // FIXME: This should take a const char*, but one caller passes nullAtom.
254 bool nodeHasRole(Node* node, const String& role)
255 {
256     if (!node || !node->isElementNode())
257         return false;
258
259     auto& roleValue = toElement(node)->fastGetAttribute(roleAttr);
260     if (role.isNull())
261         return roleValue.isEmpty();
262     if (roleValue.isEmpty())
263         return false;
264
265     return SpaceSplitString(roleValue, true).contains(role);
266 }
267
268 static PassRefPtr<AccessibilityObject> createFromRenderer(RenderObject* renderer)
269 {
270     // FIXME: How could renderer->node() ever not be an Element?
271     Node* node = renderer->node();
272
273     // If the node is aria role="list" or the aria role is empty and its a
274     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
275     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
276                       || (nodeHasRole(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
277         return AccessibilityList::create(renderer);
278
279     // aria tables
280     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid"))
281         return AccessibilityARIAGrid::create(renderer);
282     if (nodeHasRole(node, "row"))
283         return AccessibilityARIAGridRow::create(renderer);
284     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
285         return AccessibilityARIAGridCell::create(renderer);
286
287 #if ENABLE(VIDEO)
288     // media controls
289     if (node && node->isMediaControlElement())
290         return AccessibilityMediaControl::create(renderer);
291 #endif
292
293     if (renderer->isSVGRoot())
294         return AccessibilitySVGRoot::create(renderer);
295     
296     // Search field buttons
297     if (node && node->isElementNode() && toElement(node)->isSearchFieldCancelButtonElement())
298         return AccessibilitySearchFieldCancelButton::create(renderer);
299     
300     if (renderer->isBoxModelObject()) {
301         RenderBoxModelObject* cssBox = toRenderBoxModelObject(renderer);
302         if (cssBox->isListBox())
303             return AccessibilityListBox::create(toRenderListBox(cssBox));
304         if (cssBox->isMenuList())
305             return AccessibilityMenuList::create(toRenderMenuList(cssBox));
306
307         // standard tables
308         if (cssBox->isTable())
309             return AccessibilityTable::create(toRenderTable(cssBox));
310         if (cssBox->isTableRow())
311             return AccessibilityTableRow::create(toRenderTableRow(cssBox));
312         if (cssBox->isTableCell())
313             return AccessibilityTableCell::create(toRenderTableCell(cssBox));
314
315         // progress bar
316         if (cssBox->isProgress())
317             return AccessibilityProgressIndicator::create(toRenderProgress(cssBox));
318
319 #if ENABLE(METER_ELEMENT)
320         if (cssBox->isMeter())
321             return AccessibilityProgressIndicator::create(toRenderMeter(cssBox));
322 #endif
323
324         // input type=range
325         if (cssBox->isSlider())
326             return AccessibilitySlider::create(toRenderSlider(cssBox));
327     }
328
329     return AccessibilityRenderObject::create(renderer);
330 }
331
332 static PassRefPtr<AccessibilityObject> createFromNode(Node* node)
333 {
334     return AccessibilityNodeObject::create(node);
335 }
336
337 AccessibilityObject* AXObjectCache::getOrCreate(Widget* widget)
338 {
339     if (!widget)
340         return nullptr;
341
342     if (AccessibilityObject* obj = get(widget))
343         return obj;
344     
345     RefPtr<AccessibilityObject> newObj = nullptr;
346     if (widget->isFrameView())
347         newObj = AccessibilityScrollView::create(toScrollView(widget));
348     else if (widget->isScrollbar())
349         newObj = AccessibilityScrollbar::create(toScrollbar(widget));
350
351     // Will crash later if we have two objects for the same widget.
352     ASSERT(!get(widget));
353
354     // Catch the case if an (unsupported) widget type is used. Only FrameView and ScrollBar are supported now.
355     ASSERT(newObj);
356     if (!newObj)
357         return nullptr;
358
359     getAXID(newObj.get());
360     
361     m_widgetObjectMapping.set(widget, newObj->axObjectID());
362     m_objects.set(newObj->axObjectID(), newObj);    
363     newObj->init();
364     attachWrapper(newObj.get());
365     return newObj.get();
366 }
367
368 AccessibilityObject* AXObjectCache::getOrCreate(Node* node)
369 {
370     if (!node)
371         return nullptr;
372
373     if (AccessibilityObject* obj = get(node))
374         return obj;
375
376     if (node->renderer())
377         return getOrCreate(node->renderer());
378
379     if (!node->parentElement())
380         return nullptr;
381     
382     // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree.
383     // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes.
384     bool inCanvasSubtree = lineageOfType<HTMLCanvasElement>(*node->parentElement()).first();
385     bool isHidden = isNodeAriaVisible(node);
386
387     bool insideMeterElement = false;
388 #if ENABLE(METER_ELEMENT)
389     insideMeterElement = isHTMLMeterElement(node->parentElement());
390 #endif
391     
392     if (!inCanvasSubtree && !isHidden && !insideMeterElement)
393         return nullptr;
394
395     RefPtr<AccessibilityObject> newObj = createFromNode(node);
396
397     // Will crash later if we have two objects for the same node.
398     ASSERT(!get(node));
399
400     getAXID(newObj.get());
401
402     m_nodeObjectMapping.set(node, newObj->axObjectID());
403     m_objects.set(newObj->axObjectID(), newObj);
404     newObj->init();
405     attachWrapper(newObj.get());
406     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
407     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
408     // it will disappear when this function is finished, leading to a use-after-free.
409     if (newObj->isDetached())
410         return nullptr;
411     
412     return newObj.get();
413 }
414
415 AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
416 {
417     if (!renderer)
418         return nullptr;
419
420     if (AccessibilityObject* obj = get(renderer))
421         return obj;
422
423     RefPtr<AccessibilityObject> newObj = createFromRenderer(renderer);
424
425     // Will crash later if we have two objects for the same renderer.
426     ASSERT(!get(renderer));
427
428     getAXID(newObj.get());
429
430     m_renderObjectMapping.set(renderer, newObj->axObjectID());
431     m_objects.set(newObj->axObjectID(), newObj);
432     newObj->init();
433     attachWrapper(newObj.get());
434     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
435     // Sometimes asking accessibilityIsIgnored() will cause the newObject to be deallocated, and then
436     // it will disappear when this function is finished, leading to a use-after-free.
437     if (newObj->isDetached())
438         return nullptr;
439     
440     return newObj.get();
441 }
442     
443 AccessibilityObject* AXObjectCache::rootObject()
444 {
445     if (!gAccessibilityEnabled)
446         return nullptr;
447
448     return getOrCreate(m_document.view());
449 }
450
451 AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame* frame)
452 {
453     if (!gAccessibilityEnabled)
454         return nullptr;
455
456     if (!frame)
457         return nullptr;
458     return getOrCreate(frame->view());
459 }    
460     
461 AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
462 {
463     RefPtr<AccessibilityObject> obj = nullptr;
464     
465     // will be filled in...
466     switch (role) {
467     case ListBoxOptionRole:
468         obj = AccessibilityListBoxOption::create();
469         break;
470     case ImageMapLinkRole:
471         obj = AccessibilityImageMapLink::create();
472         break;
473     case ColumnRole:
474         obj = AccessibilityTableColumn::create();
475         break;            
476     case TableHeaderContainerRole:
477         obj = AccessibilityTableHeaderContainer::create();
478         break;   
479     case SliderThumbRole:
480         obj = AccessibilitySliderThumb::create();
481         break;
482     case MenuListPopupRole:
483         obj = AccessibilityMenuListPopup::create();
484         break;
485     case MenuListOptionRole:
486         obj = AccessibilityMenuListOption::create();
487         break;
488     case SpinButtonRole:
489         obj = AccessibilitySpinButton::create();
490         break;
491     case SpinButtonPartRole:
492         obj = AccessibilitySpinButtonPart::create();
493         break;
494     default:
495         obj = nullptr;
496     }
497     
498     if (obj)
499         getAXID(obj.get());
500     else
501         return nullptr;
502
503     m_objects.set(obj->axObjectID(), obj);    
504     obj->init();
505     attachWrapper(obj.get());
506     return obj.get();
507 }
508
509 void AXObjectCache::remove(AXID axID)
510 {
511     if (!axID)
512         return;
513     
514     // first fetch object to operate some cleanup functions on it 
515     AccessibilityObject* obj = m_objects.get(axID);
516     if (!obj)
517         return;
518     
519     detachWrapper(obj, ElementDestroyed);
520     obj->detach(ElementDestroyed, this);
521     removeAXID(obj);
522     
523     // finally remove the object
524     if (!m_objects.take(axID))
525         return;
526     
527     ASSERT(m_objects.size() >= m_idsInUse.size());    
528 }
529     
530 void AXObjectCache::remove(RenderObject* renderer)
531 {
532     if (!renderer)
533         return;
534     
535     AXID axID = m_renderObjectMapping.get(renderer);
536     remove(axID);
537     m_renderObjectMapping.remove(renderer);
538 }
539
540 void AXObjectCache::remove(Node* node)
541 {
542     if (!node)
543         return;
544
545     removeNodeForUse(node);
546
547     // This is all safe even if we didn't have a mapping.
548     AXID axID = m_nodeObjectMapping.get(node);
549     remove(axID);
550     m_nodeObjectMapping.remove(node);
551
552     if (node->renderer()) {
553         remove(node->renderer());
554         return;
555     }
556 }
557
558 void AXObjectCache::remove(Widget* view)
559 {
560     if (!view)
561         return;
562         
563     AXID axID = m_widgetObjectMapping.get(view);
564     remove(axID);
565     m_widgetObjectMapping.remove(view);
566 }
567     
568     
569 #if !PLATFORM(WIN) || OS(WINCE)
570 AXID AXObjectCache::platformGenerateAXID() const
571 {
572     static AXID lastUsedID = 0;
573
574     // Generate a new ID.
575     AXID objID = lastUsedID;
576     do {
577         ++objID;
578     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
579
580     lastUsedID = objID;
581
582     return objID;
583 }
584 #endif
585
586 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
587 {
588     // check for already-assigned ID
589     AXID objID = obj->axObjectID();
590     if (objID) {
591         ASSERT(m_idsInUse.contains(objID));
592         return objID;
593     }
594
595     objID = platformGenerateAXID();
596
597     m_idsInUse.add(objID);
598     obj->setAXObjectID(objID);
599     
600     return objID;
601 }
602
603 void AXObjectCache::removeAXID(AccessibilityObject* object)
604 {
605     if (!object)
606         return;
607     
608     AXID objID = object->axObjectID();
609     if (!objID)
610         return;
611     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
612     ASSERT(m_idsInUse.contains(objID));
613     object->setAXObjectID(0);
614     m_idsInUse.remove(objID);
615 }
616
617 void AXObjectCache::textChanged(Node* node)
618 {
619     textChanged(getOrCreate(node));
620 }
621
622 void AXObjectCache::textChanged(RenderObject* renderer)
623 {
624     textChanged(getOrCreate(renderer));
625 }
626
627 void AXObjectCache::textChanged(AccessibilityObject* obj)
628 {
629     if (!obj)
630         return;
631
632     bool parentAlreadyExists = obj->parentObjectIfExists();
633     obj->textChanged();
634     postNotification(obj, obj->document(), AXObjectCache::AXTextChanged);
635     if (parentAlreadyExists)
636         obj->notifyIfIgnoredValueChanged();
637 }
638
639 void AXObjectCache::updateCacheAfterNodeIsAttached(Node* node)
640 {
641     // Calling get() will update the AX object if we had an AccessibilityNodeObject but now we need
642     // an AccessibilityRenderObject, because it was reparented to a location outside of a canvas.
643     get(node);
644 }
645
646 void AXObjectCache::handleMenuOpened(Node* node)
647 {
648     if (!node || !node->renderer() || !nodeHasRole(node, "menu"))
649         return;
650     
651     postNotification(getOrCreate(node), &document(), AXMenuOpened);
652 }
653     
654 void AXObjectCache::handleLiveRegionCreated(Node* node)
655 {
656     if (!node || !node->renderer() || !node->isElementNode())
657         return;
658     
659     Element* element = toElement(node);
660     String liveRegionStatus = element->fastGetAttribute(aria_liveAttr);
661     if (liveRegionStatus.isEmpty()) {
662         const AtomicString& ariaRole = element->fastGetAttribute(roleAttr);
663         if (!ariaRole.isEmpty())
664             liveRegionStatus = AccessibilityObject::defaultLiveRegionStatusForRole(AccessibilityObject::ariaRoleToWebCoreRole(ariaRole));
665     }
666     
667     if (AccessibilityObject::liveRegionStatusIsEnabled(liveRegionStatus))
668         postNotification(getOrCreate(node), &document(), AXLiveRegionCreated);
669 }
670     
671 void AXObjectCache::childrenChanged(Node* node, Node* newChild)
672 {
673     if (newChild) {
674         handleMenuOpened(newChild);
675         handleLiveRegionCreated(newChild);
676     }
677     
678     childrenChanged(get(node));
679 }
680
681 void AXObjectCache::childrenChanged(RenderObject* renderer, RenderObject* newChild)
682 {
683     if (!renderer)
684         return;
685     
686     if (newChild) {
687         handleMenuOpened(newChild->node());
688         handleLiveRegionCreated(newChild->node());
689     }
690     
691     childrenChanged(get(renderer));
692 }
693
694 void AXObjectCache::childrenChanged(AccessibilityObject* obj)
695 {
696     if (!obj)
697         return;
698
699     obj->childrenChanged();
700 }
701     
702 void AXObjectCache::notificationPostTimerFired(Timer<AXObjectCache>&)
703 {
704     Ref<Document> protectorForCacheOwner(m_document);
705     m_notificationPostTimer.stop();
706     
707     // In DRT, posting notifications has a tendency to immediately queue up other notifications, which can lead to unexpected behavior
708     // when the notification list is cleared at the end. Instead copy this list at the start.
709     auto notifications = WTF::move(m_notificationsToPost);
710     
711     for (const auto& note : notifications) {
712         AccessibilityObject* obj = note.first.get();
713         if (!obj->axObjectID())
714             continue;
715
716         if (!obj->axObjectCache())
717             continue;
718         
719 #ifndef NDEBUG
720         // Make sure none of the render views are in the process of being layed out.
721         // Notifications should only be sent after the renderer has finished
722         if (obj->isAccessibilityRenderObject()) {
723             AccessibilityRenderObject* renderObj = toAccessibilityRenderObject(obj);
724             RenderObject* renderer = renderObj->renderer();
725             if (renderer)
726                 ASSERT(!renderer->view().layoutState());
727         }
728 #endif
729
730         AXNotification notification = note.second;
731         
732         // Ensure that this menu really is a menu. We do this check here so that we don't have to create
733         // the axChildren when the menu is marked as opening.
734         if (notification == AXMenuOpened) {
735             obj->updateChildrenIfNecessary();
736             if (obj->roleValue() != MenuRole)
737                 continue;
738         }
739         
740         postPlatformNotification(obj, notification);
741
742         if (notification == AXChildrenChanged && obj->parentObjectIfExists() && obj->lastKnownIsIgnoredValue() != obj->accessibilityIsIgnored())
743             childrenChanged(obj->parentObject());
744     }
745 }
746     
747 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, PostTarget postTarget, PostType postType)
748 {
749     if (!renderer)
750         return;
751     
752     stopCachingComputedObjectAttributes();
753
754     // Get an accessibility object that already exists. One should not be created here
755     // because a render update may be in progress and creating an AX object can re-trigger a layout
756     RefPtr<AccessibilityObject> object = get(renderer);
757     while (!object && renderer) {
758         renderer = renderer->parent();
759         object = get(renderer); 
760     }
761     
762     if (!renderer)
763         return;
764     
765     postNotification(object.get(), &renderer->document(), notification, postTarget, postType);
766 }
767
768 void AXObjectCache::postNotification(Node* node, AXNotification notification, PostTarget postTarget, PostType postType)
769 {
770     if (!node)
771         return;
772     
773     stopCachingComputedObjectAttributes();
774
775     // Get an accessibility object that already exists. One should not be created here
776     // because a render update may be in progress and creating an AX object can re-trigger a layout
777     RefPtr<AccessibilityObject> object = get(node);
778     while (!object && node) {
779         node = node->parentNode();
780         object = get(node);
781     }
782     
783     if (!node)
784         return;
785     
786     postNotification(object.get(), &node->document(), notification, postTarget, postType);
787 }
788
789 void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, PostTarget postTarget, PostType postType)
790 {
791     stopCachingComputedObjectAttributes();
792
793     if (object && postTarget == TargetObservableParent)
794         object = object->observableObject();
795
796     if (!object && document)
797         object = get(document->renderView());
798
799     if (!object)
800         return;
801
802     if (postType == PostAsynchronously) {
803         m_notificationsToPost.append(std::make_pair(object, notification));
804         if (!m_notificationPostTimer.isActive())
805             m_notificationPostTimer.startOneShot(0);
806     } else
807         postPlatformNotification(object, notification);
808 }
809
810 void AXObjectCache::checkedStateChanged(Node* node)
811 {
812     postNotification(node, AXObjectCache::AXCheckedStateChanged);
813 }
814
815 void AXObjectCache::handleMenuItemSelected(Node* node)
816 {
817     if (!node)
818         return;
819     
820     if (!nodeHasRole(node, "menuitem") && !nodeHasRole(node, "menuitemradio") && !nodeHasRole(node, "menuitemcheckbox"))
821         return;
822     
823     if (!toElement(node)->focused() && !equalIgnoringCase(toElement(node)->fastGetAttribute(aria_selectedAttr), "true"))
824         return;
825     
826     postNotification(getOrCreate(node), &document(), AXMenuListItemSelected);
827 }
828     
829 void AXObjectCache::handleFocusedUIElementChanged(Node* oldNode, Node* newNode)
830 {
831     handleMenuItemSelected(newNode);
832     platformHandleFocusedUIElementChanged(oldNode, newNode);
833 }
834     
835 void AXObjectCache::selectedChildrenChanged(Node* node)
836 {
837     handleMenuItemSelected(node);
838     
839     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
840     // to find the container which should send out the notification.
841     postNotification(node, AXSelectedChildrenChanged, TargetObservableParent);
842 }
843
844 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
845 {
846     if (renderer)
847         handleMenuItemSelected(renderer->node());
848
849     // postTarget is TargetObservableParent so that you can pass in any child of an element and it will go up the parent tree
850     // to find the container which should send out the notification.
851     postNotification(renderer, AXSelectedChildrenChanged, TargetObservableParent);
852 }
853
854 void AXObjectCache::nodeTextChangeNotification(Node* node, AXTextChange textChange, unsigned offset, const String& text)
855 {
856     if (!node)
857         return;
858
859     stopCachingComputedObjectAttributes();
860
861     // Delegate on the right platform
862     AccessibilityObject* obj = getOrCreate(node);
863     nodeTextChangePlatformNotification(obj, textChange, offset, text);
864 }
865
866 void AXObjectCache::frameLoadingEventNotification(Frame* frame, AXLoadingEvent loadingEvent)
867 {
868     if (!frame)
869         return;
870
871     // Delegate on the right platform
872     RenderView* contentRenderer = frame->contentRenderer();
873     if (!contentRenderer)
874         return;
875
876     AccessibilityObject* obj = getOrCreate(contentRenderer);
877     frameLoadingEventPlatformNotification(obj, loadingEvent);
878 }
879
880 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
881 {
882     if (!view)
883         return;
884     
885     // We don't want to create a scroll view from this method, only update an existing one.
886     if (AccessibilityObject* scrollViewObject = get(view)) {
887         stopCachingComputedObjectAttributes();
888         scrollViewObject->updateChildrenIfNecessary();
889     }
890 }
891     
892 void AXObjectCache::handleAriaExpandedChange(Node* node)
893 {
894     if (AccessibilityObject* obj = getOrCreate(node))
895         obj->handleAriaExpandedChanged();
896 }
897     
898 void AXObjectCache::handleActiveDescendantChanged(Node* node)
899 {
900     if (AccessibilityObject* obj = getOrCreate(node))
901         obj->handleActiveDescendantChanged();
902 }
903
904 void AXObjectCache::handleAriaRoleChanged(Node* node)
905 {
906     stopCachingComputedObjectAttributes();
907
908     if (AccessibilityObject* obj = getOrCreate(node)) {
909         obj->updateAccessibilityRole();
910         obj->notifyIfIgnoredValueChanged();
911     }
912 }
913
914 void AXObjectCache::handleAttributeChanged(const QualifiedName& attrName, Element* element)
915 {
916     if (attrName == roleAttr)
917         handleAriaRoleChanged(element);
918     else if (attrName == altAttr || attrName == titleAttr)
919         textChanged(element);
920     else if (attrName == forAttr && isHTMLLabelElement(element))
921         labelChanged(element);
922
923     if (!attrName.localName().string().startsWith("aria-"))
924         return;
925
926     if (attrName == aria_activedescendantAttr)
927         handleActiveDescendantChanged(element);
928     else if (attrName == aria_busyAttr)
929         postNotification(element, AXObjectCache::AXElementBusyChanged);
930     else if (attrName == aria_valuenowAttr || attrName == aria_valuetextAttr)
931         postNotification(element, AXObjectCache::AXValueChanged);
932     else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr)
933         textChanged(element);
934     else if (attrName == aria_checkedAttr)
935         checkedStateChanged(element);
936     else if (attrName == aria_selectedAttr)
937         selectedChildrenChanged(element);
938     else if (attrName == aria_expandedAttr)
939         handleAriaExpandedChange(element);
940     else if (attrName == aria_hiddenAttr)
941         childrenChanged(element->parentNode(), element);
942     else if (attrName == aria_invalidAttr)
943         postNotification(element, AXObjectCache::AXInvalidStatusChanged);
944     else
945         postNotification(element, AXObjectCache::AXAriaAttributeChanged);
946 }
947
948 void AXObjectCache::labelChanged(Element* element)
949 {
950     ASSERT(isHTMLLabelElement(element));
951     HTMLElement* correspondingControl = toHTMLLabelElement(element)->control();
952     textChanged(correspondingControl);
953 }
954
955 void AXObjectCache::recomputeIsIgnored(RenderObject* renderer)
956 {
957     if (AccessibilityObject* obj = get(renderer))
958         obj->notifyIfIgnoredValueChanged();
959 }
960
961 void AXObjectCache::startCachingComputedObjectAttributesUntilTreeMutates()
962 {
963     if (!m_computedObjectAttributeCache)
964         m_computedObjectAttributeCache = std::make_unique<AXComputedObjectAttributeCache>();
965 }
966
967 void AXObjectCache::stopCachingComputedObjectAttributes()
968 {
969     m_computedObjectAttributeCache = nullptr;
970 }
971
972 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
973 {
974     if (!isNodeInUse(textMarkerData.node))
975         return VisiblePosition();
976     
977     // FIXME: Accessability should make it clear these are DOM-compliant offsets or store Position objects.
978     VisiblePosition visiblePos = VisiblePosition(createLegacyEditingPosition(textMarkerData.node, textMarkerData.offset), textMarkerData.affinity);
979     Position deepPos = visiblePos.deepEquivalent();
980     if (deepPos.isNull())
981         return VisiblePosition();
982     
983     RenderObject* renderer = deepPos.deprecatedNode()->renderer();
984     if (!renderer)
985         return VisiblePosition();
986     
987     AXObjectCache* cache = renderer->document().axObjectCache();
988     if (!cache->isIDinUse(textMarkerData.axID))
989         return VisiblePosition();
990     
991     if (deepPos.deprecatedNode() != textMarkerData.node || deepPos.deprecatedEditingOffset() != textMarkerData.offset)
992         return VisiblePosition();
993     
994     return visiblePos;
995 }
996
997 void AXObjectCache::textMarkerDataForVisiblePosition(TextMarkerData& textMarkerData, const VisiblePosition& visiblePos)
998 {
999     // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
1000     // This also allows callers to check for failure by looking at textMarkerData upon return.
1001     memset(&textMarkerData, 0, sizeof(TextMarkerData));
1002     
1003     if (visiblePos.isNull())
1004         return;
1005     
1006     Position deepPos = visiblePos.deepEquivalent();
1007     Node* domNode = deepPos.deprecatedNode();
1008     ASSERT(domNode);
1009     if (!domNode)
1010         return;
1011     
1012     if (domNode->isHTMLElement()) {
1013         HTMLInputElement* inputElement = domNode->toInputElement();
1014         if (inputElement && inputElement->isPasswordField())
1015             return;
1016     }
1017     
1018     // find or create an accessibility object for this node
1019     AXObjectCache* cache = domNode->document().axObjectCache();
1020     RefPtr<AccessibilityObject> obj = cache->getOrCreate(domNode);
1021     
1022     textMarkerData.axID = obj.get()->axObjectID();
1023     textMarkerData.node = domNode;
1024     textMarkerData.offset = deepPos.deprecatedEditingOffset();
1025     textMarkerData.affinity = visiblePos.affinity();   
1026     
1027     cache->setNodeInUse(domNode);
1028 }
1029
1030 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
1031 {
1032     const Element* result = node->rootEditableElement();
1033     const Element* element = node->isElementNode() ? toElement(node) : node->parentElement();
1034
1035     for (; element; element = element->parentElement()) {
1036         if (nodeIsTextControl(element))
1037             result = element;
1038     }
1039
1040     return result;
1041 }
1042
1043 void AXObjectCache::clearTextMarkerNodesInUse(Document* document)
1044 {
1045     HashSet<Node*>::iterator it = m_textMarkerNodes.begin();
1046     HashSet<Node*>::iterator end = m_textMarkerNodes.end();
1047
1048     // Check each node to see if it's inside the document being deleted.
1049     HashSet<Node*> nodesToDelete;
1050     for (; it != end; ++it) {
1051         if (&(*it)->document() == document)
1052             nodesToDelete.add(*it);
1053     }
1054     
1055     it = nodesToDelete.begin();
1056     end = nodesToDelete.end();
1057     for (; it != end; ++it)
1058         m_textMarkerNodes.remove(*it);
1059 }
1060     
1061 bool AXObjectCache::nodeIsTextControl(const Node* node)
1062 {
1063     if (!node)
1064         return false;
1065
1066     const AccessibilityObject* axObject = getOrCreate(const_cast<Node*>(node));
1067     return axObject && axObject->isTextControl();
1068 }
1069     
1070 bool isNodeAriaVisible(Node* node)
1071 {
1072     if (!node)
1073         return false;
1074     
1075     // To determine if a node is ARIA visible, we need to check the parent hierarchy to see if anyone specifies
1076     // aria-hidden explicitly.
1077     for (Node* testNode = node; testNode; testNode = testNode->parentNode()) {
1078         if (testNode->isElementNode()) {
1079             const AtomicString& ariaHiddenValue = toElement(testNode)->fastGetAttribute(aria_hiddenAttr);
1080             if (equalIgnoringCase(ariaHiddenValue, "false"))
1081                 return true;
1082             if (equalIgnoringCase(ariaHiddenValue, "true"))
1083                 return false;
1084         }
1085     }
1086     
1087     return false;
1088 }
1089
1090 AXAttributeCacheEnabler::AXAttributeCacheEnabler(AXObjectCache* cache)
1091     : m_cache(cache)
1092 {
1093     if (m_cache)
1094         m_cache->startCachingComputedObjectAttributesUntilTreeMutates();
1095 }
1096     
1097 AXAttributeCacheEnabler::~AXAttributeCacheEnabler()
1098 {
1099     if (m_cache)
1100         m_cache->stopCachingComputedObjectAttributes();
1101 }
1102     
1103 } // namespace WebCore
1104
1105 #endif // HAVE(ACCESSIBILITY)