AX: Need AccessibilityObjects for nodes without renderers in canvas subtree
[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 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 #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 "AccessibilityScrollView.h"
49 #include "AccessibilityScrollbar.h"
50 #include "AccessibilitySlider.h"
51 #include "AccessibilitySpinButton.h"
52 #include "AccessibilityTable.h"
53 #include "AccessibilityTableCell.h"
54 #include "AccessibilityTableColumn.h"
55 #include "AccessibilityTableHeaderContainer.h"
56 #include "AccessibilityTableRow.h"
57 #include "Document.h"
58 #include "FocusController.h"
59 #include "Frame.h"
60 #include "HTMLAreaElement.h"
61 #include "HTMLImageElement.h"
62 #include "HTMLInputElement.h"
63 #include "HTMLNames.h"
64 #if ENABLE(VIDEO)
65 #include "MediaControlElements.h"
66 #endif
67 #include "Page.h"
68 #include "RenderListBox.h"
69 #include "RenderMenuList.h"
70 #include "RenderProgress.h"
71 #include "RenderSlider.h"
72 #include "RenderTable.h"
73 #include "RenderTableCell.h"
74 #include "RenderTableRow.h"
75 #include "RenderView.h"
76 #include "ScrollView.h"
77
78 #include <wtf/PassRefPtr.h>
79
80 namespace WebCore {
81
82 using namespace HTMLNames;
83     
84 bool AXObjectCache::gAccessibilityEnabled = false;
85 bool AXObjectCache::gAccessibilityEnhancedUserInterfaceEnabled = false;
86
87 AXObjectCache::AXObjectCache(const Document* doc)
88     : m_notificationPostTimer(this, &AXObjectCache::notificationPostTimerFired)
89 {
90     m_document = const_cast<Document*>(doc);
91 }
92
93 AXObjectCache::~AXObjectCache()
94 {
95     HashMap<AXID, RefPtr<AccessibilityObject> >::iterator end = m_objects.end();
96     for (HashMap<AXID, RefPtr<AccessibilityObject> >::iterator it = m_objects.begin(); it != end; ++it) {
97         AccessibilityObject* obj = (*it).second.get();
98         detachWrapper(obj);
99         obj->detach();
100         removeAXID(obj);
101     }
102 }
103
104 AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement)
105 {
106     // Find the corresponding accessibility object for the HTMLAreaElement. This should be
107     // in the list of children for its corresponding image.
108     if (!areaElement)
109         return 0;
110     
111     HTMLImageElement* imageElement = areaElement->imageElement();
112     if (!imageElement)
113         return 0;
114     
115     AccessibilityObject* axRenderImage = areaElement->document()->axObjectCache()->getOrCreate(imageElement->renderer());
116     if (!axRenderImage)
117         return 0;
118     
119     AccessibilityObject::AccessibilityChildrenVector imageChildren = axRenderImage->children();
120     unsigned count = imageChildren.size();
121     for (unsigned k = 0; k < count; ++k) {
122         AccessibilityObject* child = imageChildren[k].get();
123         if (!child->isImageMapLink())
124             continue;
125         
126         if (static_cast<AccessibilityImageMapLink*>(child)->areaElement() == areaElement)
127             return child;
128     }    
129     
130     return 0;
131 }
132     
133 AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page)
134 {
135     if (!gAccessibilityEnabled)
136         return 0;
137
138     // get the focused node in the page
139     Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document();
140     Node* focusedNode = focusedDocument->focusedNode();
141     if (!focusedNode)
142         focusedNode = focusedDocument;
143
144     if (focusedNode->hasTagName(areaTag))
145         return focusedImageMapUIElement(static_cast<HTMLAreaElement*>(focusedNode));
146     
147     RenderObject* focusedNodeRenderer = focusedNode->renderer();
148     if (!focusedNodeRenderer)
149         return 0;
150
151     AccessibilityObject* obj = focusedNodeRenderer->document()->axObjectCache()->getOrCreate(focusedNodeRenderer);
152
153     if (obj->shouldFocusActiveDescendant()) {
154         if (AccessibilityObject* descendant = obj->activeDescendant())
155             obj = descendant;
156     }
157
158     // the HTML element, for example, is focusable but has an AX object that is ignored
159     if (obj->accessibilityIsIgnored())
160         obj = obj->parentObjectUnignored();
161
162     return obj;
163 }
164
165 AccessibilityObject* AXObjectCache::get(Widget* widget)
166 {
167     if (!widget)
168         return 0;
169         
170     AXID axID = m_widgetObjectMapping.get(widget);
171     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
172     if (!axID)
173         return 0;
174     
175     return m_objects.get(axID).get();    
176 }
177     
178 AccessibilityObject* AXObjectCache::get(RenderObject* renderer)
179 {
180     if (!renderer)
181         return 0;
182     
183     AXID axID = m_renderObjectMapping.get(renderer);
184     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
185     if (!axID)
186         return 0;
187
188     return m_objects.get(axID).get();    
189 }
190
191 AccessibilityObject* AXObjectCache::get(Node* node)
192 {
193     if (!node)
194         return 0;
195
196     // Always prefer building the AccessibilityObject from the renderer if there is one.
197     if (node->renderer())
198         return get(node->renderer());
199
200     AXID axID = m_nodeObjectMapping.get(node);
201     ASSERT(!HashTraits<AXID>::isDeletedValue(axID));
202     if (!axID)
203         return 0;
204
205     return m_objects.get(axID).get();
206 }
207
208 // FIXME: This probably belongs on Node.
209 // FIXME: This should take a const char*, but one caller passes nullAtom.
210 bool nodeHasRole(Node* node, const String& role)
211 {
212     if (!node || !node->isElementNode())
213         return false;
214
215     return equalIgnoringCase(static_cast<Element*>(node)->getAttribute(roleAttr), role);
216 }
217
218 static PassRefPtr<AccessibilityObject> createFromRenderer(RenderObject* renderer)
219 {
220     // FIXME: How could renderer->node() ever not be an Element?
221     Node* node = renderer->node();
222
223     // If the node is aria role="list" or the aria role is empty and its a
224     // ul/ol/dl type (it shouldn't be a list if aria says otherwise).
225     if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory"))
226                       || (nodeHasRole(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag)))))
227         return AccessibilityList::create(renderer);
228
229     // aria tables
230     if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid"))
231         return AccessibilityARIAGrid::create(renderer);
232     if (nodeHasRole(node, "row"))
233         return AccessibilityARIAGridRow::create(renderer);
234     if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader"))
235         return AccessibilityARIAGridCell::create(renderer);
236
237 #if ENABLE(VIDEO)
238     // media controls
239     if (node && node->isMediaControlElement())
240         return AccessibilityMediaControl::create(renderer);
241 #endif
242
243     if (renderer->isBoxModelObject()) {
244         RenderBoxModelObject* cssBox = toRenderBoxModelObject(renderer);
245         if (cssBox->isListBox())
246             return AccessibilityListBox::create(toRenderListBox(cssBox));
247         if (cssBox->isMenuList())
248             return AccessibilityMenuList::create(toRenderMenuList(cssBox));
249
250         // standard tables
251         if (cssBox->isTable())
252             return AccessibilityTable::create(toRenderTable(cssBox));
253         if (cssBox->isTableRow())
254             return AccessibilityTableRow::create(toRenderTableRow(cssBox));
255         if (cssBox->isTableCell())
256             return AccessibilityTableCell::create(toRenderTableCell(cssBox));
257
258 #if ENABLE(PROGRESS_TAG)
259         // progress bar
260         if (cssBox->isProgress())
261             return AccessibilityProgressIndicator::create(toRenderProgress(cssBox));
262 #endif
263
264         // input type=range
265         if (cssBox->isSlider())
266             return AccessibilitySlider::create(toRenderSlider(cssBox));
267     }
268
269     return AccessibilityRenderObject::create(renderer);
270 }
271
272 static PassRefPtr<AccessibilityObject> createFromNode(Node* node)
273 {
274     return AccessibilityNodeObject::create(node);
275 }
276
277 AccessibilityObject* AXObjectCache::getOrCreate(Widget* widget)
278 {
279     if (!widget)
280         return 0;
281
282     if (AccessibilityObject* obj = get(widget))
283         return obj;
284     
285     RefPtr<AccessibilityObject> newObj = 0;
286     if (widget->isFrameView())
287         newObj = AccessibilityScrollView::create(static_cast<ScrollView*>(widget));
288     else if (widget->isScrollbar())
289         newObj = AccessibilityScrollbar::create(static_cast<Scrollbar*>(widget));
290         
291     getAXID(newObj.get());
292     
293     m_widgetObjectMapping.set(widget, newObj->axObjectID());
294     m_objects.set(newObj->axObjectID(), newObj);    
295     attachWrapper(newObj.get());
296     return newObj.get();
297 }
298
299 AccessibilityObject* AXObjectCache::getOrCreate(Node* node)
300 {
301     if (!node)
302         return 0;
303
304     if (AccessibilityObject* obj = get(node))
305         return obj;
306
307     if (node->renderer())
308         return getOrCreate(node->renderer());
309
310     // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree.
311     if (!node->parentElement() || !node->parentElement()->isInCanvasSubtree())
312         return 0;
313
314     RefPtr<AccessibilityObject> newObj = createFromNode(node);
315
316     getAXID(newObj.get());
317
318     m_nodeObjectMapping.set(node, newObj->axObjectID());
319     m_objects.set(newObj->axObjectID(), newObj);
320     attachWrapper(newObj.get());
321     return newObj.get();
322 }
323
324 AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer)
325 {
326     if (!renderer)
327         return 0;
328
329     if (AccessibilityObject* obj = get(renderer))
330         return obj;
331
332     RefPtr<AccessibilityObject> newObj = createFromRenderer(renderer);
333
334     getAXID(newObj.get());
335
336     m_renderObjectMapping.set(renderer, newObj->axObjectID());
337     m_objects.set(newObj->axObjectID(), newObj);
338     attachWrapper(newObj.get());
339     return newObj.get();
340 }
341     
342 AccessibilityObject* AXObjectCache::rootObject()
343 {
344     if (!gAccessibilityEnabled)
345         return 0;
346     
347     return getOrCreate(m_document->view());
348 }
349
350 AccessibilityObject* AXObjectCache::rootObjectForFrame(Frame* frame)
351 {
352     if (!gAccessibilityEnabled)
353         return 0;
354
355     if (!frame)
356         return 0;
357     return getOrCreate(frame->view());
358 }    
359     
360 AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role)
361 {
362     RefPtr<AccessibilityObject> obj = 0;
363     
364     // will be filled in...
365     switch (role) {
366     case ListBoxOptionRole:
367         obj = AccessibilityListBoxOption::create();
368         break;
369     case ImageMapLinkRole:
370         obj = AccessibilityImageMapLink::create();
371         break;
372     case ColumnRole:
373         obj = AccessibilityTableColumn::create();
374         break;            
375     case TableHeaderContainerRole:
376         obj = AccessibilityTableHeaderContainer::create();
377         break;   
378     case SliderThumbRole:
379         obj = AccessibilitySliderThumb::create();
380         break;
381     case MenuListPopupRole:
382         obj = AccessibilityMenuListPopup::create();
383         break;
384     case MenuListOptionRole:
385         obj = AccessibilityMenuListOption::create();
386         break;
387     case SpinButtonRole:
388         obj = AccessibilitySpinButton::create();
389         break;
390     case SpinButtonPartRole:
391         obj = AccessibilitySpinButtonPart::create();
392         break;
393     default:
394         obj = 0;
395     }
396     
397     if (obj)
398         getAXID(obj.get());
399     else
400         return 0;
401
402     m_objects.set(obj->axObjectID(), obj);    
403     attachWrapper(obj.get());
404     return obj.get();
405 }
406
407 void AXObjectCache::remove(AXID axID)
408 {
409     if (!axID)
410         return;
411     
412     // first fetch object to operate some cleanup functions on it 
413     AccessibilityObject* obj = m_objects.get(axID).get();
414     if (!obj)
415         return;
416     
417     detachWrapper(obj);
418     obj->detach();
419     removeAXID(obj);
420     
421     // finally remove the object
422     if (!m_objects.take(axID))
423         return;
424     
425     ASSERT(m_objects.size() >= m_idsInUse.size());    
426 }
427     
428 void AXObjectCache::remove(RenderObject* renderer)
429 {
430     if (!renderer)
431         return;
432     
433     AXID axID = m_renderObjectMapping.get(renderer);
434     remove(axID);
435     m_renderObjectMapping.remove(renderer);
436 }
437
438 void AXObjectCache::remove(Node* node)
439 {
440     if (!node)
441         return;
442
443     removeNodeForUse(node);
444
445     // This is all safe even if we didn't have a mapping.
446     AXID axID = m_nodeObjectMapping.get(node);
447     remove(axID);
448     m_nodeObjectMapping.remove(node);
449
450     if (node->renderer()) {
451         remove(node->renderer());
452         return;
453     }
454 }
455
456 void AXObjectCache::remove(Widget* view)
457 {
458     if (!view)
459         return;
460         
461     AXID axID = m_widgetObjectMapping.get(view);
462     remove(axID);
463     m_widgetObjectMapping.remove(view);
464 }
465     
466     
467 #if !PLATFORM(WIN) || OS(WINCE)
468 AXID AXObjectCache::platformGenerateAXID() const
469 {
470     static AXID lastUsedID = 0;
471
472     // Generate a new ID.
473     AXID objID = lastUsedID;
474     do {
475         ++objID;
476     } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID));
477
478     lastUsedID = objID;
479
480     return objID;
481 }
482 #endif
483
484 AXID AXObjectCache::getAXID(AccessibilityObject* obj)
485 {
486     // check for already-assigned ID
487     AXID objID = obj->axObjectID();
488     if (objID) {
489         ASSERT(m_idsInUse.contains(objID));
490         return objID;
491     }
492
493     objID = platformGenerateAXID();
494
495     m_idsInUse.add(objID);
496     obj->setAXObjectID(objID);
497     
498     return objID;
499 }
500
501 void AXObjectCache::removeAXID(AccessibilityObject* object)
502 {
503     if (!object)
504         return;
505     
506     AXID objID = object->axObjectID();
507     if (!objID)
508         return;
509     ASSERT(!HashTraits<AXID>::isDeletedValue(objID));
510     ASSERT(m_idsInUse.contains(objID));
511     object->setAXObjectID(0);
512     m_idsInUse.remove(objID);
513 }
514
515 void AXObjectCache::contentChanged(RenderObject* renderer)
516 {
517     AccessibilityObject* object = getOrCreate(renderer);
518     if (object)
519         object->contentChanged(); 
520 }
521
522 void AXObjectCache::childrenChanged(RenderObject* renderer)
523 {
524     if (!renderer)
525         return;
526  
527     AXID axID = m_renderObjectMapping.get(renderer);
528     if (!axID)
529         return;
530     
531     AccessibilityObject* obj = m_objects.get(axID).get();
532     if (obj)
533         obj->childrenChanged();
534 }
535     
536 void AXObjectCache::notificationPostTimerFired(Timer<AXObjectCache>*)
537 {
538     m_notificationPostTimer.stop();
539
540     unsigned i = 0, count = m_notificationsToPost.size();
541     for (i = 0; i < count; ++i) {
542         AccessibilityObject* obj = m_notificationsToPost[i].first.get();
543 #ifndef NDEBUG
544         // Make sure none of the render views are in the process of being layed out.
545         // Notifications should only be sent after the renderer has finished
546         if (obj->isAccessibilityRenderObject()) {
547             AccessibilityRenderObject* renderObj = static_cast<AccessibilityRenderObject*>(obj);
548             RenderObject* renderer = renderObj->renderer();
549             if (renderer && renderer->view())
550                 ASSERT(!renderer->view()->layoutState());
551         }
552 #endif
553         
554         postPlatformNotification(obj, m_notificationsToPost[i].second);
555     }
556     
557     m_notificationsToPost.clear();
558 }
559     
560 void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, bool postToElement, PostType postType)
561 {
562     // Notifications for text input objects are sent to that object.
563     // All others are sent to the top WebArea.
564     if (!renderer)
565         return;
566     
567     // Get an accessibility object that already exists. One should not be created here
568     // because a render update may be in progress and creating an AX object can re-trigger a layout
569     RefPtr<AccessibilityObject> object = get(renderer);
570     while (!object && renderer) {
571         renderer = renderer->parent();
572         object = get(renderer); 
573     }
574     
575     if (!renderer)
576         return;
577     
578     postNotification(object.get(), renderer->document(), notification, postToElement, postType);
579 }
580
581 void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, bool postToElement, PostType postType)
582 {
583     if (object && !postToElement)
584         object = object->observableObject();
585
586     if (!object && document)
587         object = get(document->renderer());
588
589     if (!object)
590         return;
591
592     if (postType == PostAsynchronously) {
593         m_notificationsToPost.append(std::make_pair(object, notification));
594         if (!m_notificationPostTimer.isActive())
595             m_notificationPostTimer.startOneShot(0);
596     } else
597         postPlatformNotification(object, notification);
598 }
599
600 void AXObjectCache::checkedStateChanged(RenderObject* renderer)
601 {
602     postNotification(renderer, AXObjectCache::AXCheckedStateChanged, true);
603 }
604
605 void AXObjectCache::selectedChildrenChanged(RenderObject* renderer)
606 {
607     // postToElement is false so that you can pass in any child of an element and it will go up the parent tree
608     // to find the container which should send out the notification.
609     postNotification(renderer, AXSelectedChildrenChanged, false);
610 }
611
612 void AXObjectCache::nodeTextChangeNotification(RenderObject* renderer, AXTextChange textChange, unsigned offset, const String& text)
613 {
614     if (!renderer)
615         return;
616
617     // Delegate on the right platform
618     AccessibilityObject* obj = getOrCreate(renderer);
619     nodeTextChangePlatformNotification(obj, textChange, offset, text);
620 }
621
622 void AXObjectCache::frameLoadingEventNotification(Frame* frame, AXLoadingEvent loadingEvent)
623 {
624     if (!frame)
625         return;
626
627     // Delegate on the right platform
628     RenderView* contentRenderer = frame->contentRenderer();
629     if (!contentRenderer)
630         return;
631
632     AccessibilityObject* obj = getOrCreate(contentRenderer);
633     frameLoadingEventPlatformNotification(obj, loadingEvent);
634 }
635
636 void AXObjectCache::handleScrollbarUpdate(ScrollView* view)
637 {
638     if (!view)
639         return;
640     
641     // We don't want to create a scroll view from this method, only update an existing one.
642     AccessibilityObject* scrollViewObject = get(view);
643     if (scrollViewObject)
644         scrollViewObject->updateChildrenIfNecessary();
645 }
646     
647 void AXObjectCache::handleAriaExpandedChange(RenderObject *renderer)
648 {
649     if (!renderer)
650         return;
651     AccessibilityObject* obj = getOrCreate(renderer);
652     if (obj)
653         obj->handleAriaExpandedChanged();
654 }
655     
656 void AXObjectCache::handleActiveDescendantChanged(RenderObject* renderer)
657 {
658     if (!renderer)
659         return;
660     AccessibilityObject* obj = getOrCreate(renderer);
661     if (obj)
662         obj->handleActiveDescendantChanged();
663 }
664
665 void AXObjectCache::handleAriaRoleChanged(RenderObject* renderer)
666 {
667     if (!renderer)
668         return;
669     AccessibilityObject* obj = getOrCreate(renderer);
670     if (obj && obj->isAccessibilityRenderObject())
671         static_cast<AccessibilityRenderObject*>(obj)->updateAccessibilityRole();
672 }
673
674 VisiblePosition AXObjectCache::visiblePositionForTextMarkerData(TextMarkerData& textMarkerData)
675 {
676     if (!isNodeInUse(textMarkerData.node))
677         return VisiblePosition();
678     
679     // FIXME: Accessability should make it clear these are DOM-compliant offsets or store Position objects.
680     VisiblePosition visiblePos = VisiblePosition(createLegacyEditingPosition(textMarkerData.node, textMarkerData.offset), textMarkerData.affinity);
681     Position deepPos = visiblePos.deepEquivalent();
682     if (deepPos.isNull())
683         return VisiblePosition();
684     
685     RenderObject* renderer = deepPos.deprecatedNode()->renderer();
686     if (!renderer)
687         return VisiblePosition();
688     
689     AXObjectCache* cache = renderer->document()->axObjectCache();
690     if (!cache->isIDinUse(textMarkerData.axID))
691         return VisiblePosition();
692     
693     if (deepPos.deprecatedNode() != textMarkerData.node || deepPos.deprecatedEditingOffset() != textMarkerData.offset)
694         return VisiblePosition();
695     
696     return visiblePos;
697 }
698
699 void AXObjectCache::textMarkerDataForVisiblePosition(TextMarkerData& textMarkerData, const VisiblePosition& visiblePos)
700 {
701     // This memory must be bzero'd so instances of TextMarkerData can be tested for byte-equivalence.
702     // This also allows callers to check for failure by looking at textMarkerData upon return.
703     memset(&textMarkerData, 0, sizeof(TextMarkerData));
704     
705     if (visiblePos.isNull())
706         return;
707     
708     Position deepPos = visiblePos.deepEquivalent();
709     Node* domNode = deepPos.deprecatedNode();
710     ASSERT(domNode);
711     if (!domNode)
712         return;
713     
714     if (domNode->isHTMLElement()) {
715         HTMLInputElement* inputElement = domNode->toInputElement();
716         if (inputElement && inputElement->isPasswordField())
717             return;
718     }
719     
720     // locate the renderer, which must exist for a visible dom node
721     RenderObject* renderer = domNode->renderer();
722     ASSERT(renderer);
723     
724     // find or create an accessibility object for this renderer
725     AXObjectCache* cache = renderer->document()->axObjectCache();
726     RefPtr<AccessibilityObject> obj = cache->getOrCreate(renderer);
727     
728     textMarkerData.axID = obj.get()->axObjectID();
729     textMarkerData.node = domNode;
730     textMarkerData.offset = deepPos.deprecatedEditingOffset();
731     textMarkerData.affinity = visiblePos.affinity();   
732     
733     cache->setNodeInUse(domNode);
734 }
735
736 const Element* AXObjectCache::rootAXEditableElement(const Node* node)
737 {
738     const Element* result = node->rootEditableElement();
739     const Element* element = node->isElementNode() ? toElement(node) : node->parentElement();
740
741     for (; element; element = element->parentElement()) {
742         if (nodeIsTextControl(element))
743             result = element;
744     }
745
746     return result;
747 }
748
749 bool AXObjectCache::nodeIsTextControl(const Node* node)
750 {
751     if (!node)
752         return false;
753
754     const AccessibilityObject* axObject = getOrCreate(node->renderer());
755     return axObject && axObject->isTextControl();
756 }
757
758 } // namespace WebCore
759
760 #endif // HAVE(ACCESSIBILITY)