c536db6911320f82c1f4f60ed8794aa5a7da175e
[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 "AccessibilityTableCell.h"
42 #include "AccessibilityTableRow.h"
43 #include "Document.h"
44 #include "Editing.h"
45 #include "Frame.h"
46 #include "FrameView.h"
47 #include "HTMLNames.h"
48 #include "HTMLTableElement.h"
49 #include "HostWindow.h"
50 #include "RenderAncestorIterator.h"
51 #include "RenderBlock.h"
52 #include "RenderObject.h"
53 #include "SVGElement.h"
54 #include "Settings.h"
55 #include "TextIterator.h"
56 #include "VisibleUnits.h"
57 #include "WebKitAccessibleHyperlink.h"
58 #include "WebKitAccessibleInterfaceAction.h"
59 #include "WebKitAccessibleInterfaceComponent.h"
60 #include "WebKitAccessibleInterfaceDocument.h"
61 #include "WebKitAccessibleInterfaceEditableText.h"
62 #include "WebKitAccessibleInterfaceHyperlinkImpl.h"
63 #include "WebKitAccessibleInterfaceHypertext.h"
64 #include "WebKitAccessibleInterfaceImage.h"
65 #include "WebKitAccessibleInterfaceSelection.h"
66 #include "WebKitAccessibleInterfaceTable.h"
67 #include "WebKitAccessibleInterfaceTableCell.h"
68 #include "WebKitAccessibleInterfaceText.h"
69 #include "WebKitAccessibleInterfaceValue.h"
70 #include "WebKitAccessibleUtil.h"
71 #include <glib/gprintf.h>
72 #include <wtf/text/CString.h>
73
74 using namespace WebCore;
75
76 struct _WebKitAccessiblePrivate {
77     // Cached data for AtkObject.
78     CString accessibleName;
79     CString accessibleDescription;
80
81     // Cached data for AtkAction.
82     CString actionName;
83     CString actionKeyBinding;
84
85     // Cached data for AtkDocument.
86     CString documentLocale;
87     CString documentType;
88     CString documentEncoding;
89     CString documentURI;
90
91     // Cached data for AtkImage.
92     CString imageDescription;
93 };
94
95 #define WEBKIT_ACCESSIBLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessiblePrivate))
96
97 static AccessibilityObject* fallbackObject()
98 {
99     static AccessibilityObject* object = &AccessibilityListBoxOption::create().leakRef();
100     return object;
101 }
102
103 static AccessibilityObject* core(AtkObject* object)
104 {
105     if (!WEBKIT_IS_ACCESSIBLE(object))
106         return 0;
107
108     return webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(object));
109 }
110
111 static const gchar* webkitAccessibleGetName(AtkObject* object)
112 {
113     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
114     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
115
116     Vector<AccessibilityText> textOrder;
117     core(object)->accessibilityText(textOrder);
118
119     for (const auto& text : textOrder) {
120         // FIXME: This check is here because AccessibilityNodeObject::titleElementText()
121         // appends an empty String for the LabelByElementText source when there is a
122         // titleUIElement(). Removing this check makes some fieldsets lose their name.
123         if (text.text.isEmpty())
124             continue;
125
126         // WebCore Accessibility should provide us with the text alternative computation
127         // in the order defined by that spec. So take the first thing that our platform
128         // does not expose via the AtkObject description.
129         if (text.textSource != HelpText && text.textSource != SummaryText)
130             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, text.text);
131     }
132
133     return cacheAndReturnAtkProperty(object, AtkCachedAccessibleName, "");
134 }
135
136 static const gchar* webkitAccessibleGetDescription(AtkObject* object)
137 {
138     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
139     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
140
141     Vector<AccessibilityText> textOrder;
142     core(object)->accessibilityText(textOrder);
143
144     bool nameTextAvailable = false;
145     for (const auto& text : textOrder) {
146         // WebCore Accessibility should provide us with the text alternative computation
147         // in the order defined by that spec. So take the first thing that our platform
148         // does not expose via the AtkObject name.
149         if (text.textSource == HelpText || text.textSource == SummaryText)
150             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
151
152         // If there is no other text alternative, the title tag contents will have been
153         // used for the AtkObject name. We don't want to duplicate it here.
154         if (text.textSource == TitleTagText && nameTextAvailable)
155             return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, text.text);
156
157         nameTextAvailable = true;
158     }
159
160     return cacheAndReturnAtkProperty(object, AtkCachedAccessibleDescription, "");
161 }
162
163 static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType)
164 {
165     int count = atk_relation_set_get_n_relations(relationSet);
166     for (int i = 0; i < count; i++) {
167         AtkRelation* relation = atk_relation_set_get_relation(relationSet, i);
168         if (atk_relation_get_relation_type(relation) == relationType) {
169             atk_relation_set_remove(relationSet, relation);
170             break;
171         }
172     }
173 }
174
175 static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
176 {
177     // Elements with aria-labelledby should have the labelled-by relation as per the ARIA AAM spec.
178     // Controls with a label element and fieldsets with a legend element should also use this relation
179     // as per the HTML AAM spec. The reciprocal label-for relation should also be used.
180     removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
181     removeAtkRelationByType(relationSet, ATK_RELATION_LABEL_FOR);
182     if (coreObject->isControl()) {
183         if (AccessibilityObject* label = coreObject->correspondingLabelForControlElement())
184             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
185     } else if (coreObject->isFieldset()) {
186         if (AccessibilityObject* label = coreObject->titleUIElement())
187             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, label->wrapper());
188     } else if (coreObject->roleValue() == LegendRole) {
189         if (RenderBlock* renderFieldset = ancestorsOfType<RenderBlock>(*coreObject->renderer()).first()) {
190             if (renderFieldset->isFieldset()) {
191                 AccessibilityObject* fieldset = coreObject->axObjectCache()->getOrCreate(renderFieldset);
192                 atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, fieldset->wrapper());
193             }
194         }
195     } else if (AccessibilityObject* control = coreObject->correspondingControlForLabelElement()) {
196         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, control->wrapper());
197     } else {
198         AccessibilityObject::AccessibilityChildrenVector ariaLabelledByElements;
199         coreObject->ariaLabelledByElements(ariaLabelledByElements);
200         for (const auto& accessibilityObject : ariaLabelledByElements)
201             atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, accessibilityObject->wrapper());
202     }
203
204     // Elements referenced by aria-labelledby should have the label-for relation as per the ARIA AAM spec.
205     AccessibilityObject::AccessibilityChildrenVector labels;
206     coreObject->ariaLabelledByReferencingElements(labels);
207     for (const auto& accessibilityObject : labels)
208         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, accessibilityObject->wrapper());
209
210     // Elements with aria-flowto should have the flows-to relation as per the ARIA AAM spec.
211     removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
212     AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
213     coreObject->ariaFlowToElements(ariaFlowToElements);
214     for (const auto& accessibilityObject : ariaFlowToElements)
215         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, accessibilityObject->wrapper());
216
217     // Elements referenced by aria-flowto should have the flows-from relation as per the ARIA AAM spec.
218     removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_FROM);
219     AccessibilityObject::AccessibilityChildrenVector flowFrom;
220     coreObject->ariaFlowToReferencingElements(flowFrom);
221     for (const auto& accessibilityObject : flowFrom)
222         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_FROM, accessibilityObject->wrapper());
223
224     // Elements with aria-describedby should have the described-by relation as per the ARIA AAM spec.
225     removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIBED_BY);
226     AccessibilityObject::AccessibilityChildrenVector ariaDescribedByElements;
227     coreObject->ariaDescribedByElements(ariaDescribedByElements);
228     for (const auto& accessibilityObject : ariaDescribedByElements)
229         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY, accessibilityObject->wrapper());
230
231     // Elements referenced by aria-describedby should have the description-for relation as per the ARIA AAM spec.
232     removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIPTION_FOR);
233     AccessibilityObject::AccessibilityChildrenVector describers;
234     coreObject->ariaDescribedByReferencingElements(describers);
235     for (const auto& accessibilityObject : describers)
236         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIPTION_FOR, accessibilityObject->wrapper());
237
238     // Elements with aria-controls should have the controller-for relation as per the ARIA AAM spec.
239     removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLER_FOR);
240     AccessibilityObject::AccessibilityChildrenVector ariaControls;
241     coreObject->ariaControlsElements(ariaControls);
242     for (const auto& accessibilityObject : ariaControls)
243         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLER_FOR, accessibilityObject->wrapper());
244
245     // Elements referenced by aria-controls should have the controlled-by relation as per the ARIA AAM spec.
246     removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLED_BY);
247     AccessibilityObject::AccessibilityChildrenVector controllers;
248     coreObject->ariaControlsReferencingElements(controllers);
249     for (const auto& accessibilityObject : controllers)
250         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLED_BY, accessibilityObject->wrapper());
251
252     // Elements with aria-owns should have the node-parent-of relation as per the ARIA AAM spec.
253     removeAtkRelationByType(relationSet, ATK_RELATION_NODE_PARENT_OF);
254     AccessibilityObject::AccessibilityChildrenVector ariaOwns;
255     coreObject->ariaOwnsElements(ariaOwns);
256     for (const auto& accessibilityObject : ariaOwns)
257         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_NODE_PARENT_OF, accessibilityObject->wrapper());
258
259     // Elements referenced by aria-owns should have the node-child-of relation as per the ARIA AAM spec.
260     removeAtkRelationByType(relationSet, ATK_RELATION_NODE_CHILD_OF);
261     AccessibilityObject::AccessibilityChildrenVector owners;
262     coreObject->ariaOwnsReferencingElements(owners);
263     for (const auto& accessibilityObject : owners)
264         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_NODE_CHILD_OF, accessibilityObject->wrapper());
265
266 #if ATK_CHECK_VERSION(2, 25, 2)
267     // Elements with aria-details should have the details relation as per the ARIA AAM spec.
268     removeAtkRelationByType(relationSet, ATK_RELATION_DETAILS);
269     AccessibilityObject::AccessibilityChildrenVector ariaDetails;
270     coreObject->ariaDetailsElements(ariaDetails);
271     for (const auto& accessibilityObject : ariaDetails)
272         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DETAILS, accessibilityObject->wrapper());
273
274     // Elements referenced by aria-details should have the details-for relation as per the ARIA AAM spec.
275     removeAtkRelationByType(relationSet, ATK_RELATION_DETAILS_FOR);
276     AccessibilityObject::AccessibilityChildrenVector details;
277     coreObject->ariaDetailsReferencingElements(details);
278     for (const auto& accessibilityObject : details)
279         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DETAILS_FOR, accessibilityObject->wrapper());
280
281     // Elements with aria-errormessage should have the error-message relation as per the ARIA AAM spec.
282     removeAtkRelationByType(relationSet, ATK_RELATION_ERROR_MESSAGE);
283     AccessibilityObject::AccessibilityChildrenVector ariaErrorMessage;
284     coreObject->ariaErrorMessageElements(ariaErrorMessage);
285     for (const auto& accessibilityObject : ariaErrorMessage)
286         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_ERROR_MESSAGE, accessibilityObject->wrapper());
287
288     // Elements referenced by aria-errormessage should have the error-for relation as per the ARIA AAM spec.
289     removeAtkRelationByType(relationSet, ATK_RELATION_ERROR_FOR);
290     AccessibilityObject::AccessibilityChildrenVector errors;
291     coreObject->ariaErrorMessageReferencingElements(errors);
292     for (const auto& accessibilityObject : errors)
293         atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_ERROR_FOR, accessibilityObject->wrapper());
294 #endif
295 }
296
297 static gpointer webkitAccessibleParentClass = nullptr;
298
299 static bool isRootObject(AccessibilityObject* coreObject)
300 {
301     // The root accessible object in WebCore is always an object with
302     // the ScrolledArea role with one child with the WebArea role.
303     if (!coreObject || !coreObject->isScrollView())
304         return false;
305
306     AccessibilityObject* firstChild = coreObject->firstChild();
307     if (!firstChild || !firstChild->isWebArea())
308         return false;
309
310     return true;
311 }
312
313 static AtkObject* atkParentOfRootObject(AtkObject* object)
314 {
315     AccessibilityObject* coreObject = core(object);
316     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
317
318     // The top level object claims to not have a parent. This makes it
319     // impossible for assistive technologies to ascend the accessible
320     // hierarchy all the way to the application. (Bug 30489)
321     if (!coreParent && isRootObject(coreObject)) {
322         Document* document = coreObject->document();
323         if (!document)
324             return 0;
325     }
326
327     if (!coreParent)
328         return 0;
329
330     return coreParent->wrapper();
331 }
332
333 static AtkObject* webkitAccessibleGetParent(AtkObject* object)
334 {
335     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
336     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
337
338     // Check first if the parent has been already set.
339     AtkObject* accessibleParent = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->get_parent(object);
340     if (accessibleParent)
341         return accessibleParent;
342
343     // Parent not set yet, so try to find it in the hierarchy.
344     AccessibilityObject* coreObject = core(object);
345     if (!coreObject)
346         return 0;
347
348     AccessibilityObject* coreParent = coreObject->parentObjectUnignored();
349
350     if (!coreParent && isRootObject(coreObject))
351         return atkParentOfRootObject(object);
352
353     if (!coreParent)
354         return 0;
355
356     return coreParent->wrapper();
357 }
358
359 static gint webkitAccessibleGetNChildren(AtkObject* object)
360 {
361     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
362     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
363
364     AccessibilityObject* coreObject = core(object);
365
366     return coreObject->children().size();
367 }
368
369 static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
370 {
371     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
372     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
373
374     if (index < 0)
375         return 0;
376
377     AccessibilityObject* coreObject = core(object);
378     AccessibilityObject* coreChild = nullptr;
379
380     const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
381     if (static_cast<size_t>(index) >= children.size())
382         return 0;
383     coreChild = children.at(index).get();
384
385     if (!coreChild)
386         return 0;
387
388     AtkObject* child = coreChild->wrapper();
389     atk_object_set_parent(child, object);
390     g_object_ref(child);
391
392     return child;
393 }
394
395 static gint webkitAccessibleGetIndexInParent(AtkObject* object)
396 {
397     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), -1);
398     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), -1);
399
400     AccessibilityObject* coreObject = core(object);
401     AccessibilityObject* parent = coreObject->parentObjectUnignored();
402
403     if (!parent && isRootObject(coreObject)) {
404         AtkObject* atkParent = atkParentOfRootObject(object);
405         if (!atkParent)
406             return -1;
407
408         unsigned count = atk_object_get_n_accessible_children(atkParent);
409         for (unsigned i = 0; i < count; ++i) {
410             AtkObject* child = atk_object_ref_accessible_child(atkParent, i);
411             bool childIsObject = child == object;
412             g_object_unref(child);
413             if (childIsObject)
414                 return i;
415         }
416     }
417
418     if (!parent)
419         return -1;
420
421     size_t index = parent->children().find(coreObject);
422     return (index == WTF::notFound) ? -1 : index;
423 }
424
425 static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
426 {
427     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
428     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
429
430     AtkAttributeSet* attributeSet = nullptr;
431 #if PLATFORM(GTK)
432     attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
433 #endif
434
435     AccessibilityObject* coreObject = core(object);
436     if (!coreObject)
437         return attributeSet;
438
439     // Hack needed for WebKit2 tests because obtaining an element by its ID
440     // cannot be done from the UIProcess. Assistive technologies have no need
441     // for this information.
442     Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
443     if (element) {
444         String tagName = element->tagName();
445         if (!tagName.isEmpty())
446             attributeSet = addToAtkAttributeSet(attributeSet, "tag", tagName.convertToASCIILowercase().utf8().data());
447         String id = element->getIdAttribute().string();
448         if (!id.isEmpty())
449             attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
450     }
451
452     int level = coreObject->isHeading() ? coreObject->headingLevel() : coreObject->hierarchicalLevel();
453     if (level) {
454         String value = String::number(level);
455         attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
456     }
457
458     if (coreObject->roleValue() == MathElementRole) {
459         if (coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PreSubscript))
460             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
461         else if (coreObject->isMathMultiscriptObject(PostSuperscript) || coreObject->isMathMultiscriptObject(PostSubscript))
462             attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
463     }
464
465     if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposableThroughAccessibility()) {
466         auto& table = downcast<AccessibilityTable>(*coreObject);
467         int rowCount = table.ariaRowCount();
468         if (rowCount)
469             attributeSet = addToAtkAttributeSet(attributeSet, "rowcount", String::number(rowCount).utf8().data());
470
471         int columnCount = table.ariaColumnCount();
472         if (columnCount)
473             attributeSet = addToAtkAttributeSet(attributeSet, "colcount", String::number(columnCount).utf8().data());
474     } else if (is<AccessibilityTableRow>(*coreObject)) {
475         auto& row = downcast<AccessibilityTableRow>(*coreObject);
476         int rowIndex = row.ariaRowIndex();
477         if (rowIndex != -1)
478             attributeSet = addToAtkAttributeSet(attributeSet, "rowindex", String::number(rowIndex).utf8().data());
479     } else if (is<AccessibilityTableCell>(*coreObject)) {
480         auto& cell = downcast<AccessibilityTableCell>(*coreObject);
481         int rowIndex = cell.ariaRowIndex();
482         if (rowIndex != -1)
483             attributeSet = addToAtkAttributeSet(attributeSet, "rowindex", String::number(rowIndex).utf8().data());
484
485         int columnIndex = cell.ariaColumnIndex();
486         if (columnIndex != -1)
487             attributeSet = addToAtkAttributeSet(attributeSet, "colindex", String::number(columnIndex).utf8().data());
488
489         int rowSpan = cell.ariaRowSpan();
490         if (rowSpan != -1)
491             attributeSet = addToAtkAttributeSet(attributeSet, "rowspan", String::number(rowSpan).utf8().data());
492
493         int columnSpan = cell.ariaColumnSpan();
494         if (columnSpan != -1)
495             attributeSet = addToAtkAttributeSet(attributeSet, "colspan", String::number(columnSpan).utf8().data());
496     }
497
498     String placeholder = coreObject->placeholderValue();
499     if (!placeholder.isEmpty())
500         attributeSet = addToAtkAttributeSet(attributeSet, "placeholder-text", placeholder.utf8().data());
501
502     if (coreObject->supportsARIAAutoComplete())
503         attributeSet = addToAtkAttributeSet(attributeSet, "autocomplete", coreObject->ariaAutoCompleteValue().utf8().data());
504
505     if (coreObject->supportsARIAHasPopup())
506         attributeSet = addToAtkAttributeSet(attributeSet, "haspopup", coreObject->ariaPopupValue().utf8().data());
507
508     if (coreObject->supportsARIACurrent())
509         attributeSet = addToAtkAttributeSet(attributeSet, "current", coreObject->ariaCurrentValue().utf8().data());
510
511     // The Core AAM states that an explicitly-set value should be exposed, including "none".
512     if (coreObject->hasAttribute(HTMLNames::aria_sortAttr)) {
513         switch (coreObject->sortDirection()) {
514         case SortDirectionInvalid:
515             break;
516         case SortDirectionAscending:
517             attributeSet = addToAtkAttributeSet(attributeSet, "sort", "ascending");
518             break;
519         case SortDirectionDescending:
520             attributeSet = addToAtkAttributeSet(attributeSet, "sort", "descending");
521             break;
522         case SortDirectionOther:
523             attributeSet = addToAtkAttributeSet(attributeSet, "sort", "other");
524             break;
525         default:
526             attributeSet = addToAtkAttributeSet(attributeSet, "sort", "none");
527         }
528     }
529
530     if (coreObject->supportsARIAPosInSet())
531         attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->ariaPosInSet()).utf8().data());
532
533     if (coreObject->supportsARIASetSize())
534         attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->ariaSetSize()).utf8().data());
535
536     String isReadOnly = coreObject->ariaReadOnlyValue();
537     if (!isReadOnly.isEmpty())
538         attributeSet = addToAtkAttributeSet(attributeSet, "readonly", isReadOnly.utf8().data());
539
540     String valueDescription = coreObject->valueDescription();
541     if (!valueDescription.isEmpty())
542         attributeSet = addToAtkAttributeSet(attributeSet, "valuetext", valueDescription.utf8().data());
543
544     // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
545     // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
546     // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
547     // We cannot use the computedRoleString for this purpose because it is not limited to elements
548     // with ARIA roles, and it might not contain the actual ARIA role value (e.g. DPub ARIA).
549     String roleString = coreObject->getAttribute(HTMLNames::roleAttr);
550     if (!roleString.isEmpty())
551         attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", roleString.utf8().data());
552
553     String computedRoleString = coreObject->computedRoleString();
554     if (!computedRoleString.isEmpty()) {
555         attributeSet = addToAtkAttributeSet(attributeSet, "computed-role", computedRoleString.utf8().data());
556
557         // The HTML AAM maps several elements to ARIA landmark roles. In order for the type of landmark
558         // to be obtainable in the same fashion as an ARIA landmark, fall back on the computedRoleString.
559         if (coreObject->ariaRoleAttribute() == UnknownRole && coreObject->isLandmark())
560             attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", computedRoleString.utf8().data());
561     }
562
563     String roleDescription = coreObject->roleDescription();
564     if (!roleDescription.isEmpty())
565         attributeSet = addToAtkAttributeSet(attributeSet, "roledescription", roleDescription.utf8().data());
566
567     // We need to expose the live region attributes even if the live region is currently disabled/off.
568     if (auto liveContainer = coreObject->ariaLiveRegionAncestor(false)) {
569         String liveStatus = liveContainer->ariaLiveRegionStatus();
570         String relevant = liveContainer->ariaLiveRegionRelevant();
571         bool isAtomic = liveContainer->ariaLiveRegionAtomic();
572         String liveRole = roleString.isEmpty() ? computedRoleString : roleString;
573
574         // According to the Core AAM, we need to expose the above properties with "container-" prefixed
575         // object attributes regardless of whether the container is this object, or an ancestor of it.
576         attributeSet = addToAtkAttributeSet(attributeSet, "container-live", liveStatus.utf8().data());
577         attributeSet = addToAtkAttributeSet(attributeSet, "container-relevant", relevant.utf8().data());
578         if (isAtomic)
579             attributeSet = addToAtkAttributeSet(attributeSet, "container-atomic", "true");
580         if (!liveRole.isEmpty())
581             attributeSet = addToAtkAttributeSet(attributeSet, "container-live-role", liveRole.utf8().data());
582
583         // According to the Core AAM, if this object is the live region (rather than its descendant),
584         // we must expose the above properties on the object without a "container-" prefix.
585         if (liveContainer == coreObject) {
586             attributeSet = addToAtkAttributeSet(attributeSet, "live", liveStatus.utf8().data());
587             attributeSet = addToAtkAttributeSet(attributeSet, "relevant", relevant.utf8().data());
588             if (isAtomic)
589                 attributeSet = addToAtkAttributeSet(attributeSet, "atomic", "true");
590         } else if (!isAtomic && coreObject->ariaLiveRegionAtomic())
591             attributeSet = addToAtkAttributeSet(attributeSet, "atomic", "true");
592     }
593
594     // The Core AAM states the author-provided value should be exposed as-is.
595     String dropEffect = coreObject->getAttribute(HTMLNames::aria_dropeffectAttr);
596     if (!dropEffect.isEmpty())
597         attributeSet = addToAtkAttributeSet(attributeSet, "dropeffect", dropEffect.utf8().data());
598
599     if (coreObject->isARIAGrabbed())
600         attributeSet = addToAtkAttributeSet(attributeSet, "grabbed", "true");
601     else if (coreObject->supportsARIADragging())
602         attributeSet = addToAtkAttributeSet(attributeSet, "grabbed", "false");
603
604     return attributeSet;
605 }
606
607 static AtkRole atkRole(AccessibilityObject* coreObject)
608 {
609     AccessibilityRole role = coreObject->roleValue();
610     switch (role) {
611     case ApplicationAlertRole:
612         return ATK_ROLE_ALERT;
613     case ApplicationAlertDialogRole:
614     case ApplicationDialogRole:
615         return ATK_ROLE_DIALOG;
616     case ApplicationStatusRole:
617         return ATK_ROLE_STATUSBAR;
618     case UnknownRole:
619         return ATK_ROLE_UNKNOWN;
620     case AudioRole:
621 #if ATK_CHECK_VERSION(2, 11, 3)
622         return ATK_ROLE_AUDIO;
623 #endif
624     case VideoRole:
625 #if ATK_CHECK_VERSION(2, 11, 3)
626         return ATK_ROLE_VIDEO;
627 #endif
628         return ATK_ROLE_EMBEDDED;
629     case ButtonRole:
630         return ATK_ROLE_PUSH_BUTTON;
631     case SwitchRole:
632     case ToggleButtonRole:
633         return ATK_ROLE_TOGGLE_BUTTON;
634     case RadioButtonRole:
635         return ATK_ROLE_RADIO_BUTTON;
636     case CheckBoxRole:
637         return ATK_ROLE_CHECK_BOX;
638     case SliderRole:
639         return ATK_ROLE_SLIDER;
640     case TabGroupRole:
641     case TabListRole:
642         return ATK_ROLE_PAGE_TAB_LIST;
643     case TextFieldRole:
644     case TextAreaRole:
645     case SearchFieldRole:
646         return ATK_ROLE_ENTRY;
647     case StaticTextRole:
648 #if ATK_CHECK_VERSION(2, 15, 2)
649         return ATK_ROLE_STATIC;
650 #else
651         return ATK_ROLE_TEXT;
652 #endif
653     case OutlineRole:
654     case TreeRole:
655         return ATK_ROLE_TREE;
656     case TreeItemRole:
657         return ATK_ROLE_TREE_ITEM;
658     case MenuBarRole:
659         return ATK_ROLE_MENU_BAR;
660     case MenuListPopupRole:
661     case MenuRole:
662         return ATK_ROLE_MENU;
663     case MenuListOptionRole:
664     case MenuItemRole:
665     case MenuButtonRole:
666         return ATK_ROLE_MENU_ITEM;
667     case MenuItemCheckboxRole:
668         return ATK_ROLE_CHECK_MENU_ITEM;
669     case MenuItemRadioRole:
670         return ATK_ROLE_RADIO_MENU_ITEM;
671     case ColumnRole:
672         // return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
673         return ATK_ROLE_UNKNOWN; // Matches Mozilla
674     case RowRole:
675         return ATK_ROLE_TABLE_ROW;
676     case ToolbarRole:
677         return ATK_ROLE_TOOL_BAR;
678     case BusyIndicatorRole:
679         return ATK_ROLE_PROGRESS_BAR; // Is this right?
680     case ProgressIndicatorRole:
681         return coreObject->isMeter() ? ATK_ROLE_LEVEL_BAR : ATK_ROLE_PROGRESS_BAR;
682     case WindowRole:
683         return ATK_ROLE_WINDOW;
684     case PopUpButtonRole:
685         return coreObject->ariaHasPopup() ? ATK_ROLE_PUSH_BUTTON : ATK_ROLE_COMBO_BOX;
686     case ComboBoxRole:
687         return ATK_ROLE_COMBO_BOX;
688     case SplitGroupRole:
689         return ATK_ROLE_SPLIT_PANE;
690     case SplitterRole:
691         return ATK_ROLE_SEPARATOR;
692     case ColorWellRole:
693 #if PLATFORM(GTK)
694         // ATK_ROLE_COLOR_CHOOSER is defined as a dialog (i.e. it's what appears when you push the button).
695         return ATK_ROLE_PUSH_BUTTON;
696 #endif
697     case ListRole:
698         return ATK_ROLE_LIST;
699     case ScrollBarRole:
700         return ATK_ROLE_SCROLL_BAR;
701     case ScrollAreaRole:
702     case TabPanelRole:
703         return ATK_ROLE_SCROLL_PANE;
704     case GridRole:
705     case TableRole:
706         return ATK_ROLE_TABLE;
707     case TreeGridRole:
708         return ATK_ROLE_TREE_TABLE;
709     case ApplicationRole:
710         return ATK_ROLE_APPLICATION;
711     case ApplicationGroupRole:
712     case FeedRole:
713     case FigureRole:
714     case GroupRole:
715     case RadioGroupRole:
716     case SVGRootRole:
717         return ATK_ROLE_PANEL;
718     case RowHeaderRole:
719         return ATK_ROLE_ROW_HEADER;
720     case ColumnHeaderRole:
721         return ATK_ROLE_COLUMN_HEADER;
722     case CaptionRole:
723         return ATK_ROLE_CAPTION;
724     case CellRole:
725     case GridCellRole:
726         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
727     case LinkRole:
728     case WebCoreLinkRole:
729     case ImageMapLinkRole:
730         return ATK_ROLE_LINK;
731     case ImageMapRole:
732         return ATK_ROLE_IMAGE_MAP;
733     case ImageRole:
734         return ATK_ROLE_IMAGE;
735     case ListMarkerRole:
736         return ATK_ROLE_TEXT;
737     case DocumentArticleRole:
738 #if ATK_CHECK_VERSION(2, 11, 3)
739         return ATK_ROLE_ARTICLE;
740 #endif
741     case DocumentRole:
742         return ATK_ROLE_DOCUMENT_FRAME;
743     case DocumentNoteRole:
744         return ATK_ROLE_COMMENT;
745     case HeadingRole:
746         return ATK_ROLE_HEADING;
747     case ListBoxRole:
748         // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-listbox
749         return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU : ATK_ROLE_LIST_BOX;
750     case ListItemRole:
751         return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
752     case ListBoxOptionRole:
753         return coreObject->isDescendantOfRole(ComboBoxRole) ? ATK_ROLE_MENU_ITEM : ATK_ROLE_LIST_ITEM;
754     case ParagraphRole:
755         return ATK_ROLE_PARAGRAPH;
756     case LabelRole:
757     case LegendRole:
758         return ATK_ROLE_LABEL;
759     case BlockquoteRole:
760 #if ATK_CHECK_VERSION(2, 11, 3)
761         return ATK_ROLE_BLOCK_QUOTE;
762 #endif
763     case FootnoteRole:
764 #if ATK_CHECK_VERSION(2, 25, 2)
765         return ATK_ROLE_FOOTNOTE;
766 #endif
767     case ApplicationTextGroupRole:
768     case DivRole:
769     case PreRole:
770     case SVGTextRole:
771     case TextGroupRole:
772         return ATK_ROLE_SECTION;
773     case FooterRole:
774         return ATK_ROLE_FOOTER;
775     case FormRole:
776         return ATK_ROLE_FORM;
777     case CanvasRole:
778         return ATK_ROLE_CANVAS;
779     case HorizontalRuleRole:
780         return ATK_ROLE_SEPARATOR;
781     case SpinButtonRole:
782         return ATK_ROLE_SPIN_BUTTON;
783     case TabRole:
784         return ATK_ROLE_PAGE_TAB;
785     case UserInterfaceTooltipRole:
786         return ATK_ROLE_TOOL_TIP;
787     case WebAreaRole:
788         return ATK_ROLE_DOCUMENT_WEB;
789     case WebApplicationRole:
790         return ATK_ROLE_EMBEDDED;
791 #if ATK_CHECK_VERSION(2, 11, 3)
792     case ApplicationLogRole:
793         return ATK_ROLE_LOG;
794     case ApplicationMarqueeRole:
795         return ATK_ROLE_MARQUEE;
796     case ApplicationTimerRole:
797         return ATK_ROLE_TIMER;
798     case DefinitionRole:
799         return ATK_ROLE_DEFINITION;
800     case DocumentMathRole:
801         return ATK_ROLE_MATH;
802     case MathElementRole:
803         if (coreObject->isMathRow())
804             return ATK_ROLE_PANEL;
805         if (coreObject->isMathTable())
806             return ATK_ROLE_TABLE;
807         if (coreObject->isMathTableRow())
808             return ATK_ROLE_TABLE_ROW;
809         if (coreObject->isMathTableCell())
810             return ATK_ROLE_TABLE_CELL;
811         if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
812             return ATK_ROLE_SECTION;
813 #if ATK_CHECK_VERSION(2, 15, 4)
814         if (coreObject->isMathFraction())
815             return ATK_ROLE_MATH_FRACTION;
816         if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
817             return ATK_ROLE_MATH_ROOT;
818         if (coreObject->isMathScriptObject(Subscript)
819             || coreObject->isMathMultiscriptObject(PreSubscript) || coreObject->isMathMultiscriptObject(PostSubscript))
820             return ATK_ROLE_SUBSCRIPT;
821         if (coreObject->isMathScriptObject(Superscript)
822             || coreObject->isMathMultiscriptObject(PreSuperscript) || coreObject->isMathMultiscriptObject(PostSuperscript))
823             return ATK_ROLE_SUPERSCRIPT;
824 #endif
825 #if ATK_CHECK_VERSION(2, 15, 2)
826         if (coreObject->isMathToken())
827             return ATK_ROLE_STATIC;
828 #endif
829         return ATK_ROLE_UNKNOWN;
830     case LandmarkBannerRole:
831     case LandmarkComplementaryRole:
832     case LandmarkContentInfoRole:
833     case LandmarkDocRegionRole:
834     case LandmarkMainRole:
835     case LandmarkNavigationRole:
836     case LandmarkRegionRole:
837     case LandmarkSearchRole:
838         return ATK_ROLE_LANDMARK;
839 #endif
840 #if ATK_CHECK_VERSION(2, 11, 4)
841     case DescriptionListRole:
842         return ATK_ROLE_DESCRIPTION_LIST;
843     case TermRole:
844     case DescriptionListTermRole:
845         return ATK_ROLE_DESCRIPTION_TERM;
846     case DescriptionListDetailRole:
847         return ATK_ROLE_DESCRIPTION_VALUE;
848 #endif
849     case InlineRole:
850 #if ATK_CHECK_VERSION(2, 15, 4)
851         if (coreObject->isSubscriptStyleGroup())
852             return ATK_ROLE_SUBSCRIPT;
853         if (coreObject->isSuperscriptStyleGroup())
854             return ATK_ROLE_SUPERSCRIPT;
855 #endif
856 #if ATK_CHECK_VERSION(2, 15, 2)
857         return ATK_ROLE_STATIC;
858     case SVGTextPathRole:
859     case SVGTSpanRole:
860     case TimeRole:
861         return ATK_ROLE_STATIC;
862 #endif
863     default:
864         return ATK_ROLE_UNKNOWN;
865     }
866 }
867
868 static AtkRole webkitAccessibleGetRole(AtkObject* object)
869 {
870     // ATK_ROLE_UNKNOWN should only be applied in cases where there is a valid
871     // WebCore accessible object for which the platform role mapping is unknown.
872     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), ATK_ROLE_INVALID);
873     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), ATK_ROLE_INVALID);
874
875     AccessibilityObject* coreObject = core(object);
876
877     if (!coreObject)
878         return ATK_ROLE_INVALID;
879
880     // Note: Why doesn't WebCore have a password field for this
881     if (coreObject->isPasswordField())
882         return ATK_ROLE_PASSWORD_TEXT;
883
884     return atkRole(coreObject);
885 }
886
887 static bool isTextWithCaret(AccessibilityObject* coreObject)
888 {
889     if (!coreObject || !coreObject->isAccessibilityRenderObject())
890         return false;
891
892     Document* document = coreObject->document();
893     if (!document)
894         return false;
895
896     Frame* frame = document->frame();
897     if (!frame)
898         return false;
899
900     if (!frame->settings().caretBrowsingEnabled())
901         return false;
902
903     // Check text objects and paragraphs only.
904     AtkObject* axObject = coreObject->wrapper();
905     AtkRole role = axObject ? atk_object_get_role(axObject) : ATK_ROLE_INVALID;
906     if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
907         return false;
908
909     // Finally, check whether the caret is set in the current object.
910     VisibleSelection selection = coreObject->selection();
911     if (!selection.isCaret())
912         return false;
913
914     return selectionBelongsToObject(coreObject, selection);
915 }
916
917 static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
918 {
919     AccessibilityObject* parent = coreObject->parentObject();
920     bool isListBoxOption = parent && parent->isListBox();
921
922     // Please keep the state list in alphabetical order
923     if ((isListBoxOption && coreObject->isSelectedOptionActive())
924         || coreObject->ariaCurrentState() != ARIACurrentFalse)
925         atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
926
927     if (coreObject->isBusy())
928         atk_state_set_add_state(stateSet, ATK_STATE_BUSY);
929
930 #if ATK_CHECK_VERSION(2,11,2)
931     if (coreObject->supportsChecked() && coreObject->canSetValueAttribute())
932         atk_state_set_add_state(stateSet, ATK_STATE_CHECKABLE);
933 #endif
934
935     if (coreObject->isChecked())
936         atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
937
938     if ((coreObject->isTextControl() || coreObject->isNonNativeTextControl()) && coreObject->canSetValueAttribute())
939         atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
940
941     // FIXME: Put both ENABLED and SENSITIVE together here for now
942     if (coreObject->isEnabled()) {
943         atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
944         atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
945     }
946
947     if (coreObject->canSetExpandedAttribute())
948         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
949
950     if (coreObject->isExpanded())
951         atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
952
953     if (coreObject->canSetFocusAttribute())
954         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
955
956     if (coreObject->isFocused() || isTextWithCaret(coreObject))
957         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
958
959     if (coreObject->orientation() == AccessibilityOrientationHorizontal)
960         atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);
961     else if (coreObject->orientation() == AccessibilityOrientationVertical)
962         atk_state_set_add_state(stateSet, ATK_STATE_VERTICAL);
963
964     if (coreObject->ariaHasPopup())
965         atk_state_set_add_state(stateSet, ATK_STATE_HAS_POPUP);
966
967     if (coreObject->isIndeterminate())
968         atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
969     else if (coreObject->isCheckboxOrRadio() || coreObject->isMenuItem() || coreObject->isToggleButton()) {
970         if (coreObject->checkboxOrRadioValue() == ButtonStateMixed)
971             atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
972     }
973
974     if (coreObject->isAriaModalNode())
975         atk_state_set_add_state(stateSet, ATK_STATE_MODAL);
976
977     if (coreObject->invalidStatus() != "false")
978         atk_state_set_add_state(stateSet, ATK_STATE_INVALID_ENTRY);
979
980     if (coreObject->isMultiSelectable())
981         atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
982
983     // TODO: ATK_STATE_OPAQUE
984
985     if (coreObject->isPressed())
986         atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
987
988 #if ATK_CHECK_VERSION(2,15,3)
989     if (!coreObject->canSetValueAttribute() && (coreObject->supportsARIAReadOnly()))
990         atk_state_set_add_state(stateSet, ATK_STATE_READ_ONLY);
991 #endif
992
993     if (coreObject->isRequired())
994         atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
995
996     // TODO: ATK_STATE_SELECTABLE_TEXT
997
998     if (coreObject->canSetSelectedAttribute()) {
999         atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
1000         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
1001         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on
1002         // the former.
1003         if (isListBoxOption)
1004             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
1005     }
1006
1007     if (coreObject->isSelected()) {
1008         atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
1009         // Items in focusable lists have both STATE_SELECT{ABLE,ED}
1010         // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
1011         // former.
1012         if (isListBoxOption)
1013             atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
1014     }
1015
1016     // FIXME: Group both SHOWING and VISIBLE here for now
1017     // Not sure how to handle this in WebKit, see bug
1018     // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
1019     // issues with SHOWING vs VISIBLE.
1020     if (!coreObject->isOffScreen()) {
1021         atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
1022         atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
1023     }
1024
1025     // Mutually exclusive, so we group these two
1026     if (coreObject->roleValue() == TextAreaRole || coreObject->ariaIsMultiline())
1027         atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
1028     else if (coreObject->roleValue() == TextFieldRole || coreObject->roleValue() == SearchFieldRole)
1029         atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
1030
1031     // TODO: ATK_STATE_SENSITIVE
1032
1033     if (coreObject->supportsARIAAutoComplete() && coreObject->ariaAutoCompleteValue() != "none")
1034         atk_state_set_add_state(stateSet, ATK_STATE_SUPPORTS_AUTOCOMPLETION);
1035
1036     if (coreObject->isVisited())
1037         atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
1038 }
1039
1040 static AtkStateSet* webkitAccessibleRefStateSet(AtkObject* object)
1041 {
1042     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
1043
1044     AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_state_set(object);
1045     AccessibilityObject* coreObject = core(object);
1046
1047     // Make sure the layout is updated to really know whether the object
1048     // is defunct or not, so we can return the proper state.
1049     coreObject->updateBackingStore();
1050
1051     if (coreObject == fallbackObject()) {
1052         atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
1053         return stateSet;
1054     }
1055
1056     // Text objects must be focusable.
1057     AtkRole role = atk_object_get_role(object);
1058     if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
1059         atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
1060
1061     setAtkStateSetFromCoreObject(coreObject, stateSet);
1062     return stateSet;
1063 }
1064
1065 static AtkRelationSet* webkitAccessibleRefRelationSet(AtkObject* object)
1066 {
1067     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
1068     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
1069
1070     AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkitAccessibleParentClass)->ref_relation_set(object);
1071     AccessibilityObject* coreObject = core(object);
1072
1073     setAtkRelationSetFromCoreObject(coreObject, relationSet);
1074
1075     return relationSet;
1076 }
1077
1078 static void webkitAccessibleInit(AtkObject* object, gpointer data)
1079 {
1080     if (ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize)
1081         ATK_OBJECT_CLASS(webkitAccessibleParentClass)->initialize(object, data);
1082
1083     WebKitAccessible* accessible = WEBKIT_ACCESSIBLE(object);
1084     accessible->m_object = reinterpret_cast<AccessibilityObject*>(data);
1085     accessible->priv = WEBKIT_ACCESSIBLE_GET_PRIVATE(accessible);
1086 }
1087
1088 static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
1089 {
1090     g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(object), 0);
1091     returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(object), 0);
1092
1093     AccessibilityObject* coreObject = core(object);
1094     if (!coreObject)
1095         return 0;
1096
1097     if (ATK_IS_DOCUMENT(object)) {
1098         // TODO: Should we fall back on lang xml:lang when the following comes up empty?
1099         String language = coreObject->language();
1100         if (!language.isEmpty())
1101             return cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, language);
1102
1103     } else if (ATK_IS_TEXT(object)) {
1104         const gchar* locale = nullptr;
1105
1106         AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
1107         for (AtkAttributeSet* attributes = textAttributes; attributes; attributes = attributes->next) {
1108             AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
1109             if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
1110                 locale = cacheAndReturnAtkProperty(object, AtkCachedDocumentLocale, String::fromUTF8(atkAttribute->value));
1111                 break;
1112             }
1113         }
1114         atk_attribute_set_free(textAttributes);
1115
1116         return locale;
1117     }
1118
1119     return 0;
1120 }
1121
1122 static void webkitAccessibleFinalize(GObject* object)
1123 {
1124     G_OBJECT_CLASS(webkitAccessibleParentClass)->finalize(object);
1125 }
1126
1127 static void webkitAccessibleClassInit(AtkObjectClass* klass)
1128 {
1129     GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
1130
1131     webkitAccessibleParentClass = g_type_class_peek_parent(klass);
1132
1133     gobjectClass->finalize = webkitAccessibleFinalize;
1134
1135     klass->initialize = webkitAccessibleInit;
1136     klass->get_name = webkitAccessibleGetName;
1137     klass->get_description = webkitAccessibleGetDescription;
1138     klass->get_parent = webkitAccessibleGetParent;
1139     klass->get_n_children = webkitAccessibleGetNChildren;
1140     klass->ref_child = webkitAccessibleRefChild;
1141     klass->get_role = webkitAccessibleGetRole;
1142     klass->ref_state_set = webkitAccessibleRefStateSet;
1143     klass->get_index_in_parent = webkitAccessibleGetIndexInParent;
1144     klass->get_attributes = webkitAccessibleGetAttributes;
1145     klass->ref_relation_set = webkitAccessibleRefRelationSet;
1146     klass->get_object_locale = webkitAccessibleGetObjectLocale;
1147
1148     g_type_class_add_private(klass, sizeof(WebKitAccessiblePrivate));
1149 }
1150
1151 GType
1152 webkitAccessibleGetType(void)
1153 {
1154     static volatile gsize typeVolatile = 0;
1155
1156     if (g_once_init_enter(&typeVolatile)) {
1157         static const GTypeInfo tinfo = {
1158             sizeof(WebKitAccessibleClass),
1159             (GBaseInitFunc) 0,
1160             (GBaseFinalizeFunc) 0,
1161             (GClassInitFunc) webkitAccessibleClassInit,
1162             (GClassFinalizeFunc) 0,
1163             0, /* class data */
1164             sizeof(WebKitAccessible), /* instance size */
1165             0, /* nb preallocs */
1166             (GInstanceInitFunc) 0,
1167             0 /* value table */
1168         };
1169
1170         GType type = g_type_register_static(ATK_TYPE_OBJECT, "WebKitAccessible", &tinfo, GTypeFlags(0));
1171         g_once_init_leave(&typeVolatile, type);
1172     }
1173
1174     return typeVolatile;
1175 }
1176
1177 static const GInterfaceInfo AtkInterfacesInitFunctions[] = {
1178     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleActionInterfaceInit), 0, 0},
1179     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleSelectionInterfaceInit), 0, 0},
1180     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleEditableTextInterfaceInit), 0, 0},
1181     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTextInterfaceInit), 0, 0},
1182     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleComponentInterfaceInit), 0, 0},
1183     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleImageInterfaceInit), 0, 0},
1184     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableInterfaceInit), 0, 0},
1185 #if ATK_CHECK_VERSION(2,11,90)
1186     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleTableCellInterfaceInit), 0, 0},
1187 #endif
1188     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHypertextInterfaceInit), 0, 0},
1189     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleHyperlinkImplInterfaceInit), 0, 0},
1190     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleDocumentInterfaceInit), 0, 0},
1191     {reinterpret_cast<GInterfaceInitFunc>(webkitAccessibleValueInterfaceInit), 0, 0}
1192 };
1193
1194 enum WAIType {
1195     WAIAction,
1196     WAISelection,
1197     WAIEditableText,
1198     WAIText,
1199     WAIComponent,
1200     WAIImage,
1201     WAITable,
1202 #if ATK_CHECK_VERSION(2,11,90)
1203     WAITableCell,
1204 #endif
1205     WAIHypertext,
1206     WAIHyperlink,
1207     WAIDocument,
1208     WAIValue,
1209 };
1210
1211 static GType GetAtkInterfaceTypeFromWAIType(WAIType type)
1212 {
1213     switch (type) {
1214     case WAIAction:
1215         return ATK_TYPE_ACTION;
1216     case WAISelection:
1217         return ATK_TYPE_SELECTION;
1218     case WAIEditableText:
1219         return ATK_TYPE_EDITABLE_TEXT;
1220     case WAIText:
1221         return ATK_TYPE_TEXT;
1222     case WAIComponent:
1223         return ATK_TYPE_COMPONENT;
1224     case WAIImage:
1225         return ATK_TYPE_IMAGE;
1226     case WAITable:
1227         return ATK_TYPE_TABLE;
1228 #if ATK_CHECK_VERSION(2,11,90)
1229     case WAITableCell:
1230         return ATK_TYPE_TABLE_CELL;
1231 #endif
1232     case WAIHypertext:
1233         return ATK_TYPE_HYPERTEXT;
1234     case WAIHyperlink:
1235         return ATK_TYPE_HYPERLINK_IMPL;
1236     case WAIDocument:
1237         return ATK_TYPE_DOCUMENT;
1238     case WAIValue:
1239         return ATK_TYPE_VALUE;
1240     }
1241
1242     return G_TYPE_INVALID;
1243 }
1244
1245 static bool roleIsTextType(AccessibilityRole role)
1246 {
1247     return role == ParagraphRole || role == HeadingRole || role == DivRole || role == CellRole
1248         || role == LinkRole || role == WebCoreLinkRole || role == ListItemRole || role == PreRole
1249         || role == GridCellRole || role == TextGroupRole || role == ApplicationTextGroupRole;
1250 }
1251
1252 static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject)
1253 {
1254     guint16 interfaceMask = 0;
1255
1256     // Component interface is always supported
1257     interfaceMask |= 1 << WAIComponent;
1258
1259     AccessibilityRole role = coreObject->roleValue();
1260
1261     // Action
1262     // As the implementation of the AtkAction interface is a very
1263     // basic one (just relays in executing the default action for each
1264     // object, and only supports having one action per object), it is
1265     // better just to implement this interface for every instance of
1266     // the WebKitAccessible class and let WebCore decide what to do.
1267     interfaceMask |= 1 << WAIAction;
1268
1269     // Selection
1270     if (coreObject->canHaveSelectedChildren() || coreObject->isMenuList())
1271         interfaceMask |= 1 << WAISelection;
1272
1273     // Get renderer if available.
1274     RenderObject* renderer = nullptr;
1275     if (coreObject->isAccessibilityRenderObject())
1276         renderer = coreObject->renderer();
1277
1278     // Hyperlink (links and embedded objects).
1279     if (coreObject->isLink() || (renderer && renderer->isReplaced()))
1280         interfaceMask |= 1 << WAIHyperlink;
1281
1282     // Text, Editable Text & Hypertext
1283     if (role == StaticTextRole || coreObject->isMenuListOption())
1284         interfaceMask |= 1 << WAIText;
1285     else if (coreObject->isTextControl() || coreObject->isNonNativeTextControl()) {
1286         interfaceMask |= 1 << WAIText;
1287         if (coreObject->canSetValueAttribute())
1288             interfaceMask |= 1 << WAIEditableText;
1289     } else if (!coreObject->isWebArea()) {
1290         if (role != TableRole) {
1291             interfaceMask |= 1 << WAIHypertext;
1292             if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
1293                 interfaceMask |= 1 << WAIText;
1294         }
1295
1296         // Add the TEXT interface for list items whose
1297         // first accessible child has a text renderer
1298         if (role == ListItemRole) {
1299             const AccessibilityObject::AccessibilityChildrenVector& children = coreObject->children();
1300             if (children.size()) {
1301                 AccessibilityObject* axRenderChild = children.at(0).get();
1302                 interfaceMask |= getInterfaceMaskFromObject(axRenderChild);
1303             }
1304         }
1305     }
1306
1307     // Image
1308     if (coreObject->isImage())
1309         interfaceMask |= 1 << WAIImage;
1310
1311     // Table
1312     if (coreObject->isTable())
1313         interfaceMask |= 1 << WAITable;
1314
1315 #if ATK_CHECK_VERSION(2,11,90)
1316     if (role == CellRole || role == GridCellRole || role == ColumnHeaderRole || role == RowHeaderRole)
1317         interfaceMask |= 1 << WAITableCell;
1318 #endif
1319
1320     // Document
1321     if (role == WebAreaRole)
1322         interfaceMask |= 1 << WAIDocument;
1323
1324     // Value
1325     if (coreObject->supportsRangeValue())
1326         interfaceMask |= 1 << WAIValue;
1327
1328 #if ENABLE(INPUT_TYPE_COLOR)
1329     // Color type.
1330     if (role == ColorWellRole)
1331         interfaceMask |= 1 << WAIText;
1332 #endif
1333
1334     return interfaceMask;
1335 }
1336
1337 static const char* getUniqueAccessibilityTypeName(guint16 interfaceMask)
1338 {
1339 #define WAI_TYPE_NAME_LEN (30) /* Enough for prefix + 5 hex characters (max) */
1340     static char name[WAI_TYPE_NAME_LEN + 1];
1341
1342     g_sprintf(name, "WAIType%x", interfaceMask);
1343     name[WAI_TYPE_NAME_LEN] = '\0';
1344
1345     return name;
1346 }
1347
1348 static GType getAccessibilityTypeFromObject(AccessibilityObject* coreObject)
1349 {
1350     static const GTypeInfo typeInfo = {
1351         sizeof(WebKitAccessibleClass),
1352         (GBaseInitFunc) 0,
1353         (GBaseFinalizeFunc) 0,
1354         (GClassInitFunc) 0,
1355         (GClassFinalizeFunc) 0,
1356         0, /* class data */
1357         sizeof(WebKitAccessible), /* instance size */
1358         0, /* nb preallocs */
1359         (GInstanceInitFunc) 0,
1360         0 /* value table */
1361     };
1362
1363     guint16 interfaceMask = getInterfaceMaskFromObject(coreObject);
1364     const char* atkTypeName = getUniqueAccessibilityTypeName(interfaceMask);
1365     GType type = g_type_from_name(atkTypeName);
1366     if (type)
1367         return type;
1368
1369     type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE, atkTypeName, &typeInfo, GTypeFlags(0));
1370     for (guint i = 0; i < G_N_ELEMENTS(AtkInterfacesInitFunctions); i++) {
1371         if (interfaceMask & (1 << i))
1372             g_type_add_interface_static(type,
1373                 GetAtkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
1374                 &AtkInterfacesInitFunctions[i]);
1375     }
1376
1377     return type;
1378 }
1379
1380 WebKitAccessible* webkitAccessibleNew(AccessibilityObject* coreObject)
1381 {
1382     GType type = getAccessibilityTypeFromObject(coreObject);
1383     AtkObject* object = static_cast<AtkObject*>(g_object_new(type, 0));
1384
1385     atk_object_initialize(object, coreObject);
1386
1387     return WEBKIT_ACCESSIBLE(object);
1388 }
1389
1390 AccessibilityObject* webkitAccessibleGetAccessibilityObject(WebKitAccessible* accessible)
1391 {
1392     return accessible->m_object;
1393 }
1394
1395 void webkitAccessibleDetach(WebKitAccessible* accessible)
1396 {
1397     ASSERT(accessible->m_object);
1398
1399     if (accessible->m_object->roleValue() == WebAreaRole)
1400         atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, true);
1401
1402     // We replace the WebCore AccessibilityObject with a fallback object that
1403     // provides default implementations to avoid repetitive null-checking after
1404     // detachment.
1405     accessible->m_object = fallbackObject();
1406 }
1407
1408 bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
1409 {
1410     ASSERT(accessible->m_object);
1411     return accessible->m_object == fallbackObject();
1412 }
1413
1414 AccessibilityObject* objectFocusedAndCaretOffsetUnignored(AccessibilityObject* referenceObject, int& offset)
1415 {
1416     // Indication that something bogus has transpired.
1417     offset = -1;
1418
1419     Document* document = referenceObject->document();
1420     if (!document)
1421         return 0;
1422
1423     Node* focusedNode = referenceObject->selection().end().containerNode();
1424     if (!focusedNode)
1425         return 0;
1426
1427     RenderObject* focusedRenderer = focusedNode->renderer();
1428     if (!focusedRenderer)
1429         return 0;
1430
1431     AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
1432     if (!focusedObject)
1433         return 0;
1434
1435     // Look for the actual (not ignoring accessibility) selected object.
1436     AccessibilityObject* firstUnignoredParent = focusedObject;
1437     if (firstUnignoredParent->accessibilityIsIgnored())
1438         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1439     if (!firstUnignoredParent)
1440         return 0;
1441
1442     // Don't ignore links if the offset is being requested for a link
1443     // or if the link is a block.
1444     if (!referenceObject->isLink() && firstUnignoredParent->isLink()
1445         && !(firstUnignoredParent->renderer() && !firstUnignoredParent->renderer()->isInline()))
1446         firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
1447     if (!firstUnignoredParent)
1448         return 0;
1449
1450     // The reference object must either coincide with the focused
1451     // object being considered, or be a descendant of it.
1452     if (referenceObject->isDescendantOfObject(firstUnignoredParent))
1453         referenceObject = firstUnignoredParent;
1454
1455     Node* startNode = nullptr;
1456     if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
1457         // We need to use the first child's node of the reference
1458         // object as the start point to calculate the caret offset
1459         // because we want it to be relative to the object of
1460         // reference, not just to the focused object (which could have
1461         // previous siblings which should be taken into account too).
1462         AccessibilityObject* axFirstChild = referenceObject->firstChild();
1463         if (axFirstChild)
1464             startNode = axFirstChild->node();
1465     }
1466     // Getting the Position of a PseudoElement now triggers an assertion.
1467     // This can occur when clicking on empty space in a render block.
1468     if (!startNode || startNode->isPseudoElement())
1469         startNode = firstUnignoredParent->node();
1470
1471     // Check if the node for the first parent object not ignoring
1472     // accessibility is null again before using it. This might happen
1473     // with certain kind of accessibility objects, such as the root
1474     // one (the scroller containing the webArea object).
1475     if (!startNode)
1476         return 0;
1477
1478     VisiblePosition startPosition = VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM);
1479     VisiblePosition endPosition = firstUnignoredParent->selection().visibleEnd();
1480
1481     if (startPosition == endPosition)
1482         offset = 0;
1483     else if (!isStartOfLine(endPosition)) {
1484         RefPtr<Range> range = makeRange(startPosition, endPosition.previous());
1485         offset = TextIterator::rangeLength(range.get(), true) + 1;
1486     } else {
1487         RefPtr<Range> range = makeRange(startPosition, endPosition);
1488         offset = TextIterator::rangeLength(range.get(), true);
1489     }
1490
1491     return firstUnignoredParent;
1492 }
1493
1494 const char* cacheAndReturnAtkProperty(AtkObject* object, AtkCachedProperty property, String value)
1495 {
1496     WebKitAccessiblePrivate* priv = WEBKIT_ACCESSIBLE(object)->priv;
1497     CString* propertyPtr = nullptr;
1498
1499     switch (property) {
1500     case AtkCachedAccessibleName:
1501         propertyPtr = &priv->accessibleName;
1502         break;
1503
1504     case AtkCachedAccessibleDescription:
1505         propertyPtr = &priv->accessibleDescription;
1506         break;
1507
1508     case AtkCachedActionName:
1509         propertyPtr = &priv->actionName;
1510         break;
1511
1512     case AtkCachedActionKeyBinding:
1513         propertyPtr = &priv->actionKeyBinding;
1514         break;
1515
1516     case AtkCachedDocumentLocale:
1517         propertyPtr = &priv->documentLocale;
1518         break;
1519
1520     case AtkCachedDocumentType:
1521         propertyPtr = &priv->documentType;
1522         break;
1523
1524     case AtkCachedDocumentEncoding:
1525         propertyPtr = &priv->documentEncoding;
1526         break;
1527
1528     case AtkCachedDocumentURI:
1529         propertyPtr = &priv->documentURI;
1530         break;
1531
1532     case AtkCachedImageDescription:
1533         propertyPtr = &priv->imageDescription;
1534         break;
1535
1536     default:
1537         ASSERT_NOT_REACHED();
1538     }
1539
1540     // Don't invalidate old memory if not stricly needed, since other
1541     // callers might be still holding on to it.
1542     if (*propertyPtr != value.utf8())
1543         *propertyPtr = value.utf8();
1544
1545     return (*propertyPtr).data();
1546 }
1547
1548 #endif // HAVE(ACCESSIBILITY)