AX: [ATK] Implement support for new AtkRole types for MathML
[WebKit-https.git] / Source / WebCore / accessibility / atk / WebKitAccessibleWrapperAtk.cpp
1 /*
2  * Copyright (C) 2008 Nuanti Ltd.
3  * Copyright (C) 2009 Jan Alonzo
4  * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
5  * Copyright (C) 2013 Samsung Electronics
6  *
7  * Portions from Mozilla a11y, copyright as follows:
8  *
9  * The Original Code is mozilla.org code.
10  *
11  * The Initial Developer of the Original Code is
12  * Sun Microsystems, Inc.
13  * Portions created by the Initial Developer are Copyright (C) 2002
14  * the Initial Developer. All Rights Reserved.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Library General Public
18  * License as published by the Free Software Foundation; either
19  * version 2 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Library General Public License for more details.
25  *
26  * You should have received a copy of the GNU Library General Public License
27  * along with this library; see the file COPYING.LIB.  If not, write to
28  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
29  * Boston, MA 02110-1301, USA.
30  */
31
32 #include "config.h"
33 #include "WebKitAccessibleWrapperAtk.h"
34
35 #if HAVE(ACCESSIBILITY)
36
37 #include "AXObjectCache.h"
38 #include "AccessibilityList.h"
39 #include "AccessibilityListBoxOption.h"
40 #include "AccessibilityTable.h"
41 #include "Document.h"
42 #include "Frame.h"
43 #include "FrameView.h"
44 #include "HTMLNames.h"
45 #include "HTMLTableElement.h"
46 #include "HostWindow.h"
47 #include "RenderObject.h"
48 #include "Settings.h"
49 #include "TextIterator.h"
50 #include "VisibleUnits.h"
51 #include "WebKitAccessibleHyperlink.h"
52 #include "WebKitAccessibleInterfaceAction.h"
53 #include "WebKitAccessibleInterfaceComponent.h"
54 #include "WebKitAccessibleInterfaceDocument.h"
55 #include "WebKitAccessibleInterfaceEditableText.h"
56 #include "WebKitAccessibleInterfaceHyperlinkImpl.h"
57 #include "WebKitAccessibleInterfaceHypertext.h"
58 #include "WebKitAccessibleInterfaceImage.h"
59 #include "WebKitAccessibleInterfaceSelection.h"
60 #include "WebKitAccessibleInterfaceTable.h"
61 #include "WebKitAccessibleInterfaceTableCell.h"
62 #include "WebKitAccessibleInterfaceText.h"
63 #include "WebKitAccessibleInterfaceValue.h"
64 #include "WebKitAccessibleUtil.h"
65 #include "htmlediting.h"
66 #include <glib/gprintf.h>
67 #include <wtf/text/CString.h>
68
69 using namespace WebCore;
70
71 struct _WebKitAccessiblePrivate {
72     // Cached data for AtkObject.
73     CString accessibleName;
74     CString accessibleDescription;
75
76     // Cached data for AtkAction.
77     CString actionName;
78     CString actionKeyBinding;
79
80     // Cached data for AtkDocument.
81     CString documentLocale;
82     CString documentType;
83     CString documentEncoding;
84     CString documentURI;
85
86     // Cached data for AtkImage.
87     CString imageDescription;
88 };
89
90 #define WEBKIT_ACCESSIBLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessiblePrivate))
91
92 static AccessibilityObject* fallbackObject()
93 {
94     static AccessibilityObject* object = &AccessibilityListBoxOption::create().leakRef();
95     return object;
96 }
97
98 static AccessibilityObject* core(AtkObject* object)
99 {
100     if (!WEBKIT_IS_ACCESSIBLE(object))
101         return 0;
102
103     return webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(object));
104 }
105
106 static const gchar* webkitAccessibleGetName(AtkObject* object)
107 {
108     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
109     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
110
111     AccessibilityObject* coreObject = core(object);
112     if (coreObject->isFieldset()) {
113         AccessibilityObject* label = coreObject->titleUIElement();
114         if (label) {
115             AtkObject* atkObject = label->wrapper();
116             if (ATK_IS_TEXT(atkObject))
117                 return atk_text_get_text(ATK_TEXT(atkObject), 0, -1);
118         }
119     }
120
121     if (coreObject->isControl()) {
122         AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
123         if (label) {
124             AtkObject* atkObject = label->wrapper();
125             if (ATK_IS_TEXT(atkObject))
126                 return atk_text_get_text(ATK_TEXT(atkObject), 0, -1);
127         }
128
129         // Try text under the node.
130         String textUnder = coreObject->textUnderElement();
131         if (textUnder.length())
132             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, textUnder);
133     }
134
135     if (coreObject->isImage() || coreObject->isInputImage() || coreObject->isImageMap() || coreObject->isImageMapLink()) {
136         Node* node = coreObject->node();
137         if (is<HTMLElement>(node)) {
138             // Get the attribute rather than altText String so as not to fall back on title.
139             const AtomicString& alt = downcast<HTMLElement>(*node).getAttribute(HTMLNames::altAttr);
140             if (!alt.isEmpty())
141                 return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, alt);
142         }
143     }
144
145     // Fallback for the webArea object: just return the document's title.
146     if (coreObject->isWebArea()) {
147         Document* document = coreObject->document();
148         if (document)
149             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, document->title());
150     }
151
152     // Nothing worked so far, try with the AccessibilityObject's
153     // title() before going ahead with stringValue().
154     String axTitle = accessibilityTitle(coreObject);
155     if (!axTitle.isEmpty())
156         return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, axTitle);
157
158     return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, coreObject->stringValue());
159 }
160
161 static const gchar* webkitAccessibleGetDescription(AtkObject* object)
162 {
163     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
164     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
165
166     AccessibilityObject* coreObject = core(object);
167     Node* node = nullptr;
168     if (coreObject->isAccessibilityRenderObject())
169         node = coreObject->node();
170     if (!is<HTMLElement>(node) || coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isImage())
171         return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject));
172
173     // atk_table_get_summary returns an AtkObject. We have no summary object, so expose summary here.
174     if (coreObject->roleValue() == TableRole) {
175         const AtomicString& summary = downcast<HTMLTableElement>(*node).summary();
176         if (!summary.isEmpty())
177             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, summary);
178     }
179
180     // The title attribute should be reliably available as the object's descripton.
181     // We do not want to fall back on other attributes in its absence. See bug 25524.
182     String title = downcast<HTMLElement>(*node).title();
183     if (!title.isEmpty())
184         return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, title);
185
186     return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, accessibilityDescription(coreObject));
187 }
188
189 static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType)
190 {
191     int count = atk_relation_set_get_n_relations(relationSet);
192     for (int i = 0; i < count; i++) {
193         AtkRelation* relation = atk_relation_set_get_relation(relationSet, i);
194         if (atk_relation_get_relation_type(relation) == relationType) {
195             atk_relation_set_remove(relationSet, relation);
196             break;
197         }
198     }
199 }
200
201 static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
202 {
203     if (coreObject->isFieldset()) {
204         AccessibilityObject* label = coreObject->titleUIElement();
205         if (label) {
206             removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
207             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
208         }
209         return;
210     }
211
212     if (coreObject->roleValue() == LegendRole) {
213         for (AccessibilityObject* parent = coreObject->parentObjectUnignored(); parent; parent = parent->parentObjectUnignored()) {
214             if (parent->isFieldset()) {
215                 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, parent->wrapper());
216                 break;
217             }
218         }
219         return;
220     }
221
222     if (coreObject->isControl()) {
223         AccessibilityObject* label = coreObject->correspondingLabelForControlElement();
224         if (label) {
225             removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
226             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
227         }
228     } else {
229         AccessibilityObject* control = coreObject->correspondingControlForLabelElement();
230         if (control)
231             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
232     }
233
234     // Check whether object supports aria-flowto
235     if (coreObject->supportsARIAFlowTo()) {
236         removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
237         AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
238         coreObject->ariaFlowToElements(ariaFlowToElements);
239         for (const auto& accessibilityObject : ariaFlowToElements)
240             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, accessibilityObject->wrapper());
241     }
242
243     // Check whether object supports aria-describedby. It provides an additional information for the user.
244     if (coreObject->supportsARIADescribedBy()) {
245         removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIBED_BY);
246         AccessibilityObject::AccessibilityChildrenVector ariaDescribedByElements;
247         coreObject->ariaDescribedByElements(ariaDescribedByElements);
248         for (const auto& accessibilityObject : ariaDescribedByElements)
249             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY, accessibilityObject->wrapper());
250     }
251
252     // Check whether object supports aria-controls. It provides information about elements that are controlled by the current object.
253     if (coreObject->supportsARIAControls()) {
254         removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLER_FOR);
255         AccessibilityObject::AccessibilityChildrenVector ariaControls;
256         coreObject->ariaControlsElements(ariaControls);
257         for (const auto& accessibilityObject : ariaControls)
258             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLER_FOR, accessibilityObject->wrapper());
259     }
260 }
261
262 static gpointer webkitAccessibleParentClass = 0;
263
264 static bool isRootObject(AccessibilityObject* coreObject)
265 {
266     // The root accessible object in WebCore is always an object with
267     // the ScrolledArea role with one child with the WebArea role.
268     if (!coreObject || !coreObject->isScrollView())
269         return false;
270
271     AccessibilityObject* firstChild = coreObject->firstChild();
272     if (!firstChild || !firstChild->isWebArea())
273         return false;
274
275     return true;
276 }
277
278 static AtkObject* atkParentOfRootObject(AtkObject* object)
279 {
280     AccessibilityObject* coreObject = core(object);
281     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
282
283     // The top level object claims to not have a parent. This makes it
284     // impossible for assistive technologies to ascend the accessible
285     // hierarchy all the way to the application. (Bug 30489)
286     if (!coreParent && isRootObject(coreObject)) {
287         Document* document = coreObject->document();
288         if (!document)
289             return 0;
290     }
291
292     if (!coreParent)
293         return 0;
294
295     return coreParent->wrapper();
296 }
297
298 static AtkObject* webkitAccessibleGetParent(AtkObject* object)
299 {
300     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
301     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
302
303     // Check first if the parent has been already set.
304     AtkObject* accessibleParent = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->get_parent(object);
305     if (accessibleParent)
306         return accessibleParent;
307
308     // Parent not set yet, so try to find it in the hierarchy.
309     AccessibilityObject* coreObject = core(object);
310     if (!coreObject)
311         return 0;
312
313     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
314
315     if (!coreParent && isRootObject(coreObject))
316         return atkParentOfRootObject(object);
317
318     if (!coreParent)
319         return 0;
320
321     // We don't expose table rows to Assistive technologies, but we
322     // need to have them anyway in the hierarchy from WebCore to
323     // properly perform coordinates calculations when requested.
324     if (coreParent->isTableRow() && coreObject->isTableCell())
325         coreParent = coreParent->parentObjectUnignored();
326
327     return coreParent->wrapper();
328 }
329
330 static gint webkitAccessibleGetNChildren(AtkObject* object)
331 {
332     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
333     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
334
335     AccessibilityObject* coreObject = core(object);
336
337     return coreObject->children().size();
338 }
339
340 static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
341 {
342     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
343     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
344
345     if (index < 0)
346         return 0;
347
348     AccessibilityObject* coreObject = core(object);
349     AccessibilityObject* coreChild = 0;
350
351     const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
352     if (static_cast<size_t>(index) >= children.size())
353         return 0;
354     coreChild = children.at(index).get();
355
356     if (!coreChild)
357         return 0;
358
359     AtkObject* child = coreChild->wrapper();
360     atk_object_set_parent(child, object);
361     g_object_ref(child);
362
363     return child;
364 }
365
366 static gint webkitAccessibleGetIndexInParent(AtkObject* object)
367 {
368     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), -1);
369     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), -1);
370
371     AccessibilityObject* coreObject = core(object);
372     AccessibilityObject* parent = coreObject->parentObjectUnignored();
373
374     if (!parent && isRootObject(coreObject)) {
375         AtkObject* atkParent = atkParentOfRootObject(object);
376         if (!atkParent)
377             return -1;
378
379         unsigned count = atk_object_get_n_accessible_children(atkParent);
380         for (unsigned i = 0; i < count; ++i) {
381             AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
382             bool childIsObject = child == object;
383             g_object_unref(child);
384             if (childIsObject)
385                 return i;
386         }
387     }
388
389     if (!parent)
390         return -1;
391
392     size_t index = parent->children().find(coreObject);
393     return (index == WTF::notFound) ? -1 : index;
394 }
395
396 static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
397 {
398     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
399     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
400
401     AtkAttributeSet* attributeSet = 0;
402 #if PLATFORM(GTK)
403     attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
404 #elif PLATFORM(EFL)
405     attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitEfl");
406 #endif
407
408     AccessibilityObject* coreObject = core(object);
409     if (!coreObject)
410         return attributeSet;
411
412     // Hack needed for WebKit2 tests because obtaining an element by its ID
413     // cannot be done from the UIProcess. Assistive technologies have no need
414     // for this information.
415     Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
416     if (element) {
417         String id = element->getIdAttribute().string();
418         if (!id.isEmpty())
419             attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
420     }
421
422     int headingLevel = coreObject->headingLevel();
423     if (headingLevel) {
424         String value = String::number(headingLevel);
425         attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
426     }
427
428     if (coreObject->roleValue() == MathElementRole) {
429         if (coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PreSubscript))
430             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
431         else if (coreObject->isMathMultiscriptObject(PostSuperscript) || coreObject->isMathMultiscriptObject(PostSubscript))
432             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
433     }
434
435     // Set the 'layout-guess' attribute to help Assistive
436     // Technologies know when an exposed table is not data table.
437     if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposableThroughAccessibility() && !coreObject->isDataTable())
438         attributeSet = addToAtkAttributeSet(attributeSet, "layout-guess", "true");
439
440     String placeholder = coreObject->placeholderValue();
441     if (!placeholder.isEmpty())
442         attributeSet = addToAtkAttributeSet(attributeSet, "placeholder-text", placeholder.utf8().data());
443
444     if (coreObject->ariaHasPopup())
445         attributeSet = addToAtkAttributeSet(attributeSet, "haspopup", "true");
446
447     AccessibilitySortDirection sortDirection = coreObject->sortDirection();
448     if (sortDirection != SortDirectionNone) {
449         // WAI-ARIA spec says to translate the value as is from the attribute.
450         const AtomicString& sortAttribute = coreObject->getAttribute(HTMLNames::aria_sortAttr);
451         attributeSet = addToAtkAttributeSet(attributeSet, "sort", sortAttribute.string().utf8().data());
452     }
453
454     if (coreObject->supportsARIAPosInSet())
455         attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->ariaPosInSet()).utf8().data());
456
457     if (coreObject->supportsARIASetSize())
458         attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->ariaSetSize()).utf8().data());
459
460     // Landmarks will be exposed with xml-roles object attributes, with the exception
461     // of LandmarkApplicationRole, which will be exposed with ATK_ROLE_EMBEDDED.
462     AccessibilityRole role = coreObject->roleValue();
463     switch (role) {
464     case LandmarkBannerRole:
465         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "banner");
466         break;
467     case LandmarkComplementaryRole:
468         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "complementary");
469         break;
470     case LandmarkContentInfoRole:
471         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "contentinfo");
472         break;
473     case LandmarkMainRole:
474         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "main");
475         break;
476     case LandmarkNavigationRole:
477         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "navigation");
478         break;
479     case LandmarkSearchRole:
480         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", "search");
481         break;
482     default:
483         break;
484     }
485
486     return attributeSet;
487 }
488
489 static AtkRole atkRole(AccessibilityObject* coreObject)
490 {
491     AccessibilityRole role = coreObject->roleValue();
492     switch (role) {
493     case ApplicationAlertDialogRole:
494     case ApplicationAlertRole:
495         return ATK_ROLE_ALERT;
496     case ApplicationDialogRole:
497         return ATK_ROLE_DIALOG;
498     case ApplicationStatusRole:
499         return ATK_ROLE_STATUSBAR;
500     case UnknownRole:
501         return ATK_ROLE_UNKNOWN;
502     case AudioRole:
503 #if ATK_CHECK_VERSION(2, 11, 3)
504         return ATK_ROLE_AUDIO;
505 #endif
506     case VideoRole:
507 #if ATK_CHECK_VERSION(2, 11, 3)
508         return ATK_ROLE_VIDEO;
509 #endif
510         return ATK_ROLE_EMBEDDED;
511     case ButtonRole:
512         return ATK_ROLE_PUSH_BUTTON;
513     case ToggleButtonRole:
514         return ATK_ROLE_TOGGLE_BUTTON;
515     case RadioButtonRole:
516         return ATK_ROLE_RADIO_BUTTON;
517     case CheckBoxRole:
518         return ATK_ROLE_CHECK_BOX;
519     case SliderRole:
520         return ATK_ROLE_SLIDER;
521     case TabGroupRole:
522     case TabListRole:
523         return ATK_ROLE_PAGE_TAB_LIST;
524     case TextFieldRole:
525     case TextAreaRole:
526         return ATK_ROLE_ENTRY;
527     case StaticTextRole:
528         return ATK_ROLE_TEXT;
529     case OutlineRole:
530     case TreeRole:
531         return ATK_ROLE_TREE;
532     case TreeItemRole:
533         return ATK_ROLE_TREE_ITEM;
534     case MenuBarRole:
535         return ATK_ROLE_MENU_BAR;
536     case MenuListPopupRole:
537     case MenuRole:
538         return ATK_ROLE_MENU;
539     case MenuListOptionRole:
540     case MenuItemRole:
541         return ATK_ROLE_MENU_ITEM;
542     case MenuItemCheckboxRole:
543         return ATK_ROLE_CHECK_MENU_ITEM;
544     case MenuItemRadioRole:
545         return ATK_ROLE_RADIO_MENU_ITEM;
546     case ColumnRole:
547         // return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
548         return ATK_ROLE_UNKNOWN; // Matches Mozilla
549     case RowRole:
550         return ATK_ROLE_TABLE_ROW;
551     case ToolbarRole:
552         return ATK_ROLE_TOOL_BAR;
553     case BusyIndicatorRole:
554         return ATK_ROLE_PROGRESS_BAR; // Is this right?
555     case ProgressIndicatorRole:
556         // return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp
557         return ATK_ROLE_PROGRESS_BAR;
558     case WindowRole:
559         return ATK_ROLE_WINDOW;
560     case PopUpButtonRole:
561     case ComboBoxRole:
562         return ATK_ROLE_COMBO_BOX;
563     case SplitGroupRole:
564         return ATK_ROLE_SPLIT_PANE;
565     case SplitterRole:
566         return ATK_ROLE_SEPARATOR;
567     case ColorWellRole:
568         return ATK_ROLE_COLOR_CHOOSER;
569     case ListRole:
570         return ATK_ROLE_LIST;
571     case ScrollBarRole:
572         return ATK_ROLE_SCROLL_BAR;
573     case ScrollAreaRole:
574         return ATK_ROLE_SCROLL_PANE;
575     case GridRole: // Is this right?
576     case TableRole:
577         return ATK_ROLE_TABLE;
578     case ApplicationRole:
579         return ATK_ROLE_APPLICATION;
580     case DocumentRegionRole:
581     case GroupRole:
582     case RadioGroupRole:
583     case TabPanelRole:
584         return ATK_ROLE_PANEL;
585     case RowHeaderRole:
586         return ATK_ROLE_ROW_HEADER;
587     case ColumnHeaderRole:
588         return ATK_ROLE_COLUMN_HEADER;
589     case CaptionRole:
590         return ATK_ROLE_CAPTION;
591     case CellRole:
592         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
593     case LinkRole:
594     case WebCoreLinkRole:
595     case ImageMapLinkRole:
596         return ATK_ROLE_LINK;
597     case ImageMapRole:
598         return ATK_ROLE_IMAGE_MAP;
599     case ImageRole:
600         return ATK_ROLE_IMAGE;
601     case ListMarkerRole:
602         return ATK_ROLE_TEXT;
603     case DocumentArticleRole:
604 #if ATK_CHECK_VERSION(2, 11, 3)
605         return ATK_ROLE_ARTICLE;
606 #endif
607     case DocumentRole:
608         return ATK_ROLE_DOCUMENT_FRAME;
609     case DocumentNoteRole:
610         return ATK_ROLE_COMMENT;
611     case HeadingRole:
612         return ATK_ROLE_HEADING;
613     case ListBoxRole:
614         return ATK_ROLE_LIST_BOX;
615     case ListItemRole:
616         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
617     case ListBoxOptionRole:
618         return ATK_ROLE_LIST_ITEM;
619     case ParagraphRole:
620         return ATK_ROLE_PARAGRAPH;
621     case LabelRole:
622     case LegendRole:
623         return ATK_ROLE_LABEL;
624     case BlockquoteRole:
625 #if ATK_CHECK_VERSION(2, 11, 3)
626         return ATK_ROLE_BLOCK_QUOTE;
627 #endif
628     case DivRole:
629         return ATK_ROLE_SECTION;
630     case FooterRole:
631         return ATK_ROLE_FOOTER;
632     case FormRole:
633         return ATK_ROLE_FORM;
634     case CanvasRole:
635         return ATK_ROLE_CANVAS;
636     case HorizontalRuleRole:
637         return ATK_ROLE_SEPARATOR;
638     case SpinButtonRole:
639         return ATK_ROLE_SPIN_BUTTON;
640     case TabRole:
641         return ATK_ROLE_PAGE_TAB;
642     case UserInterfaceTooltipRole:
643         return ATK_ROLE_TOOL_TIP;
644     case WebAreaRole:
645         return ATK_ROLE_DOCUMENT_WEB;
646     case LandmarkApplicationRole:
647         return ATK_ROLE_EMBEDDED;
648 #if ATK_CHECK_VERSION(2, 11, 3)
649     case ApplicationLogRole:
650         return ATK_ROLE_LOG;
651     case ApplicationMarqueeRole:
652         return ATK_ROLE_MARQUEE;
653     case ApplicationTimerRole:
654         return ATK_ROLE_TIMER;
655     case DefinitionRole:
656         return ATK_ROLE_DEFINITION;
657     case DocumentMathRole:
658         return ATK_ROLE_MATH;
659     case MathElementRole:
660         if (coreObject->isMathRow())
661             return ATK_ROLE_PANEL;
662         if (coreObject->isMathTable())
663             return ATK_ROLE_TABLE;
664         if (coreObject->isMathTableRow())
665             return ATK_ROLE_TABLE_ROW;
666         if (coreObject->isMathTableCell())
667             return ATK_ROLE_TABLE_CELL;
668         if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
669             return ATK_ROLE_SECTION;
670 #if ATK_CHECK_VERSION(2, 15, 4)
671         if (coreObject->isMathFraction())
672             return ATK_ROLE_MATH_FRACTION;
673         if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
674             return ATK_ROLE_MATH_ROOT;
675         if (coreObject->isMathScriptObject(Subscript)
676             || coreObject->isMathMultiscriptObject(PreSubscript) || coreObject->isMathMultiscriptObject(PostSubscript))
677             return ATK_ROLE_SUBSCRIPT;
678         if (coreObject->isMathScriptObject(Superscript)
679             || coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PostSuperscript))
680             return ATK_ROLE_SUPERSCRIPT;
681 #endif
682 #if ATK_CHECK_VERSION(2, 15, 2)
683         if (coreObject->isMathToken())
684             return ATK_ROLE_STATIC;
685 #endif
686         return ATK_ROLE_UNKNOWN;
687     case LandmarkBannerRole:
688     case LandmarkComplementaryRole:
689     case LandmarkContentInfoRole:
690     case LandmarkMainRole:
691     case LandmarkNavigationRole:
692     case LandmarkSearchRole:
693         return ATK_ROLE_LANDMARK;
694 #endif
695 #if ATK_CHECK_VERSION(2, 11, 4)
696     case DescriptionListRole:
697         return ATK_ROLE_DESCRIPTION_LIST;
698     case DescriptionListTermRole:
699         return ATK_ROLE_DESCRIPTION_TERM;
700     case DescriptionListDetailRole:
701         return ATK_ROLE_DESCRIPTION_VALUE;
702 #endif
703 #if ATK_CHECK_VERSION(2, 15, 2)
704     case InlineRole:
705         return ATK_ROLE_STATIC;
706 #endif
707     default:
708         return ATK_ROLE_UNKNOWN;
709     }
710 }
711
712 static AtkRole webkitAccessibleGetRole(AtkObject* object)
713 {
714     // ATK_ROLE_UNKNOWN should only be applied in cases where there is a valid
715     // WebCore accessible object for which the platform role mapping is unknown.
716     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), ATK_ROLE_INVALID);
717     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), ATK_ROLE_INVALID);
718
719     AccessibilityObject* coreObject = core(object);
720
721     if (!coreObject)
722         return ATK_ROLE_INVALID;
723
724     // Note: Why doesn't WebCore have a password field for this
725     if (coreObject->isPasswordField())
726         return ATK_ROLE_PASSWORD_TEXT;
727
728     return atkRole(coreObject);
729 }
730
731 static bool isTextWithCaret(AccessibilityObject* coreObject)
732 {
733     if (!coreObject || !coreObject->isAccessibilityRenderObject())
734         return false;
735
736     Document* document = coreObject->document();
737     if (!document)
738         return false;
739
740     Frame* frame = document->frame();
741     if (!frame)
742         return false;
743
744     if (!frame->settings().caretBrowsingEnabled())
745         return false;
746
747     // Check text objects and paragraphs only.
748     AtkObject* axObject = coreObject->wrapper();
749     AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
750     if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
751         return false;
752
753     // Finally, check whether the caret is set in the current object.
754     VisibleSelection selection = coreObject->selection();
755     if (!selection.isCaret())
756         return false;
757
758     return selectionBelongsToObject(coreObject, selection);
759 }
760
761 static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
762 {
763     AccessibilityObject* parent = coreObject->parentObject();
764     bool isListBoxOption = parent && parent->isListBox();
765
766     // Please keep the state list in alphabetical order
767     if (isListBoxOption && coreObject->isSelectedOptionActive())
768         atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
769
770     if (coreObject->isChecked())
771         atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
772
773     // FIXME: isReadOnly does not seem to do the right thing for
774     // controls, so check explicitly for them. In addition, because
775     // isReadOnly is false for listBoxOptions, we need to add one
776     // more check so that we do not present them as being "editable".
777     if ((!coreObject->isReadOnly()
778         || (coreObject->isControl() && coreObject->canSetValueAttribute()))
779         && !isListBoxOption)
780         atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
781
782     // FIXME: Put both ENABLED and SENSITIVE together here for now
783     if (coreObject->isEnabled()) {
784         atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
785         atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
786     }
787
788     if (coreObject->canSetExpandedAttribute())
789         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
790
791     if (coreObject->isExpanded())
792         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
793
794     if (coreObject->canSetFocusAttribute())
795         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
796
797     if (coreObject->isFocused() || isTextWithCaret(coreObject))
798         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
799
800     if (coreObject->orientation() == AccessibilityOrientationHorizontal)
801         atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);
802     else if (coreObject->orientation() == AccessibilityOrientationVertical)
803         atk_state_set_add_state(stateSet, ATK_STATE_VERTICAL);
804
805     if (coreObject->isIndeterminate())
806         atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
807
808     if (coreObject->isCheckboxOrRadio() || coreObject->isMenuItem()) {
809         if (coreObject->checkboxOrRadioValue() == ButtonStateMixed)
810             atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
811     }
812
813     if (coreObject->invalidStatus() != "false")
814         atk_state_set_add_state(stateSet, ATK_STATE_INVALID_ENTRY);
815
816     if (coreObject->isMultiSelectable())
817         atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
818
819     // TODO: ATK_STATE_OPAQUE
820
821     if (coreObject->isPressed())
822         atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
823
824     if (coreObject->isRequired())
825         atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
826
827     // TODO: ATK_STATE_SELECTABLE_TEXT
828
829     if (coreObject->canSetSelectedAttribute()) {
830         atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
831         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
832         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on
833         // the former.
834         if (isListBoxOption)
835             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
836     }
837
838     if (coreObject->isSelected()) {
839         atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
840         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
841         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
842         // former.
843         if (isListBoxOption)
844             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
845     }
846
847     // FIXME: Group both SHOWING and VISIBLE here for now
848     // Not sure how to handle this in WebKit, see bug
849     // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
850     // issues with SHOWING vs VISIBLE.
851     if (!coreObject->isOffScreen()) {
852         atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
853         atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
854     }
855
856     // Mutually exclusive, so we group these two
857     if (coreObject->roleValue() == TextFieldRole)
858         atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
859     else if (coreObject->roleValue() == TextAreaRole)
860         atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
861
862     // TODO: ATK_STATE_SENSITIVE
863
864     if (coreObject->isVisited())
865         atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
866 }
867
868 static AtkStateSet* webkitAccessibleRefStateSet(AtkObject* object)
869 {
870     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
871
872     AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_state_set(object);
873     AccessibilityObject* coreObject = core(object);
874
875     // Make sure the layout is updated to really know whether the object
876     // is defunct or not, so we can return the proper state.
877     coreObject->updateBackingStore();
878
879     if (coreObject == fallbackObject()) {
880         atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
881         return stateSet;
882     }
883
884     // Text objects must be focusable.
885     AtkRole role = atk_object_get_role(object);
886     if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
887         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
888
889     setAtkStateSetFromCoreObject(coreObject, stateSet);
890     return stateSet;
891 }
892
893 static AtkRelationSet* webkitAccessibleRefRelationSet(AtkObject* object)
894 {
895     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
896     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
897
898     AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_relation_set(object);
899     AccessibilityObject* coreObject = core(object);
900
901     setAtkRelationSetFromCoreObject(coreObject, relationSet);
902
903     return relationSet;
904 }
905
906 static void webkitAccessibleInit(AtkObject* object, gpointer data)
907 {
908     if (ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize)
909         ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize(object, data);
910
911     WebKitAccessible* accessible = WEBKIT_ACCESSIBLE(object);
912     accessible->m_object = reinterpret_cast<AccessibilityObject*>(data);
913     accessible->priv = WEBKIT_ACCESSIBLE_GET_PRIVATE(accessible);
914 }
915
916 static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
917 {
918     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
919     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
920
921     AccessibilityObject* coreObject = core(object);
922     if (!coreObject)
923         return 0;
924
925     if (ATK_IS_DOCUMENT(object)) {
926         // TODO: Should we fall back on lang xml:lang when the following comes up empty?
927         String language = coreObject->language();
928         if (!language.isEmpty())
929             return cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, language);
930
931     } else if (ATK_IS_TEXT(object)) {
932         const gchar* locale = 0;
933
934         AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
935         for (AtkAttributeSet* attributes = textAttributes; attributes; attributes = attributes->next) {
936             AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
937             if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
938                 locale = cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, String::fromUTF8(atkAttribute->value));
939                 break;
940             }
941         }
942         atk_attribute_set_free(textAttributes);
943
944         return locale;
945     }
946
947     return 0;
948 }
949
950 static void webkitAccessibleFinalize(GObject* object)
951 {
952     G_OBJECT_CLASS(webkitAccessibleParentClass)->finalize(object);
953 }
954
955 static void webkitAccessibleClassInit(AtkObjectClass* klass)
956 {
957     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
958
959     webkitAccessibleParentClass = g_type_class_peek_parent(klass);
960
961     gobjectClass->finalize = webkitAccessibleFinalize;
962
963     klass->initialize = webkitAccessibleInit;
964     klass->get_name = webkitAccessibleGetName;
965     klass->get_description = webkitAccessibleGetDescription;
966     klass->get_parent = webkitAccessibleGetParent;
967     klass->get_n_children = webkitAccessibleGetNChildren;
968     klass->ref_child = webkitAccessibleRefChild;
969     klass->get_role = webkitAccessibleGetRole;
970     klass->ref_state_set = webkitAccessibleRefStateSet;
971     klass->get_index_in_parent = webkitAccessibleGetIndexInParent;
972     klass->get_attributes = webkitAccessibleGetAttributes;
973     klass->ref_relation_set = webkitAccessibleRefRelationSet;
974     klass->get_object_locale = webkitAccessibleGetObjectLocale;
975
976     g_type_class_add_private(klass, sizeof(WebKitAccessiblePrivate));
977 }
978
979 GType
980 webkitAccessibleGetType(void)
981 {
982     static volatile gsize typeVolatile = 0;
983
984     if (g_once_init_enter(&typeVolatile)) {
985         static const GTypeInfo tinfo = {
986             sizeof(WebKitAccessibleClass),
987             (GBaseInitFunc) 0,
988             (GBaseFinalizeFunc) 0,
989             (GClassInitFunc) webkitAccessibleClassInit,
990             (GClassFinalizeFunc) 0,
991             0, /* class data */
992             sizeof(WebKitAccessible), /* instance size */
993             0, /* nb preallocs */
994             (GInstanceInitFunc) 0,
995             0 /* value table */
996         };
997
998         GType type = g_type_register_static(ATK_TYPE_OBJECT, "WebKitAccessible", &tinfo, GTypeFlags(0));
999         g_once_init_leave(&typeVolatile, type);
1000     }
1001
1002     return typeVolatile;
1003 }
1004
1005 static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
1006     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleActionInterfaceInit), 0, 0},
1007     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleSelectionInterfaceInit), 0, 0},
1008     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleEditableTextInterfaceInit), 0, 0},
1009     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTextInterfaceInit), 0, 0},
1010     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleComponentInterfaceInit), 0, 0},
1011     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleImageInterfaceInit), 0, 0},
1012     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableInterfaceInit), 0, 0},
1013 #if ATK_CHECK_VERSION(2,11,90)
1014     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableCellInterfaceInit), 0, 0},
1015 #endif
1016     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHypertextInterfaceInit), 0, 0},
1017     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHyperlinkImplInterfaceInit), 0, 0},
1018     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleDocumentInterfaceInit), 0, 0},
1019     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleValueInterfaceInit), 0, 0}
1020 };
1021
1022 enum WAIType {
1023     WAIAction,
1024     WAISelection,
1025     WAIEditableText,
1026     WAIText,
1027     WAIComponent,
1028     WAIImage,
1029     WAITable,
1030 #if ATK_CHECK_VERSION(2,11,90)
1031     WAITableCell,
1032 #endif
1033     WAIHypertext,
1034     WAIHyperlink,
1035     WAIDocument,
1036     WAIValue,
1037 };
1038
1039 static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
1040 {
1041     switch (type) {
1042     case WAIAction:
1043         return ATK_TYPE_ACTION;
1044     case WAISelection:
1045         return ATK_TYPE_SELECTION;
1046     case WAIEditableText:
1047         return ATK_TYPE_EDITABLE_TEXT;
1048     case WAIText:
1049         return ATK_TYPE_TEXT;
1050     case WAIComponent:
1051         return ATK_TYPE_COMPONENT;
1052     case WAIImage:
1053         return ATK_TYPE_IMAGE;
1054     case WAITable:
1055         return ATK_TYPE_TABLE;
1056 #if ATK_CHECK_VERSION(2,11,90)
1057     case WAITableCell:
1058         return ATK_TYPE_TABLE_CELL;
1059 #endif
1060     case WAIHypertext:
1061         return ATK_TYPE_HYPERTEXT;
1062     case WAIHyperlink:
1063         return ATK_TYPE_HYPERLINK_IMPL;
1064     case WAIDocument:
1065         return ATK_TYPE_DOCUMENT;
1066     case WAIValue:
1067         return ATK_TYPE_VALUE;
1068     }
1069
1070     return G_TYPE_INVALID;
1071 }
1072
1073 static bool roleIsTextType(AccessibilityRole role)
1074 {
1075     return role == ParagraphRole || role == HeadingRole || role == DivRole || role == CellRole
1076         || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole;
1077 }
1078
1079 static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
1080 {
1081     guint16 interfaceMask = 0;
1082
1083     // Component interface is always supported
1084     interfaceMask |= 1 << WAIComponent;
1085
1086     AccessibilityRole role = coreObject->roleValue();
1087
1088     // Action
1089     // As the implementation of the AtkAction interface is a very
1090     // basic one (just relays in executing the default action for each
1091     // object, and only supports having one action per object), it is
1092     // better just to implement this interface for every instance of
1093     // the WebKitAccessible class and let WebCore decide what to do.
1094     interfaceMask |= 1 << WAIAction;
1095
1096     // Selection
1097     if (coreObject->isListBox() || coreObject->isMenuList())
1098         interfaceMask |= 1 << WAISelection;
1099
1100     // Get renderer if available.
1101     RenderObject* renderer = 0;
1102     if (coreObject->isAccessibilityRenderObject())
1103         renderer = coreObject->renderer();
1104
1105     // Hyperlink (links and embedded objects).
1106     if (coreObject->isLink() || (renderer && renderer->isReplaced()))
1107         interfaceMask |= 1 << WAIHyperlink;
1108
1109     // Text, Editable Text & Hypertext
1110     if (role == StaticTextRole || coreObject->isMenuListOption())
1111         interfaceMask |= 1 << WAIText;
1112     else if (coreObject->isTextControl()) {
1113         interfaceMask |= 1 << WAIText;
1114         if (!coreObject->isReadOnly())
1115             interfaceMask |= 1 << WAIEditableText;
1116     } else if (!coreObject->isWebArea()) {
1117         if (role != TableRole) {
1118             interfaceMask |= 1 << WAIHypertext;
1119             if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
1120                 interfaceMask |= 1 << WAIText;
1121         }
1122
1123         // Add the TEXT interface for list items whose
1124         // first accessible child has a text renderer
1125         if (role == ListItemRole) {
1126             const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
1127             if (children.size()) {
1128                 AccessibilityObject* axRenderChild = children.at(0).get();
1129                 interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
1130             }
1131         }
1132     }
1133
1134     // Image
1135     if (coreObject->isImage())
1136         interfaceMask |= 1 << WAIImage;
1137
1138     // Table
1139     if (role == TableRole)
1140         interfaceMask |= 1 << WAITable;
1141
1142 #if ATK_CHECK_VERSION(2,11,90)
1143     if (role == CellRole || role == ColumnHeaderRole || role == RowHeaderRole)
1144         interfaceMask |= 1 << WAITableCell;
1145 #endif
1146
1147     // Document
1148     if (role == WebAreaRole)
1149         interfaceMask |= 1 << WAIDocument;
1150
1151     // Value
1152     if (role == SliderRole || role == SpinButtonRole || role == ScrollBarRole || role == ProgressIndicatorRole)
1153         interfaceMask |= 1 << WAIValue;
1154
1155 #if ENABLE(INPUT_TYPE_COLOR)
1156     // Color type.
1157     if (role == ColorWellRole)
1158         interfaceMask |= 1 << WAIText;
1159 #endif
1160
1161     return interfaceMask;
1162 }
1163
1164 static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
1165 {
1166 #define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
1167     static char name[WAI_TYPE_NAME_LEN + 1];
1168
1169     g_sprintf(name, "WAIType%x", interfaceMask);
1170     name[WAI_TYPE_NAME_LEN] = '\0';
1171
1172     return name;
1173 }
1174
1175 static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
1176 {
1177     static const GTypeInfo typeInfo = {
1178         sizeof(WebKitAccessibleClass),
1179         (GBaseInitFunc) 0,
1180         (GBaseFinalizeFunc) 0,
1181         (GClassInitFunc) 0,
1182         (GClassFinalizeFunc) 0,
1183         0, /* class data */
1184         sizeof(WebKitAccessible), /* instance size */
1185         0, /* nb preallocs */
1186         (GInstanceInitFunc) 0,
1187         0 /* value table */
1188     };
1189
1190     guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
1191     const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
1192     GType type = g_type_from_name(atkTypeName);
1193     if (type)
1194         return type;
1195
1196     type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE, atkTypeName, &typeInfo, GTypeFlags(0));
1197     for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
1198         if (interfaceMask & (1 << i))
1199             g_type_add_interface_static(type,
1200                 GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
1201                 &AtkInterfacesInitFunctions[i]);
1202     }
1203
1204     return type;
1205 }
1206
1207 WebKitAccessible* webkitAccessibleNew(AccessibilityObject* coreObject)
1208 {
1209     GType type = getAccessibilityTypeFromObject(coreObject);
1210     AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
1211
1212     atk_object_initialize(object, coreObject);
1213
1214     return WEBKIT_ACCESSIBLE(object);
1215 }
1216
1217 AccessibilityObject* webkitAccessibleGetAccessibilityObject(WebKitAccessible* accessible)
1218 {
1219     return accessible->m_object;
1220 }
1221
1222 void webkitAccessibleDetach(WebKitAccessible* accessible)
1223 {
1224     ASSERT(accessible->m_object);
1225
1226     if (accessible->m_object->roleValue() == WebAreaRole)
1227         atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, true);
1228
1229     // We replace the WebCore AccessibilityObject with a fallback object that
1230     // provides default implementations to avoid repetitive null-checking after
1231     // detachment.
1232     accessible->m_object = fallbackObject();
1233 }
1234
1235 bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
1236 {
1237     ASSERT(accessible->m_object);
1238     return accessible->m_object == fallbackObject();
1239 }
1240
1241 AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* referenceObject, int& offset)
1242 {
1243     // Indication that something bogus has transpired.
1244     offset = -1;
1245
1246     Document* document = referenceObject->document();
1247     if (!document)
1248         return 0;
1249
1250     Node* focusedNode = referenceObject->selection().end().containerNode();
1251     if (!focusedNode)
1252         return 0;
1253
1254     RenderObject* focusedRenderer = focusedNode->renderer();
1255     if (!focusedRenderer)
1256         return 0;
1257
1258     AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
1259     if (!focusedObject)
1260         return 0;
1261
1262     // Look for the actual (not ignoring accessibility) selected object.
1263     AccessibilityObject* firstUnignoredParent = focusedObject;
1264     if (firstUnignoredParent->accessibilityIsIgnored())
1265         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1266     if (!firstUnignoredParent)
1267         return 0;
1268
1269     // Don't ignore links if the offset is being requested for a link
1270     // or if the link is a block.
1271     if (!referenceObject->isLink() && firstUnignoredParent->isLink()
1272         && !(firstUnignoredParent->renderer() && !firstUnignoredParent->renderer()->isInline()))
1273         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1274     if (!firstUnignoredParent)
1275         return 0;
1276
1277     // The reference object must either coincide with the focused
1278     // object being considered, or be a descendant of it.
1279     if (referenceObject->isDescendantOfObject(firstUnignoredParent))
1280         referenceObject = firstUnignoredParent;
1281
1282     Node* startNode = 0;
1283     if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
1284         // We need to use the first child's node of the reference
1285         // object as the start point to calculate the caret offset
1286         // because we want it to be relative to the object of
1287         // reference, not just to the focused object (which could have
1288         // previous siblings which should be taken into account too).
1289         AccessibilityObject* axFirstChild = referenceObject->firstChild();
1290         if (axFirstChild)
1291             startNode = axFirstChild->node();
1292     }
1293     // Getting the Position of a PseudoElement now triggers an assertion.
1294     // This can occur when clicking on empty space in a render block.
1295     if (!startNode || startNode->isPseudoElement())
1296         startNode = firstUnignoredParent->node();
1297
1298     // Check if the node for the first parent object not ignoring
1299     // accessibility is null again before using it. This might happen
1300     // with certain kind of accessibility objects, such as the root
1301     // one (the scroller containing the webArea object).
1302     if (!startNode)
1303         return 0;
1304
1305     VisiblePosition startPosition = VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
1306     VisiblePosition endPosition = firstUnignoredParent->selection().visibleEnd();
1307
1308     if (startPosition == endPosition)
1309         offset = 0;
1310     else if (!isStartOfLine(endPosition)) {
1311         RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
1312         offset = TextIterator::rangeLength(range.get(), true) + 1;
1313     } else {
1314         RefPtr<Range> range = makeRange(startPosition, endPosition);
1315         offset = TextIterator::rangeLength(range.get(), true);
1316     }
1317
1318     return firstUnignoredParent;
1319 }
1320
1321 const char* cacheAndReturnAtkProperty(AtkObject* object, AtkCachedProperty property, String value)
1322 {
1323     WebKitAccessiblePrivate* priv = WEBKIT_ACCESSIBLE(object)->priv;
1324     CString* propertyPtr = 0;
1325
1326     switch (property) {
1327     case AtkCachedAccessibleName:
1328         propertyPtr = &priv->accessibleName;
1329         break;
1330
1331     case AtkCachedAccessibleDescription:
1332         propertyPtr = &priv->accessibleDescription;
1333         break;
1334
1335     case AtkCachedActionName:
1336         propertyPtr = &priv->actionName;
1337         break;
1338
1339     case AtkCachedActionKeyBinding:
1340         propertyPtr = &priv->actionKeyBinding;
1341         break;
1342
1343     case AtkCachedDocumentLocale:
1344         propertyPtr = &priv->documentLocale;
1345         break;
1346
1347     case AtkCachedDocumentType:
1348         propertyPtr = &priv->documentType;
1349         break;
1350
1351     case AtkCachedDocumentEncoding:
1352         propertyPtr = &priv->documentEncoding;
1353         break;
1354
1355     case AtkCachedDocumentURI:
1356         propertyPtr = &priv->documentURI;
1357         break;
1358
1359     case AtkCachedImageDescription:
1360         propertyPtr = &priv->imageDescription;
1361         break;
1362
1363     default:
1364         ASSERT_NOT_REACHED();
1365     }
1366
1367     // Don't invalidate old memory if not stricly needed, since other
1368     // callers might be still holding on to it.
1369     if (*propertyPtr != value.utf8())
1370         *propertyPtr = value.utf8();
1371
1372     return (*propertyPtr).data();
1373 }
1374
1375 #endif // HAVE(ACCESSIBILITY)