Replaced 0 with nullptr in WebCore/accessibility.
[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 = nullptr;
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     return coreParent->wrapper();
322 }
323
324 static gint webkitAccessibleGetNChildren(AtkObject* object)
325 {
326     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
327     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
328
329     AccessibilityObject* coreObject = core(object);
330
331     return coreObject->children().size();
332 }
333
334 static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
335 {
336     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
337     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
338
339     if (index < 0)
340         return 0;
341
342     AccessibilityObject* coreObject = core(object);
343     AccessibilityObject* coreChild = nullptr;
344
345     const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
346     if (static_cast<size_t>(index) >= children.size())
347         return 0;
348     coreChild = children.at(index).get();
349
350     if (!coreChild)
351         return 0;
352
353     AtkObject* child = coreChild->wrapper();
354     atk_object_set_parent(child, object);
355     g_object_ref(child);
356
357     return child;
358 }
359
360 static gint webkitAccessibleGetIndexInParent(AtkObject* object)
361 {
362     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), -1);
363     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), -1);
364
365     AccessibilityObject* coreObject = core(object);
366     AccessibilityObject* parent = coreObject->parentObjectUnignored();
367
368     if (!parent && isRootObject(coreObject)) {
369         AtkObject* atkParent = atkParentOfRootObject(object);
370         if (!atkParent)
371             return -1;
372
373         unsigned count = atk_object_get_n_accessible_children(atkParent);
374         for (unsigned i = 0; i < count; ++i) {
375             AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
376             bool childIsObject = child == object;
377             g_object_unref(child);
378             if (childIsObject)
379                 return i;
380         }
381     }
382
383     if (!parent)
384         return -1;
385
386     size_t index = parent->children().find(coreObject);
387     return (index == WTF::notFound) ? -1 : index;
388 }
389
390 static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
391 {
392     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
393     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
394
395     AtkAttributeSet* attributeSet = nullptr;
396 #if PLATFORM(GTK)
397     attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
398 #elif PLATFORM(EFL)
399     attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitEfl");
400 #endif
401
402     AccessibilityObject* coreObject = core(object);
403     if (!coreObject)
404         return attributeSet;
405
406     // Hack needed for WebKit2 tests because obtaining an element by its ID
407     // cannot be done from the UIProcess. Assistive technologies have no need
408     // for this information.
409     Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
410     if (element) {
411         String id = element->getIdAttribute().string();
412         if (!id.isEmpty())
413             attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
414     }
415
416     int headingLevel = coreObject->headingLevel();
417     if (headingLevel) {
418         String value = String::number(headingLevel);
419         attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
420     }
421
422     if (coreObject->roleValue() == MathElementRole) {
423         if (coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PreSubscript))
424             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
425         else if (coreObject->isMathMultiscriptObject(PostSuperscript) || coreObject->isMathMultiscriptObject(PostSubscript))
426             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
427     }
428
429     // Set the 'layout-guess' attribute to help Assistive
430     // Technologies know when an exposed table is not data table.
431     if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposableThroughAccessibility() && !coreObject->isDataTable())
432         attributeSet = addToAtkAttributeSet(attributeSet, "layout-guess", "true");
433
434     String placeholder = coreObject->placeholderValue();
435     if (!placeholder.isEmpty())
436         attributeSet = addToAtkAttributeSet(attributeSet, "placeholder-text", placeholder.utf8().data());
437
438     if (coreObject->ariaHasPopup())
439         attributeSet = addToAtkAttributeSet(attributeSet, "haspopup", "true");
440
441     AccessibilitySortDirection sortDirection = coreObject->sortDirection();
442     if (sortDirection != SortDirectionNone) {
443         // WAI-ARIA spec says to translate the value as is from the attribute.
444         const AtomicString& sortAttribute = coreObject->getAttribute(HTMLNames::aria_sortAttr);
445         attributeSet = addToAtkAttributeSet(attributeSet, "sort", sortAttribute.string().utf8().data());
446     }
447
448     if (coreObject->supportsARIAPosInSet())
449         attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->ariaPosInSet()).utf8().data());
450
451     if (coreObject->supportsARIASetSize())
452         attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->ariaSetSize()).utf8().data());
453
454     // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
455     // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
456     // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
457     // The computedRoleString is primarily for testing, and not limited to elements with ARIA roles.
458     // Because the computedRoleString currently contains the ARIA role string, we'll use it for
459     // both purposes, as the "computed-role" object attribute for all elements which have a value
460     // and also via the "xml-roles" attribute for elements with ARIA, as well as for landmarks.
461     String roleString = coreObject->computedRoleString();
462     if (!roleString.isEmpty()) {
463         if (coreObject->ariaRoleAttribute() != UnknownRole || coreObject->isLandmark())
464             attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", roleString.utf8().data());
465         attributeSet = addToAtkAttributeSet(attributeSet, "computed-role", roleString.utf8().data());
466     }
467
468     return attributeSet;
469 }
470
471 static AtkRole atkRole(AccessibilityObject* coreObject)
472 {
473     AccessibilityRole role = coreObject->roleValue();
474     switch (role) {
475     case ApplicationAlertDialogRole:
476     case ApplicationAlertRole:
477         return ATK_ROLE_ALERT;
478     case ApplicationDialogRole:
479         return ATK_ROLE_DIALOG;
480     case ApplicationStatusRole:
481         return ATK_ROLE_STATUSBAR;
482     case UnknownRole:
483         return ATK_ROLE_UNKNOWN;
484     case AudioRole:
485 #if ATK_CHECK_VERSION(2, 11, 3)
486         return ATK_ROLE_AUDIO;
487 #endif
488     case VideoRole:
489 #if ATK_CHECK_VERSION(2, 11, 3)
490         return ATK_ROLE_VIDEO;
491 #endif
492         return ATK_ROLE_EMBEDDED;
493     case ButtonRole:
494         return ATK_ROLE_PUSH_BUTTON;
495     case SwitchRole:
496     case ToggleButtonRole:
497         return ATK_ROLE_TOGGLE_BUTTON;
498     case RadioButtonRole:
499         return ATK_ROLE_RADIO_BUTTON;
500     case CheckBoxRole:
501         return ATK_ROLE_CHECK_BOX;
502     case SliderRole:
503         return ATK_ROLE_SLIDER;
504     case TabGroupRole:
505     case TabListRole:
506         return ATK_ROLE_PAGE_TAB_LIST;
507     case TextFieldRole:
508     case TextAreaRole:
509     case SearchFieldRole:
510         return ATK_ROLE_ENTRY;
511     case StaticTextRole:
512         return ATK_ROLE_TEXT;
513     case OutlineRole:
514     case TreeRole:
515         return ATK_ROLE_TREE;
516     case TreeItemRole:
517         return ATK_ROLE_TREE_ITEM;
518     case MenuBarRole:
519         return ATK_ROLE_MENU_BAR;
520     case MenuListPopupRole:
521     case MenuRole:
522         return ATK_ROLE_MENU;
523     case MenuListOptionRole:
524     case MenuItemRole:
525         return ATK_ROLE_MENU_ITEM;
526     case MenuItemCheckboxRole:
527         return ATK_ROLE_CHECK_MENU_ITEM;
528     case MenuItemRadioRole:
529         return ATK_ROLE_RADIO_MENU_ITEM;
530     case ColumnRole:
531         // return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
532         return ATK_ROLE_UNKNOWN; // Matches Mozilla
533     case RowRole:
534         return ATK_ROLE_TABLE_ROW;
535     case ToolbarRole:
536         return ATK_ROLE_TOOL_BAR;
537     case BusyIndicatorRole:
538         return ATK_ROLE_PROGRESS_BAR; // Is this right?
539     case ProgressIndicatorRole:
540         // return ATK_ROLE_SPIN_BUTTON; // Some confusion about this role in AccessibilityRenderObject.cpp
541         return ATK_ROLE_PROGRESS_BAR;
542     case WindowRole:
543         return ATK_ROLE_WINDOW;
544     case PopUpButtonRole:
545     case ComboBoxRole:
546         return ATK_ROLE_COMBO_BOX;
547     case SplitGroupRole:
548         return ATK_ROLE_SPLIT_PANE;
549     case SplitterRole:
550         return ATK_ROLE_SEPARATOR;
551     case ColorWellRole:
552 #if PLATFORM(GTK)
553         // ATK_ROLE_COLOR_CHOOSER is defined as a dialog (i.e. it's what appears when you push the button).
554         return ATK_ROLE_PUSH_BUTTON;
555 #elif PLATFORM(EFL)
556         return ATK_ROLE_COLOR_CHOOSER;
557 #endif
558     case ListRole:
559         return ATK_ROLE_LIST;
560     case ScrollBarRole:
561         return ATK_ROLE_SCROLL_BAR;
562     case ScrollAreaRole:
563         return ATK_ROLE_SCROLL_PANE;
564     case GridRole: // Is this right?
565     case TableRole:
566         return ATK_ROLE_TABLE;
567     case ApplicationRole:
568         return ATK_ROLE_APPLICATION;
569     case DocumentRegionRole:
570     case GroupRole:
571     case RadioGroupRole:
572     case TabPanelRole:
573         return ATK_ROLE_PANEL;
574     case RowHeaderRole:
575         return ATK_ROLE_ROW_HEADER;
576     case ColumnHeaderRole:
577         return ATK_ROLE_COLUMN_HEADER;
578     case CaptionRole:
579         return ATK_ROLE_CAPTION;
580     case CellRole:
581         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
582     case LinkRole:
583     case WebCoreLinkRole:
584     case ImageMapLinkRole:
585         return ATK_ROLE_LINK;
586     case ImageMapRole:
587         return ATK_ROLE_IMAGE_MAP;
588     case ImageRole:
589         return ATK_ROLE_IMAGE;
590     case ListMarkerRole:
591         return ATK_ROLE_TEXT;
592     case DocumentArticleRole:
593 #if ATK_CHECK_VERSION(2, 11, 3)
594         return ATK_ROLE_ARTICLE;
595 #endif
596     case DocumentRole:
597         return ATK_ROLE_DOCUMENT_FRAME;
598     case DocumentNoteRole:
599         return ATK_ROLE_COMMENT;
600     case HeadingRole:
601         return ATK_ROLE_HEADING;
602     case ListBoxRole:
603         return ATK_ROLE_LIST_BOX;
604     case ListItemRole:
605         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
606     case ListBoxOptionRole:
607         return ATK_ROLE_LIST_ITEM;
608     case ParagraphRole:
609         return ATK_ROLE_PARAGRAPH;
610     case LabelRole:
611     case LegendRole:
612         return ATK_ROLE_LABEL;
613     case BlockquoteRole:
614 #if ATK_CHECK_VERSION(2, 11, 3)
615         return ATK_ROLE_BLOCK_QUOTE;
616 #endif
617     case DivRole:
618     case PreRole:
619         return ATK_ROLE_SECTION;
620     case FooterRole:
621         return ATK_ROLE_FOOTER;
622     case FormRole:
623         return ATK_ROLE_FORM;
624     case CanvasRole:
625         return ATK_ROLE_CANVAS;
626     case HorizontalRuleRole:
627         return ATK_ROLE_SEPARATOR;
628     case SpinButtonRole:
629         return ATK_ROLE_SPIN_BUTTON;
630     case TabRole:
631         return ATK_ROLE_PAGE_TAB;
632     case UserInterfaceTooltipRole:
633         return ATK_ROLE_TOOL_TIP;
634     case WebAreaRole:
635         return ATK_ROLE_DOCUMENT_WEB;
636     case LandmarkApplicationRole:
637         return ATK_ROLE_EMBEDDED;
638 #if ATK_CHECK_VERSION(2, 11, 3)
639     case ApplicationLogRole:
640         return ATK_ROLE_LOG;
641     case ApplicationMarqueeRole:
642         return ATK_ROLE_MARQUEE;
643     case ApplicationTimerRole:
644         return ATK_ROLE_TIMER;
645     case DefinitionRole:
646         return ATK_ROLE_DEFINITION;
647     case DocumentMathRole:
648         return ATK_ROLE_MATH;
649     case MathElementRole:
650         if (coreObject->isMathRow())
651             return ATK_ROLE_PANEL;
652         if (coreObject->isMathTable())
653             return ATK_ROLE_TABLE;
654         if (coreObject->isMathTableRow())
655             return ATK_ROLE_TABLE_ROW;
656         if (coreObject->isMathTableCell())
657             return ATK_ROLE_TABLE_CELL;
658         if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
659             return ATK_ROLE_SECTION;
660 #if ATK_CHECK_VERSION(2, 15, 4)
661         if (coreObject->isMathFraction())
662             return ATK_ROLE_MATH_FRACTION;
663         if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
664             return ATK_ROLE_MATH_ROOT;
665         if (coreObject->isMathScriptObject(Subscript)
666             || coreObject->isMathMultiscriptObject(PreSubscript) || coreObject->isMathMultiscriptObject(PostSubscript))
667             return ATK_ROLE_SUBSCRIPT;
668         if (coreObject->isMathScriptObject(Superscript)
669             || coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PostSuperscript))
670             return ATK_ROLE_SUPERSCRIPT;
671 #endif
672 #if ATK_CHECK_VERSION(2, 15, 2)
673         if (coreObject->isMathToken())
674             return ATK_ROLE_STATIC;
675 #endif
676         return ATK_ROLE_UNKNOWN;
677     case LandmarkBannerRole:
678     case LandmarkComplementaryRole:
679     case LandmarkContentInfoRole:
680     case LandmarkMainRole:
681     case LandmarkNavigationRole:
682     case LandmarkSearchRole:
683         return ATK_ROLE_LANDMARK;
684 #endif
685 #if ATK_CHECK_VERSION(2, 11, 4)
686     case DescriptionListRole:
687         return ATK_ROLE_DESCRIPTION_LIST;
688     case DescriptionListTermRole:
689         return ATK_ROLE_DESCRIPTION_TERM;
690     case DescriptionListDetailRole:
691         return ATK_ROLE_DESCRIPTION_VALUE;
692 #endif
693 #if ATK_CHECK_VERSION(2, 15, 2)
694     case InlineRole:
695         return ATK_ROLE_STATIC;
696 #endif
697     default:
698         return ATK_ROLE_UNKNOWN;
699     }
700 }
701
702 static AtkRole webkitAccessibleGetRole(AtkObject* object)
703 {
704     // ATK_ROLE_UNKNOWN should only be applied in cases where there is a valid
705     // WebCore accessible object for which the platform role mapping is unknown.
706     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), ATK_ROLE_INVALID);
707     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), ATK_ROLE_INVALID);
708
709     AccessibilityObject* coreObject = core(object);
710
711     if (!coreObject)
712         return ATK_ROLE_INVALID;
713
714     // Note: Why doesn't WebCore have a password field for this
715     if (coreObject->isPasswordField())
716         return ATK_ROLE_PASSWORD_TEXT;
717
718     return atkRole(coreObject);
719 }
720
721 static bool isTextWithCaret(AccessibilityObject* coreObject)
722 {
723     if (!coreObject || !coreObject->isAccessibilityRenderObject())
724         return false;
725
726     Document* document = coreObject->document();
727     if (!document)
728         return false;
729
730     Frame* frame = document->frame();
731     if (!frame)
732         return false;
733
734     if (!frame->settings().caretBrowsingEnabled())
735         return false;
736
737     // Check text objects and paragraphs only.
738     AtkObject* axObject = coreObject->wrapper();
739     AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
740     if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
741         return false;
742
743     // Finally, check whether the caret is set in the current object.
744     VisibleSelection selection = coreObject->selection();
745     if (!selection.isCaret())
746         return false;
747
748     return selectionBelongsToObject(coreObject, selection);
749 }
750
751 static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
752 {
753     AccessibilityObject* parent = coreObject->parentObject();
754     bool isListBoxOption = parent && parent->isListBox();
755
756     // Please keep the state list in alphabetical order
757     if (isListBoxOption && coreObject->isSelectedOptionActive())
758         atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
759
760     if (coreObject->isChecked())
761         atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
762
763     // FIXME: isReadOnly does not seem to do the right thing for
764     // controls, so check explicitly for them. In addition, because
765     // isReadOnly is false for listBoxOptions, we need to add one
766     // more check so that we do not present them as being "editable".
767     if ((!coreObject->isReadOnly()
768         || (coreObject->isControl() && coreObject->canSetValueAttribute()))
769         && !isListBoxOption)
770         atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
771
772     // FIXME: Put both ENABLED and SENSITIVE together here for now
773     if (coreObject->isEnabled()) {
774         atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
775         atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
776     }
777
778     if (coreObject->canSetExpandedAttribute())
779         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
780
781     if (coreObject->isExpanded())
782         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
783
784     if (coreObject->canSetFocusAttribute())
785         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
786
787     if (coreObject->isFocused() || isTextWithCaret(coreObject))
788         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
789
790     if (coreObject->orientation() == AccessibilityOrientationHorizontal)
791         atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);
792     else if (coreObject->orientation() == AccessibilityOrientationVertical)
793         atk_state_set_add_state(stateSet, ATK_STATE_VERTICAL);
794
795     if (coreObject->isIndeterminate())
796         atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
797
798     if (coreObject->isCheckboxOrRadio() || coreObject->isMenuItem()) {
799         if (coreObject->checkboxOrRadioValue() == ButtonStateMixed)
800             atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
801     }
802
803     if (coreObject->invalidStatus() != "false")
804         atk_state_set_add_state(stateSet, ATK_STATE_INVALID_ENTRY);
805
806     if (coreObject->isMultiSelectable())
807         atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
808
809     // TODO: ATK_STATE_OPAQUE
810
811     if (coreObject->isPressed())
812         atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
813
814     if (coreObject->isRequired())
815         atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
816
817     // TODO: ATK_STATE_SELECTABLE_TEXT
818
819     if (coreObject->canSetSelectedAttribute()) {
820         atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
821         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
822         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on
823         // the former.
824         if (isListBoxOption)
825             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
826     }
827
828     if (coreObject->isSelected()) {
829         atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
830         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
831         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
832         // former.
833         if (isListBoxOption)
834             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
835     }
836
837     // FIXME: Group both SHOWING and VISIBLE here for now
838     // Not sure how to handle this in WebKit, see bug
839     // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
840     // issues with SHOWING vs VISIBLE.
841     if (!coreObject->isOffScreen()) {
842         atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
843         atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
844     }
845
846     // Mutually exclusive, so we group these two
847     if (coreObject->roleValue() == TextFieldRole)
848         atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
849     else if (coreObject->roleValue() == TextAreaRole)
850         atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
851
852     // TODO: ATK_STATE_SENSITIVE
853
854     if (coreObject->isVisited())
855         atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
856 }
857
858 static AtkStateSet* webkitAccessibleRefStateSet(AtkObject* object)
859 {
860     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
861
862     AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_state_set(object);
863     AccessibilityObject* coreObject = core(object);
864
865     // Make sure the layout is updated to really know whether the object
866     // is defunct or not, so we can return the proper state.
867     coreObject->updateBackingStore();
868
869     if (coreObject == fallbackObject()) {
870         atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
871         return stateSet;
872     }
873
874     // Text objects must be focusable.
875     AtkRole role = atk_object_get_role(object);
876     if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
877         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
878
879     setAtkStateSetFromCoreObject(coreObject, stateSet);
880     return stateSet;
881 }
882
883 static AtkRelationSet* webkitAccessibleRefRelationSet(AtkObject* object)
884 {
885     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
886     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
887
888     AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_relation_set(object);
889     AccessibilityObject* coreObject = core(object);
890
891     setAtkRelationSetFromCoreObject(coreObject, relationSet);
892
893     return relationSet;
894 }
895
896 static void webkitAccessibleInit(AtkObject* object, gpointer data)
897 {
898     if (ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize)
899         ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize(object, data);
900
901     WebKitAccessible* accessible = WEBKIT_ACCESSIBLE(object);
902     accessible->m_object = reinterpret_cast<AccessibilityObject*>(data);
903     accessible->priv = WEBKIT_ACCESSIBLE_GET_PRIVATE(accessible);
904 }
905
906 static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
907 {
908     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
909     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
910
911     AccessibilityObject* coreObject = core(object);
912     if (!coreObject)
913         return 0;
914
915     if (ATK_IS_DOCUMENT(object)) {
916         // TODO: Should we fall back on lang xml:lang when the following comes up empty?
917         String language = coreObject->language();
918         if (!language.isEmpty())
919             return cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, language);
920
921     } else if (ATK_IS_TEXT(object)) {
922         const gchar* locale = nullptr;
923
924         AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
925         for (AtkAttributeSet* attributes = textAttributes; attributes; attributes = attributes->next) {
926             AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
927             if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
928                 locale = cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, String::fromUTF8(atkAttribute->value));
929                 break;
930             }
931         }
932         atk_attribute_set_free(textAttributes);
933
934         return locale;
935     }
936
937     return 0;
938 }
939
940 static void webkitAccessibleFinalize(GObject* object)
941 {
942     G_OBJECT_CLASS(webkitAccessibleParentClass)->finalize(object);
943 }
944
945 static void webkitAccessibleClassInit(AtkObjectClass* klass)
946 {
947     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
948
949     webkitAccessibleParentClass = g_type_class_peek_parent(klass);
950
951     gobjectClass->finalize = webkitAccessibleFinalize;
952
953     klass->initialize = webkitAccessibleInit;
954     klass->get_name = webkitAccessibleGetName;
955     klass->get_description = webkitAccessibleGetDescription;
956     klass->get_parent = webkitAccessibleGetParent;
957     klass->get_n_children = webkitAccessibleGetNChildren;
958     klass->ref_child = webkitAccessibleRefChild;
959     klass->get_role = webkitAccessibleGetRole;
960     klass->ref_state_set = webkitAccessibleRefStateSet;
961     klass->get_index_in_parent = webkitAccessibleGetIndexInParent;
962     klass->get_attributes = webkitAccessibleGetAttributes;
963     klass->ref_relation_set = webkitAccessibleRefRelationSet;
964     klass->get_object_locale = webkitAccessibleGetObjectLocale;
965
966     g_type_class_add_private(klass, sizeof(WebKitAccessiblePrivate));
967 }
968
969 GType
970 webkitAccessibleGetType(void)
971 {
972     static volatile gsize typeVolatile = 0;
973
974     if (g_once_init_enter(&typeVolatile)) {
975         static const GTypeInfo tinfo = {
976             sizeof(WebKitAccessibleClass),
977             (GBaseInitFunc) 0,
978             (GBaseFinalizeFunc) 0,
979             (GClassInitFunc) webkitAccessibleClassInit,
980             (GClassFinalizeFunc) 0,
981             0, /* class data */
982             sizeof(WebKitAccessible), /* instance size */
983             0, /* nb preallocs */
984             (GInstanceInitFunc) 0,
985             0 /* value table */
986         };
987
988         GType type = g_type_register_static(ATK_TYPE_OBJECT, "WebKitAccessible", &tinfo, GTypeFlags(0));
989         g_once_init_leave(&typeVolatile, type);
990     }
991
992     return typeVolatile;
993 }
994
995 static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
996     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleActionInterfaceInit), 0, 0},
997     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleSelectionInterfaceInit), 0, 0},
998     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleEditableTextInterfaceInit), 0, 0},
999     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTextInterfaceInit), 0, 0},
1000     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleComponentInterfaceInit), 0, 0},
1001     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleImageInterfaceInit), 0, 0},
1002     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableInterfaceInit), 0, 0},
1003 #if ATK_CHECK_VERSION(2,11,90)
1004     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableCellInterfaceInit), 0, 0},
1005 #endif
1006     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHypertextInterfaceInit), 0, 0},
1007     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHyperlinkImplInterfaceInit), 0, 0},
1008     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleDocumentInterfaceInit), 0, 0},
1009     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleValueInterfaceInit), 0, 0}
1010 };
1011
1012 enum WAIType {
1013     WAIAction,
1014     WAISelection,
1015     WAIEditableText,
1016     WAIText,
1017     WAIComponent,
1018     WAIImage,
1019     WAITable,
1020 #if ATK_CHECK_VERSION(2,11,90)
1021     WAITableCell,
1022 #endif
1023     WAIHypertext,
1024     WAIHyperlink,
1025     WAIDocument,
1026     WAIValue,
1027 };
1028
1029 static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
1030 {
1031     switch (type) {
1032     case WAIAction:
1033         return ATK_TYPE_ACTION;
1034     case WAISelection:
1035         return ATK_TYPE_SELECTION;
1036     case WAIEditableText:
1037         return ATK_TYPE_EDITABLE_TEXT;
1038     case WAIText:
1039         return ATK_TYPE_TEXT;
1040     case WAIComponent:
1041         return ATK_TYPE_COMPONENT;
1042     case WAIImage:
1043         return ATK_TYPE_IMAGE;
1044     case WAITable:
1045         return ATK_TYPE_TABLE;
1046 #if ATK_CHECK_VERSION(2,11,90)
1047     case WAITableCell:
1048         return ATK_TYPE_TABLE_CELL;
1049 #endif
1050     case WAIHypertext:
1051         return ATK_TYPE_HYPERTEXT;
1052     case WAIHyperlink:
1053         return ATK_TYPE_HYPERLINK_IMPL;
1054     case WAIDocument:
1055         return ATK_TYPE_DOCUMENT;
1056     case WAIValue:
1057         return ATK_TYPE_VALUE;
1058     }
1059
1060     return G_TYPE_INVALID;
1061 }
1062
1063 static bool roleIsTextType(AccessibilityRole role)
1064 {
1065     return role == ParagraphRole || role == HeadingRole || role == DivRole || role == CellRole
1066         || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole || role == PreRole;
1067 }
1068
1069 static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
1070 {
1071     guint16 interfaceMask = 0;
1072
1073     // Component interface is always supported
1074     interfaceMask |= 1 << WAIComponent;
1075
1076     AccessibilityRole role = coreObject->roleValue();
1077
1078     // Action
1079     // As the implementation of the AtkAction interface is a very
1080     // basic one (just relays in executing the default action for each
1081     // object, and only supports having one action per object), it is
1082     // better just to implement this interface for every instance of
1083     // the WebKitAccessible class and let WebCore decide what to do.
1084     interfaceMask |= 1 << WAIAction;
1085
1086     // Selection
1087     if (coreObject->isListBox() || coreObject->isMenuList())
1088         interfaceMask |= 1 << WAISelection;
1089
1090     // Get renderer if available.
1091     RenderObject* renderer = nullptr;
1092     if (coreObject->isAccessibilityRenderObject())
1093         renderer = coreObject->renderer();
1094
1095     // Hyperlink (links and embedded objects).
1096     if (coreObject->isLink() || (renderer && renderer->isReplaced()))
1097         interfaceMask |= 1 << WAIHyperlink;
1098
1099     // Text, Editable Text & Hypertext
1100     if (role == StaticTextRole || coreObject->isMenuListOption())
1101         interfaceMask |= 1 << WAIText;
1102     else if (coreObject->isTextControl()) {
1103         interfaceMask |= 1 << WAIText;
1104         if (!coreObject->isReadOnly())
1105             interfaceMask |= 1 << WAIEditableText;
1106     } else if (!coreObject->isWebArea()) {
1107         if (role != TableRole) {
1108             interfaceMask |= 1 << WAIHypertext;
1109             if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
1110                 interfaceMask |= 1 << WAIText;
1111         }
1112
1113         // Add the TEXT interface for list items whose
1114         // first accessible child has a text renderer
1115         if (role == ListItemRole) {
1116             const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
1117             if (children.size()) {
1118                 AccessibilityObject* axRenderChild = children.at(0).get();
1119                 interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
1120             }
1121         }
1122     }
1123
1124     // Image
1125     if (coreObject->isImage())
1126         interfaceMask |= 1 << WAIImage;
1127
1128     // Table
1129     if (role == TableRole)
1130         interfaceMask |= 1 << WAITable;
1131
1132 #if ATK_CHECK_VERSION(2,11,90)
1133     if (role == CellRole || role == ColumnHeaderRole || role == RowHeaderRole)
1134         interfaceMask |= 1 << WAITableCell;
1135 #endif
1136
1137     // Document
1138     if (role == WebAreaRole)
1139         interfaceMask |= 1 << WAIDocument;
1140
1141     // Value
1142     if (role == SliderRole || role == SpinButtonRole || role == ScrollBarRole || role == ProgressIndicatorRole)
1143         interfaceMask |= 1 << WAIValue;
1144
1145 #if ENABLE(INPUT_TYPE_COLOR)
1146     // Color type.
1147     if (role == ColorWellRole)
1148         interfaceMask |= 1 << WAIText;
1149 #endif
1150
1151     return interfaceMask;
1152 }
1153
1154 static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
1155 {
1156 #define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
1157     static char name[WAI_TYPE_NAME_LEN + 1];
1158
1159     g_sprintf(name, "WAIType%x", interfaceMask);
1160     name[WAI_TYPE_NAME_LEN] = '\0';
1161
1162     return name;
1163 }
1164
1165 static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
1166 {
1167     static const GTypeInfo typeInfo = {
1168         sizeof(WebKitAccessibleClass),
1169         (GBaseInitFunc) 0,
1170         (GBaseFinalizeFunc) 0,
1171         (GClassInitFunc) 0,
1172         (GClassFinalizeFunc) 0,
1173         0, /* class data */
1174         sizeof(WebKitAccessible), /* instance size */
1175         0, /* nb preallocs */
1176         (GInstanceInitFunc) 0,
1177         0 /* value table */
1178     };
1179
1180     guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
1181     const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
1182     GType type = g_type_from_name(atkTypeName);
1183     if (type)
1184         return type;
1185
1186     type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE, atkTypeName, &typeInfo, GTypeFlags(0));
1187     for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
1188         if (interfaceMask & (1 << i))
1189             g_type_add_interface_static(type,
1190                 GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
1191                 &AtkInterfacesInitFunctions[i]);
1192     }
1193
1194     return type;
1195 }
1196
1197 WebKitAccessible* webkitAccessibleNew(AccessibilityObject* coreObject)
1198 {
1199     GType type = getAccessibilityTypeFromObject(coreObject);
1200     AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
1201
1202     atk_object_initialize(object, coreObject);
1203
1204     return WEBKIT_ACCESSIBLE(object);
1205 }
1206
1207 AccessibilityObject* webkitAccessibleGetAccessibilityObject(WebKitAccessible* accessible)
1208 {
1209     return accessible->m_object;
1210 }
1211
1212 void webkitAccessibleDetach(WebKitAccessible* accessible)
1213 {
1214     ASSERT(accessible->m_object);
1215
1216     if (accessible->m_object->roleValue() == WebAreaRole)
1217         atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, true);
1218
1219     // We replace the WebCore AccessibilityObject with a fallback object that
1220     // provides default implementations to avoid repetitive null-checking after
1221     // detachment.
1222     accessible->m_object = fallbackObject();
1223 }
1224
1225 bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
1226 {
1227     ASSERT(accessible->m_object);
1228     return accessible->m_object == fallbackObject();
1229 }
1230
1231 AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* referenceObject, int& offset)
1232 {
1233     // Indication that something bogus has transpired.
1234     offset = -1;
1235
1236     Document* document = referenceObject->document();
1237     if (!document)
1238         return 0;
1239
1240     Node* focusedNode = referenceObject->selection().end().containerNode();
1241     if (!focusedNode)
1242         return 0;
1243
1244     RenderObject* focusedRenderer = focusedNode->renderer();
1245     if (!focusedRenderer)
1246         return 0;
1247
1248     AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
1249     if (!focusedObject)
1250         return 0;
1251
1252     // Look for the actual (not ignoring accessibility) selected object.
1253     AccessibilityObject* firstUnignoredParent = focusedObject;
1254     if (firstUnignoredParent->accessibilityIsIgnored())
1255         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1256     if (!firstUnignoredParent)
1257         return 0;
1258
1259     // Don't ignore links if the offset is being requested for a link
1260     // or if the link is a block.
1261     if (!referenceObject->isLink() && firstUnignoredParent->isLink()
1262         && !(firstUnignoredParent->renderer() && !firstUnignoredParent->renderer()->isInline()))
1263         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1264     if (!firstUnignoredParent)
1265         return 0;
1266
1267     // The reference object must either coincide with the focused
1268     // object being considered, or be a descendant of it.
1269     if (referenceObject->isDescendantOfObject(firstUnignoredParent))
1270         referenceObject = firstUnignoredParent;
1271
1272     Node* startNode = nullptr;
1273     if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
1274         // We need to use the first child's node of the reference
1275         // object as the start point to calculate the caret offset
1276         // because we want it to be relative to the object of
1277         // reference, not just to the focused object (which could have
1278         // previous siblings which should be taken into account too).
1279         AccessibilityObject* axFirstChild = referenceObject->firstChild();
1280         if (axFirstChild)
1281             startNode = axFirstChild->node();
1282     }
1283     // Getting the Position of a PseudoElement now triggers an assertion.
1284     // This can occur when clicking on empty space in a render block.
1285     if (!startNode || startNode->isPseudoElement())
1286         startNode = firstUnignoredParent->node();
1287
1288     // Check if the node for the first parent object not ignoring
1289     // accessibility is null again before using it. This might happen
1290     // with certain kind of accessibility objects, such as the root
1291     // one (the scroller containing the webArea object).
1292     if (!startNode)
1293         return 0;
1294
1295     VisiblePosition startPosition = VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
1296     VisiblePosition endPosition = firstUnignoredParent->selection().visibleEnd();
1297
1298     if (startPosition == endPosition)
1299         offset = 0;
1300     else if (!isStartOfLine(endPosition)) {
1301         RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
1302         offset = TextIterator::rangeLength(range.get(), true) + 1;
1303     } else {
1304         RefPtr<Range> range = makeRange(startPosition, endPosition);
1305         offset = TextIterator::rangeLength(range.get(), true);
1306     }
1307
1308     return firstUnignoredParent;
1309 }
1310
1311 const char* cacheAndReturnAtkProperty(AtkObject* object, AtkCachedProperty property, String value)
1312 {
1313     WebKitAccessiblePrivate* priv = WEBKIT_ACCESSIBLE(object)->priv;
1314     CString* propertyPtr = nullptr;
1315
1316     switch (property) {
1317     case AtkCachedAccessibleName:
1318         propertyPtr = &priv->accessibleName;
1319         break;
1320
1321     case AtkCachedAccessibleDescription:
1322         propertyPtr = &priv->accessibleDescription;
1323         break;
1324
1325     case AtkCachedActionName:
1326         propertyPtr = &priv->actionName;
1327         break;
1328
1329     case AtkCachedActionKeyBinding:
1330         propertyPtr = &priv->actionKeyBinding;
1331         break;
1332
1333     case AtkCachedDocumentLocale:
1334         propertyPtr = &priv->documentLocale;
1335         break;
1336
1337     case AtkCachedDocumentType:
1338         propertyPtr = &priv->documentType;
1339         break;
1340
1341     case AtkCachedDocumentEncoding:
1342         propertyPtr = &priv->documentEncoding;
1343         break;
1344
1345     case AtkCachedDocumentURI:
1346         propertyPtr = &priv->documentURI;
1347         break;
1348
1349     case AtkCachedImageDescription:
1350         propertyPtr = &priv->imageDescription;
1351         break;
1352
1353     default:
1354         ASSERT_NOT_REACHED();
1355     }
1356
1357     // Don't invalidate old memory if not stricly needed, since other
1358     // callers might be still holding on to it.
1359     if (*propertyPtr != value.utf8())
1360         *propertyPtr = value.utf8();
1361
1362     return (*propertyPtr).data();
1363 }
1364
1365 #endif // HAVE(ACCESSIBILITY)