Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 Computer, 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 #include "core/accessibility/AXObjectCache.h"
32
33 #include "core/HTMLNames.h"
34 #include "core/accessibility/AXARIAGrid.h"
35 #include "core/accessibility/AXARIAGridCell.h"
36 #include "core/accessibility/AXARIAGridRow.h"
37 #include "core/accessibility/AXImageMapLink.h"
38 #include "core/accessibility/AXInlineTextBox.h"
39 #include "core/accessibility/AXList.h"
40 #include "core/accessibility/AXListBox.h"
41 #include "core/accessibility/AXListBoxOption.h"
42 #include "core/accessibility/AXMediaControls.h"
43 #include "core/accessibility/AXMenuList.h"
44 #include "core/accessibility/AXMenuListOption.h"
45 #include "core/accessibility/AXMenuListPopup.h"
46 #include "core/accessibility/AXProgressIndicator.h"
47 #include "core/accessibility/AXRenderObject.h"
48 #include "core/accessibility/AXSVGRoot.h"
49 #include "core/accessibility/AXScrollView.h"
50 #include "core/accessibility/AXScrollbar.h"
51 #include "core/accessibility/AXSlider.h"
52 #include "core/accessibility/AXSpinButton.h"
53 #include "core/accessibility/AXTable.h"
54 #include "core/accessibility/AXTableCell.h"
55 #include "core/accessibility/AXTableColumn.h"
56 #include "core/accessibility/AXTableHeaderContainer.h"
57 #include "core/accessibility/AXTableRow.h"
58 #include "core/dom/Document.h"
59 #include "core/frame/LocalFrame.h"
60 #include "core/html/HTMLAreaElement.h"
61 #include "core/html/HTMLImageElement.h"
62 #include "core/html/HTMLInputElement.h"
63 #include "core/html/HTMLLabelElement.h"
64 #include "core/page/Chrome.h"
65 #include "core/page/ChromeClient.h"
66 #include "core/page/FocusController.h"
67 #include "core/page/Page.h"
68 #include "core/rendering/AbstractInlineTextBox.h"
69 #include "core/rendering/RenderListBox.h"
70 #include "core/rendering/RenderMenuList.h"
71 #include "core/rendering/RenderProgress.h"
72 #include "core/rendering/RenderSlider.h"
73 #include "core/rendering/RenderTable.h"
74 #include "core/rendering/RenderTableCell.h"
75 #include "core/rendering/RenderTableRow.h"
76 #include "core/rendering/RenderView.h"
77 #include "platform/scroll/ScrollView.h"
78 #include "wtf/PassRefPtr.h"
79
80 namespace blink {
81
82 using namespace HTMLNames;
83
84 AXObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const
85 {
86     HashMap<AXID, CachedAXObjectAttributes>::const_iterator it = m_idMapping.find(id);
87     return it != m_idMapping.end() ? it->value.ignored : DefaultBehavior;
88 }
89
90 void AXComputedObjectAttributeCache::setIgnored(AXID id, AXObjectInclusion inclusion)
91 {
92     HashMap<AXID, CachedAXObjectAttributes>::iterator it = m_idMapping.find(id);
93     if (it != m_idMapping.end()) {
94         it->value.ignored = inclusion;
95     } else {
96         CachedAXObjectAttributes attributes;
97         attributes.ignored = inclusion;
98         m_idMapping.set(id, attributes);
99     }
100 }
101
102 void AXComputedObjectAttributeCache::clear()
103 {
104     m_idMapping.clear();
105 }
106
107 bool AXObjectCache::gAccessibilityEnabled = false;
108 bool AXObjectCache::gInlineTextBoxAccessibility = false;
109
110 AXObjectCache::AXObjectCache(Document& document)
111     : m_document(document)
112     , m_notificationPostTimer(this, &AXObjectCache::notificationPostTimerFired)
113 {
114     m_computedObjectAttributeCache = AXComputedObjectAttributeCache::create();
115 }
116
117 AXObjectCache::~AXObjectCache()
118 {
119     m_notificationPostTimer.stop();
120
121     HashMap<AXID, RefPtr<AXObject> >::iterator end = m_objects.end();
122     for (HashMap<AXID, RefPtr<AXObject> >::iterator it = m_objects.begin(); it != end; ++it) {
123         AXObject* obj = (*it).value.get();
124         detachWrapper(obj);
125         obj->detach();
126         removeAXID(obj);
127     }
128 }
129
130 AXObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
131 {
132     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
133     // in the list of children for its corresponding image.
134     if (!areaElement)
135         return 0;
136
137     HTMLImageElement* imageElement = areaElement->imageElement();
138     if (!imageElement)
139         return 0;
140
141     AXObject* axRenderImage = areaElement->document().axObjectCache()->getOrCreate(imageElement);
142     if (!axRenderImage)
143         return 0;
144
145     AXObject::AccessibilityChildrenVector imageChildren = axRenderImage->children();
146     unsigned count = imageChildren.size();
147     for (unsigned k = 0; k < count; ++k) {
148         AXObject* child = imageChildren[k].get();
149         if (!child->isImageMapLink())
150             continue;
151
152         if (toAXImageMapLink(child)->areaElement() == areaElement)
153             return child;
154     }
155
156     return 0;
157 }
158
159 AXObject* AXObjectCache::focusedUIElementForPage(const Page* page)
160 {
161     if (!gAccessibilityEnabled)
162         return 0;
163
164     // Cross-process accessibility is not yet implemented.
165     if (!page->focusController().focusedOrMainFrame()->isLocalFrame())
166         return 0;
167
168     // get the focused node in the page
169     Document* focusedDocument = toLocalFrame(page->focusController().focusedOrMainFrame())->document();
170     Node* focusedNode = focusedDocument->focusedElement();
171     if (!focusedNode)
172         focusedNode = focusedDocument;
173
174     if (isHTMLAreaElement(*focusedNode))
175         return focusedImageMapUIElement(toHTMLAreaElement(focusedNode));
176
177     AXObject* obj = focusedNode->document().axObjectCache()->getOrCreate(focusedNode);
178     if (!obj)
179         return 0;
180
181     if (obj->shouldFocusActiveDescendant()) {
182         if (AXObject* descendant = obj->activeDescendant())
183             obj = descendant;
184     }
185
186     // the HTML element, for example, is focusable but has an AX object that is ignored
187     if (obj->accessibilityIsIgnored())
188         obj = obj->parentObjectUnignored();
189
190     return obj;
191 }
192
193 AXObject* AXObjectCache::get(Widget* widget)
194 {
195     if (!widget)
196         return 0;
197
198     AXID axID = m_widgetObjectMapping.get(widget);
199     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
200     if (!axID)
201         return 0;
202
203     return m_objects.get(axID);
204 }
205
206 AXObject* AXObjectCache::get(RenderObject* renderer)
207 {
208     if (!renderer)
209         return 0;
210
211     AXID axID = m_renderObjectMapping.get(renderer);
212     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
213     if (!axID)
214         return 0;
215
216     return m_objects.get(axID);
217 }
218
219 AXObject* AXObjectCache::get(Node* node)
220 {
221     if (!node)
222         return 0;
223
224     AXID renderID = node->renderer() ? m_renderObjectMapping.get(node->renderer()) : 0;
225     ASSERT(!HashTraits<AXID>::isDeletedValue(renderID));
226
227     AXID nodeID = m_nodeObjectMapping.get(node);
228     ASSERT(!HashTraits<AXID>::isDeletedValue(nodeID));
229
230     if (node->renderer() && nodeID && !renderID) {
231         // This can happen if an AXNodeObject is created for a node that's not
232         // rendered, but later something changes and it gets a renderer (like if it's
233         // reparented).
234         remove(nodeID);
235         return 0;
236     }
237
238     if (renderID)
239         return m_objects.get(renderID);
240
241     if (!nodeID)
242         return 0;
243
244     return m_objects.get(nodeID);
245 }
246
247 AXObject* AXObjectCache::get(AbstractInlineTextBox* inlineTextBox)
248 {
249     if (!inlineTextBox)
250         return 0;
251
252     AXID axID = m_inlineTextBoxObjectMapping.get(inlineTextBox);
253     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
254     if (!axID)
255         return 0;
256
257     return m_objects.get(axID);
258 }
259
260 // FIXME: This probably belongs on Node.
261 // FIXME: This should take a const char*, but one caller passes nullAtom.
262 bool nodeHasRole(Node* node, const String& role)
263 {
264     if (!node || !node->isElementNode())
265         return false;
266
267     return equalIgnoringCase(toElement(node)->getAttribute(roleAttr), role);
268 }
269
270 static PassRefPtr<AXObject> createFromRenderer(RenderObject* renderer)
271 {
272     // FIXME: How could renderer->node() ever not be an Element?
273     Node* node = renderer->node();
274
275     // If the node is aria role="list" or the aria role is empty and its a
276     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
277     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
278         || (nodeHasRole(node, nullAtom) && (isHTMLUListElement(*node) || isHTMLOListElement(*node) || isHTMLDListElement(*node)))))
279         return AXList::create(renderer);
280
281     // aria tables
282     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid"))
283         return AXARIAGrid::create(renderer);
284     if (nodeHasRole(node, "row"))
285         return AXARIAGridRow::create(renderer);
286     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
287         return AXARIAGridCell::create(renderer);
288
289     // media controls
290     if (node && node->isMediaControlElement())
291         return AccessibilityMediaControl::create(renderer);
292
293     if (isHTMLOptionElement(node))
294         return AXListBoxOption::create(renderer);
295
296     if (renderer->isSVGRoot())
297         return AXSVGRoot::create(renderer);
298
299     if (renderer->isBoxModelObject()) {
300         RenderBoxModelObject* cssBox = toRenderBoxModelObject(renderer);
301         if (cssBox->isListBox())
302             return AXListBox::create(toRenderListBox(cssBox));
303         if (cssBox->isMenuList())
304             return AXMenuList::create(toRenderMenuList(cssBox));
305
306         // standard tables
307         if (cssBox->isTable())
308             return AXTable::create(toRenderTable(cssBox));
309         if (cssBox->isTableRow())
310             return AXTableRow::create(toRenderTableRow(cssBox));
311         if (cssBox->isTableCell())
312             return AXTableCell::create(toRenderTableCell(cssBox));
313
314         // progress bar
315         if (cssBox->isProgress())
316             return AXProgressIndicator::create(toRenderProgress(cssBox));
317
318         // input type=range
319         if (cssBox->isSlider())
320             return AXSlider::create(toRenderSlider(cssBox));
321     }
322
323     return AXRenderObject::create(renderer);
324 }
325
326 static PassRefPtr<AXObject> createFromNode(Node* node)
327 {
328     return AXNodeObject::create(node);
329 }
330
331 static PassRefPtr<AXObject> createFromInlineTextBox(AbstractInlineTextBox* inlineTextBox)
332 {
333     return AXInlineTextBox::create(inlineTextBox);
334 }
335
336 AXObject* AXObjectCache::getOrCreate(Widget* widget)
337 {
338     if (!widget)
339         return 0;
340
341     if (AXObject* obj = get(widget))
342         return obj;
343
344     RefPtr<AXObject> newObj = nullptr;
345     if (widget->isFrameView())
346         newObj = AXScrollView::create(toScrollView(widget));
347     else if (widget->isScrollbar())
348         newObj = AXScrollbar::create(toScrollbar(widget));
349
350     // Will crash later if we have two objects for the same widget.
351     ASSERT(!get(widget));
352
353     // Catch the case if an (unsupported) widget type is used. Only FrameView and ScrollBar are supported now.
354     ASSERT(newObj);
355     if (!newObj)
356         return 0;
357
358     getAXID(newObj.get());
359
360     m_widgetObjectMapping.set(widget, newObj->axObjectID());
361     m_objects.set(newObj->axObjectID(), newObj);
362     newObj->init();
363     attachWrapper(newObj.get());
364     return newObj.get();
365 }
366
367 AXObject* AXObjectCache::getOrCreate(Node* node)
368 {
369     if (!node)
370         return 0;
371
372     if (AXObject* obj = get(node))
373         return obj;
374
375     if (node->renderer())
376         return getOrCreate(node->renderer());
377
378     if (!node->parentElement())
379         return 0;
380
381     // It's only allowed to create an AXObject from a Node if it's in a canvas subtree.
382     // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes.
383     bool inCanvasSubtree = node->parentElement()->isInCanvasSubtree();
384     bool isHidden = !node->renderer() && isNodeAriaVisible(node);
385     if (!inCanvasSubtree && !isHidden)
386         return 0;
387
388     RefPtr<AXObject> newObj = createFromNode(node);
389
390     // Will crash later if we have two objects for the same node.
391     ASSERT(!get(node));
392
393     getAXID(newObj.get());
394
395     m_nodeObjectMapping.set(node, newObj->axObjectID());
396     m_objects.set(newObj->axObjectID(), newObj);
397     newObj->init();
398     attachWrapper(newObj.get());
399     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
400
401     return newObj.get();
402 }
403
404 AXObject* AXObjectCache::getOrCreate(RenderObject* renderer)
405 {
406     if (!renderer)
407         return 0;
408
409     if (AXObject* obj = get(renderer))
410         return obj;
411
412     RefPtr<AXObject> newObj = createFromRenderer(renderer);
413
414     // Will crash later if we have two objects for the same renderer.
415     ASSERT(!get(renderer));
416
417     getAXID(newObj.get());
418
419     m_renderObjectMapping.set(renderer, newObj->axObjectID());
420     m_objects.set(newObj->axObjectID(), newObj);
421     newObj->init();
422     attachWrapper(newObj.get());
423     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
424
425     return newObj.get();
426 }
427
428 AXObject* AXObjectCache::getOrCreate(AbstractInlineTextBox* inlineTextBox)
429 {
430     if (!inlineTextBox)
431         return 0;
432
433     if (AXObject* obj = get(inlineTextBox))
434         return obj;
435
436     RefPtr<AXObject> newObj = createFromInlineTextBox(inlineTextBox);
437
438     // Will crash later if we have two objects for the same inlineTextBox.
439     ASSERT(!get(inlineTextBox));
440
441     getAXID(newObj.get());
442
443     m_inlineTextBoxObjectMapping.set(inlineTextBox, newObj->axObjectID());
444     m_objects.set(newObj->axObjectID(), newObj);
445     newObj->init();
446     attachWrapper(newObj.get());
447     newObj->setLastKnownIsIgnoredValue(newObj->accessibilityIsIgnored());
448
449     return newObj.get();
450 }
451
452 AXObject* AXObjectCache::rootObject()
453 {
454     if (!gAccessibilityEnabled)
455         return 0;
456
457     return getOrCreate(m_document.view());
458 }
459
460 AXObject* AXObjectCache::getOrCreate(AccessibilityRole role)
461 {
462     RefPtr<AXObject> obj = nullptr;
463
464     // will be filled in...
465     switch (role) {
466     case ImageMapLinkRole:
467         obj = AXImageMapLink::create();
468         break;
469     case ColumnRole:
470         obj = AXTableColumn::create();
471         break;
472     case TableHeaderContainerRole:
473         obj = AXTableHeaderContainer::create();
474         break;
475     case SliderThumbRole:
476         obj = AXSliderThumb::create();
477         break;
478     case MenuListPopupRole:
479         obj = AXMenuListPopup::create();
480         break;
481     case MenuListOptionRole:
482         obj = AXMenuListOption::create();
483         break;
484     case SpinButtonRole:
485         obj = AXSpinButton::create();
486         break;
487     case SpinButtonPartRole:
488         obj = AXSpinButtonPart::create();
489         break;
490     default:
491         obj = nullptr;
492     }
493
494     if (obj)
495         getAXID(obj.get());
496     else
497         return 0;
498
499     m_objects.set(obj->axObjectID(), obj);
500     obj->init();
501     attachWrapper(obj.get());
502     return obj.get();
503 }
504
505 void AXObjectCache::remove(AXID axID)
506 {
507     if (!axID)
508         return;
509
510     // first fetch object to operate some cleanup functions on it
511     AXObject* obj = m_objects.get(axID);
512     if (!obj)
513         return;
514
515     detachWrapper(obj);
516     obj->detach();
517     removeAXID(obj);
518
519     // finally remove the object
520     if (!m_objects.take(axID))
521         return;
522
523     ASSERT(m_objects.size() >= m_idsInUse.size());
524 }
525
526 void AXObjectCache::remove(RenderObject* renderer)
527 {
528     if (!renderer)
529         return;
530
531     AXID axID = m_renderObjectMapping.get(renderer);
532     remove(axID);
533     m_renderObjectMapping.remove(renderer);
534 }
535
536 void AXObjectCache::remove(Node* node)
537 {
538     if (!node)
539         return;
540
541     removeNodeForUse(node);
542
543     // This is all safe even if we didn't have a mapping.
544     AXID axID = m_nodeObjectMapping.get(node);
545     remove(axID);
546     m_nodeObjectMapping.remove(node);
547
548     if (node->renderer()) {
549         remove(node->renderer());
550         return;
551     }
552 }
553
554 void AXObjectCache::remove(Widget* view)
555 {
556     if (!view)
557         return;
558
559     AXID axID = m_widgetObjectMapping.get(view);
560     remove(axID);
561     m_widgetObjectMapping.remove(view);
562 }
563
564 void AXObjectCache::remove(AbstractInlineTextBox* inlineTextBox)
565 {
566     if (!inlineTextBox)
567         return;
568
569     AXID axID = m_inlineTextBoxObjectMapping.get(inlineTextBox);
570     remove(axID);
571     m_inlineTextBoxObjectMapping.remove(inlineTextBox);
572 }
573
574 // FIXME: Oilpan: Use a weak hashmap for this instead.
575 void AXObjectCache::clearWeakMembers(Visitor* visitor)
576 {
577     Vector<Node*> deadNodes;
578     for (HashMap<Node*, AXID>::iterator it = m_nodeObjectMapping.begin(); it != m_nodeObjectMapping.end(); ++it) {
579         if (!visitor->isAlive(it->key))
580             deadNodes.append(it->key);
581     }
582     for (unsigned i = 0; i < deadNodes.size(); ++i)
583         remove(deadNodes[i]);
584 }
585
586 AXID AXObjectCache::platformGenerateAXID() const
587 {
588     static AXID lastUsedID = 0;
589
590     // Generate a new ID.
591     AXID objID = lastUsedID;
592     do {
593         ++objID;
594     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
595
596     lastUsedID = objID;
597
598     return objID;
599 }
600
601 AXID AXObjectCache::getAXID(AXObject* obj)
602 {
603     // check for already-assigned ID
604     AXID objID = obj->axObjectID();
605     if (objID) {
606         ASSERT(m_idsInUse.contains(objID));
607         return objID;
608     }
609
610     objID = platformGenerateAXID();
611
612     m_idsInUse.add(objID);
613     obj->setAXObjectID(objID);
614
615     return objID;
616 }
617
618 void AXObjectCache::removeAXID(AXObject* object)
619 {
620     if (!object)
621         return;
622
623     AXID objID = object->axObjectID();
624     if (!objID)
625         return;
626     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
627     ASSERT(m_idsInUse.contains(objID));
628     object->setAXObjectID(0);
629     m_idsInUse.remove(objID);
630 }
631
632 void AXObjectCache::selectionChanged(Node* node)
633 {
634     // Find the nearest ancestor that already has an accessibility object, since we
635     // might be in the middle of a layout.
636     while (node) {
637         if (AXObject* obj = get(node)) {
638             obj->selectionChanged();
639             return;
640         }
641         node = node->parentNode();
642     }
643 }
644
645 void AXObjectCache::textChanged(Node* node)
646 {
647     textChanged(getOrCreate(node));
648 }
649
650 void AXObjectCache::textChanged(RenderObject* renderer)
651 {
652     textChanged(getOrCreate(renderer));
653 }
654
655 void AXObjectCache::textChanged(AXObject* obj)
656 {
657     if (!obj)
658         return;
659
660     bool parentAlreadyExists = obj->parentObjectIfExists();
661     obj->textChanged();
662     postNotification(obj, obj->document(), AXObjectCache::AXTextChanged, true);
663     if (parentAlreadyExists)
664         obj->notifyIfIgnoredValueChanged();
665 }
666
667 void AXObjectCache::updateCacheAfterNodeIsAttached(Node* node)
668 {
669     // Calling get() will update the AX object if we had an AXNodeObject but now we need
670     // an AXRenderObject, because it was reparented to a location outside of a canvas.
671     get(node);
672 }
673
674 void AXObjectCache::childrenChanged(Node* node)
675 {
676     childrenChanged(get(node));
677 }
678
679 void AXObjectCache::childrenChanged(RenderObject* renderer)
680 {
681     childrenChanged(get(renderer));
682 }
683
684 void AXObjectCache::childrenChanged(AXObject* obj)
685 {
686     if (!obj)
687         return;
688
689     obj->childrenChanged();
690 }
691
692 void AXObjectCache::notificationPostTimerFired(Timer<AXObjectCache>*)
693 {
694     RefPtrWillBeRawPtr<Document> protectorForCacheOwner(m_document);
695
696     m_notificationPostTimer.stop();
697
698     unsigned i = 0, count = m_notificationsToPost.size();
699     for (i = 0; i < count; ++i) {
700         AXObject* obj = m_notificationsToPost[i].first.get();
701         if (!obj->axObjectID())
702             continue;
703
704         if (!obj->axObjectCache())
705             continue;
706
707 #if ENABLE(ASSERT)
708         // Make sure none of the render views are in the process of being layed out.
709         // Notifications should only be sent after the renderer has finished
710         if (obj->isAXRenderObject()) {
711             AXRenderObject* renderObj = toAXRenderObject(obj);
712             RenderObject* renderer = renderObj->renderer();
713             if (renderer && renderer->view())
714                 ASSERT(!renderer->view()->layoutState());
715         }
716 #endif
717
718         AXNotification notification = m_notificationsToPost[i].second;
719         postPlatformNotification(obj, notification);
720
721         if (notification == AXChildrenChanged && obj->parentObjectIfExists() && obj->lastKnownIsIgnoredValue() != obj->accessibilityIsIgnored())
722             childrenChanged(obj->parentObject());
723     }
724
725     m_notificationsToPost.clear();
726 }
727
728 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, bool postToElement, PostType postType)
729 {
730     if (!renderer)
731         return;
732
733     m_computedObjectAttributeCache->clear();
734
735     // Get an accessibility object that already exists. One should not be created here
736     // because a render update may be in progress and creating an AX object can re-trigger a layout
737     RefPtr<AXObject> object = get(renderer);
738     while (!object && renderer) {
739         renderer = renderer->parent();
740         object = get(renderer);
741     }
742
743     if (!renderer)
744         return;
745
746     postNotification(object.get(), &renderer->document(), notification, postToElement, postType);
747 }
748
749 void AXObjectCache::postNotification(Node* node, AXNotification notification, bool postToElement, PostType postType)
750 {
751     if (!node)
752         return;
753
754     m_computedObjectAttributeCache->clear();
755
756     // Get an accessibility object that already exists. One should not be created here
757     // because a render update may be in progress and creating an AX object can re-trigger a layout
758     RefPtr<AXObject> object = get(node);
759     while (!object && node) {
760         node = node->parentNode();
761         object = get(node);
762     }
763
764     if (!node)
765         return;
766
767     postNotification(object.get(), &node->document(), notification, postToElement, postType);
768 }
769
770 void AXObjectCache::postNotification(AXObject* object, Document* document, AXNotification notification, bool postToElement, PostType postType)
771 {
772     m_computedObjectAttributeCache->clear();
773
774     if (object && !postToElement)
775         object = object->observableObject();
776
777     if (!object && document)
778         object = get(document->renderView());
779
780     if (!object)
781         return;
782
783     if (postType == PostAsynchronously) {
784         m_notificationsToPost.append(std::make_pair(object, notification));
785         if (!m_notificationPostTimer.isActive())
786             m_notificationPostTimer.startOneShot(0, FROM_HERE);
787     } else {
788         postPlatformNotification(object, notification);
789     }
790 }
791
792 void AXObjectCache::checkedStateChanged(Node* node)
793 {
794     postNotification(node, AXObjectCache::AXCheckedStateChanged, true);
795 }
796
797 void AXObjectCache::selectedChildrenChanged(Node* node)
798 {
799     // postToElement is false so that you can pass in any child of an element and it will go up the parent tree
800     // to find the container which should send out the notification.
801     postNotification(node, AXSelectedChildrenChanged, false);
802 }
803
804 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
805 {
806     // postToElement is false so that you can pass in any child of an element and it will go up the parent tree
807     // to find the container which should send out the notification.
808     postNotification(renderer, AXSelectedChildrenChanged, false);
809 }
810
811 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
812 {
813     if (!view)
814         return;
815
816     // We don't want to create a scroll view from this method, only update an existing one.
817     if (AXObject* scrollViewObject = get(view)) {
818         m_computedObjectAttributeCache->clear();
819         scrollViewObject->updateChildrenIfNecessary();
820     }
821 }
822
823 void AXObjectCache::handleLayoutComplete(RenderObject* renderer)
824 {
825     if (!renderer)
826         return;
827
828     m_computedObjectAttributeCache->clear();
829
830     // Create the AXObject if it didn't yet exist - that's always safe at the end of a layout, and it
831     // allows an AX notification to be sent when a page has its first layout, rather than when the
832     // document first loads.
833     if (AXObject* obj = getOrCreate(renderer))
834         postNotification(obj, obj->document(), AXLayoutComplete, true);
835 }
836
837 void AXObjectCache::handleAriaExpandedChange(Node* node)
838 {
839     if (AXObject* obj = getOrCreate(node))
840         obj->handleAriaExpandedChanged();
841 }
842
843 void AXObjectCache::handleActiveDescendantChanged(Node* node)
844 {
845     if (AXObject* obj = getOrCreate(node))
846         obj->handleActiveDescendantChanged();
847 }
848
849 void AXObjectCache::handleAriaRoleChanged(Node* node)
850 {
851     if (AXObject* obj = getOrCreate(node)) {
852         obj->updateAccessibilityRole();
853         m_computedObjectAttributeCache->clear();
854         obj->notifyIfIgnoredValueChanged();
855     }
856 }
857
858 void AXObjectCache::handleAttributeChanged(const QualifiedName& attrName, Element* element)
859 {
860     if (attrName == roleAttr)
861         handleAriaRoleChanged(element);
862     else if (attrName == altAttr || attrName == titleAttr)
863         textChanged(element);
864     else if (attrName == forAttr && isHTMLLabelElement(*element))
865         labelChanged(element);
866
867     if (!attrName.localName().string().startsWith("aria-"))
868         return;
869
870     if (attrName == aria_activedescendantAttr)
871         handleActiveDescendantChanged(element);
872     else if (attrName == aria_valuenowAttr || attrName == aria_valuetextAttr)
873         postNotification(element, AXObjectCache::AXValueChanged, true);
874     else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr)
875         textChanged(element);
876     else if (attrName == aria_checkedAttr)
877         checkedStateChanged(element);
878     else if (attrName == aria_selectedAttr)
879         selectedChildrenChanged(element);
880     else if (attrName == aria_expandedAttr)
881         handleAriaExpandedChange(element);
882     else if (attrName == aria_hiddenAttr)
883         childrenChanged(element->parentNode());
884     else if (attrName == aria_invalidAttr)
885         postNotification(element, AXObjectCache::AXInvalidStatusChanged, true);
886     else
887         postNotification(element, AXObjectCache::AXAriaAttributeChanged, true);
888 }
889
890 void AXObjectCache::labelChanged(Element* element)
891 {
892     textChanged(toHTMLLabelElement(element)->control());
893 }
894
895 void AXObjectCache::recomputeIsIgnored(RenderObject* renderer)
896 {
897     if (AXObject* obj = get(renderer))
898         obj->notifyIfIgnoredValueChanged();
899 }
900
901 void AXObjectCache::inlineTextBoxesUpdated(RenderObject* renderer)
902 {
903     if (!gInlineTextBoxAccessibility)
904         return;
905
906     // Only update if the accessibility object already exists and it's
907     // not already marked as dirty.
908     if (AXObject* obj = get(renderer)) {
909         if (!obj->needsToUpdateChildren()) {
910             obj->setNeedsToUpdateChildren();
911             postNotification(renderer, AXChildrenChanged, true);
912         }
913     }
914 }
915
916 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
917 {
918     const Element* result = node->rootEditableElement();
919     const Element* element = node->isElementNode() ? toElement(node) : node->parentElement();
920
921     for (; element; element = element->parentElement()) {
922         if (nodeIsTextControl(element))
923             result = element;
924     }
925
926     return result;
927 }
928
929 bool AXObjectCache::nodeIsTextControl(const Node* node)
930 {
931     if (!node)
932         return false;
933
934     const AXObject* axObject = getOrCreate(const_cast<Node*>(node));
935     return axObject && axObject->isTextControl();
936 }
937
938 bool isNodeAriaVisible(Node* node)
939 {
940     if (!node)
941         return false;
942
943     if (!node->isElementNode())
944         return false;
945
946     return equalIgnoringCase(toElement(node)->getAttribute(aria_hiddenAttr), "false");
947 }
948
949 void AXObjectCache::detachWrapper(AXObject* obj)
950 {
951     // In Chromium, AXObjects are not wrapped.
952 }
953
954 void AXObjectCache::attachWrapper(AXObject*)
955 {
956     // In Chromium, AXObjects are not wrapped.
957 }
958
959 void AXObjectCache::postPlatformNotification(AXObject* obj, AXNotification notification)
960 {
961     if (obj && obj->isAXScrollbar() && notification == AXValueChanged) {
962         // Send document value changed on scrollbar value changed notification.
963         Scrollbar* scrollBar = toAXScrollbar(obj)->scrollbar();
964         if (!scrollBar || !scrollBar->parent() || !scrollBar->parent()->isFrameView())
965             return;
966         Document* document = toFrameView(scrollBar->parent())->frame().document();
967         if (document != document->topDocument())
968             return;
969         obj = get(document->renderView());
970     }
971
972     if (!obj || !obj->document() || !obj->documentFrameView() || !obj->documentFrameView()->frame().page())
973         return;
974
975     ChromeClient& client = obj->documentFrameView()->frame().page()->chrome().client();
976
977     if (notification == AXActiveDescendantChanged
978         && obj->document()->focusedElement()
979         && obj->node() == obj->document()->focusedElement()) {
980         // Calling handleFocusedUIElementChanged will focus the new active
981         // descendant and send the AXFocusedUIElementChanged notification.
982         handleFocusedUIElementChanged(0, obj->document()->focusedElement());
983     }
984
985     client.postAccessibilityNotification(obj, notification);
986 }
987
988 void AXObjectCache::handleFocusedUIElementChanged(Node*, Node* newFocusedNode)
989 {
990     if (!newFocusedNode)
991         return;
992
993     Page* page = newFocusedNode->document().page();
994     if (!page)
995         return;
996
997     AXObject* focusedObject = focusedUIElementForPage(page);
998     if (!focusedObject)
999         return;
1000
1001     postPlatformNotification(focusedObject, AXFocusedUIElementChanged);
1002 }
1003
1004 void AXObjectCache::handleScrolledToAnchor(const Node* anchorNode)
1005 {
1006     // The anchor node may not be accessible. Post the notification for the
1007     // first accessible object.
1008     postPlatformNotification(AXObject::firstAccessibleObjectFromNode(anchorNode), AXScrolledToAnchor);
1009 }
1010
1011 void AXObjectCache::handleScrollPositionChanged(ScrollView* scrollView)
1012 {
1013     postPlatformNotification(getOrCreate(scrollView), AXScrollPositionChanged);
1014 }
1015
1016 void AXObjectCache::handleScrollPositionChanged(RenderObject* renderObject)
1017 {
1018     postPlatformNotification(getOrCreate(renderObject), AXScrollPositionChanged);
1019 }
1020
1021 void AXObjectCache::setCanvasObjectBounds(Element* element, const LayoutRect& rect)
1022 {
1023     AXObject* obj = getOrCreate(element);
1024     if (!obj)
1025         return;
1026
1027     obj->setElementRect(rect);
1028 }
1029
1030 } // namespace blink