[EFL] Remove E_Dbus dependency
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / atk / AccessibilityUIElementAtk.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2012 Igalia S.L.
4  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "AccessibilityUIElement.h"
30
31 #if HAVE(ACCESSIBILITY)
32
33 #include "InjectedBundle.h"
34 #include "InjectedBundlePage.h"
35 #include "NotImplemented.h"
36 #include <JavaScriptCore/JSStringRef.h>
37 #include <JavaScriptCore/OpaqueJSString.h>
38 #if ATK_CHECK_VERSION(2,11,90)
39 #include <WebKit/WKBundleFrame.h>
40 #endif
41 #include <atk/atk.h>
42 #include <wtf/Assertions.h>
43 #include <wtf/gobject/GRefPtr.h>
44 #include <wtf/gobject/GUniquePtr.h>
45 #include <wtf/text/CString.h>
46 #include <wtf/text/StringBuilder.h>
47 #include <wtf/text/WTFString.h>
48 #include <wtf/unicode/CharacterNames.h>
49
50 namespace WTR {
51
52 namespace {
53
54 #if ATK_CHECK_VERSION(2,11,92)
55 enum RangeLimit {
56     RangeLimitMinimum,
57     RangeLimitMaximum
58 };
59 #endif
60
61 enum AtkAttributeType {
62     ObjectAttributeType,
63     TextAttributeType
64 };
65
66 enum AttributeDomain {
67     CoreDomain = 0,
68     AtkDomain
69 };
70
71 enum AttributesIndex {
72     // Attribute names.
73     InvalidNameIndex = 0,
74     PosInSetIndex,
75     SetSizeIndex,
76     PlaceholderNameIndex,
77     SortNameIndex,
78
79     // Attribute values.
80     SortAscendingValueIndex,
81     SortDescendingValueIndex,
82     SortUnknownValueIndex,
83
84     NumberOfAttributes
85 };
86
87 // Attribute names & Values (keep on sync with enum AttributesIndex).
88 const String attributesMap[][2] = {
89     // Attribute names.
90     { "AXInvalid", "invalid" },
91     { "AXARIAPosInSet", "posinset" },
92     { "AXARIASetSize", "setsize" },
93     { "AXPlaceholderValue", "placeholder-text" } ,
94     { "AXSortDirection", "sort" },
95
96     // Attribute values.
97     { "AXAscendingSortDirection", "ascending" },
98     { "AXDescendingSortDirection", "descending" },
99     { "AXUnknownSortDirection", "unknown" }
100 };
101
102 #if ATK_CHECK_VERSION(2, 11, 3)
103 const char* landmarkStringBanner = "AXLandmarkBanner";
104 const char* landmarkStringComplementary = "AXLandmarkComplementary";
105 const char* landmarkStringContentinfo = "AXLandmarkContentInfo";
106 const char* landmarkStringMain = "AXLandmarkMain";
107 const char* landmarkStringNavigation = "AXLandmarkNavigation";
108 const char* landmarkStringSearch = "AXLandmarkSearch";
109 #endif
110
111 String jsStringToWTFString(JSStringRef attribute)
112 {
113     size_t bufferSize = JSStringGetMaximumUTF8CStringSize(attribute);
114     GUniquePtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize)));
115     JSStringGetUTF8CString(attribute, buffer.get(), bufferSize);
116
117     return String::fromUTF8(buffer.get());
118 }
119
120 String coreAttributeToAtkAttribute(JSStringRef attribute)
121 {
122     String attributeString = jsStringToWTFString(attribute);
123     for (int i = 0; i < NumberOfAttributes; ++i) {
124         if (attributesMap[i][CoreDomain] == attributeString)
125             return attributesMap[i][AtkDomain];
126     }
127
128     return attributeString;
129 }
130
131 String atkAttributeValueToCoreAttributeValue(AtkAttributeType type, const String& id, const String& value)
132 {
133     if (type == ObjectAttributeType) {
134         // We need to translate ATK values exposed for 'aria-sort' (e.g. 'ascending')
135         // into those expected by the layout tests (e.g. 'AXAscendingSortDirection').
136         if (id == attributesMap[SortNameIndex][AtkDomain] && !value.isEmpty()) {
137             if (value == attributesMap[SortAscendingValueIndex][AtkDomain])
138                 return attributesMap[SortAscendingValueIndex][CoreDomain];
139             if (value == attributesMap[SortDescendingValueIndex][AtkDomain])
140                 return attributesMap[SortDescendingValueIndex][CoreDomain];
141
142             return attributesMap[SortUnknownValueIndex][CoreDomain];
143         }
144     } else if (type == TextAttributeType) {
145         // In case of 'aria-invalid' when the attribute empty or has "false" for ATK
146         // it should not be mapped at all, but layout tests will expect 'false'.
147         if (id == attributesMap[InvalidNameIndex][AtkDomain] && value.isEmpty())
148             return "false";
149     }
150
151     return value;
152 }
153
154 AtkAttributeSet* getAttributeSet(AtkObject* accessible, AtkAttributeType type)
155 {
156     if (type == ObjectAttributeType)
157         return atk_object_get_attributes(accessible);
158
159     if (type == TextAttributeType) {
160         if (!ATK_IS_TEXT(accessible))
161             return nullptr;
162
163         return atk_text_get_default_attributes(ATK_TEXT(accessible));
164     }
165
166     ASSERT_NOT_REACHED();
167     return nullptr;
168 }
169
170 String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, String id)
171 {
172     AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
173     if (!attributeSet)
174         return String();
175
176     String attributeValue;
177     for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
178         AtkAttribute* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
179         if (id == atkAttribute->name) {
180             attributeValue = String::fromUTF8(atkAttribute->value);
181             break;
182         }
183     }
184     atk_attribute_set_free(attributeSet);
185
186     return atkAttributeValueToCoreAttributeValue(type, id, attributeValue);
187 }
188
189 String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type)
190 {
191     AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
192     if (!attributeSet)
193         return String();
194
195     StringBuilder builder;
196     for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
197         AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
198         GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
199         builder.append(attributeData.get());
200         if (attributes->next)
201             builder.append(", ");
202     }
203     atk_attribute_set_free(attributeSet);
204
205     return builder.toString();
206 }
207
208 bool checkElementState(PlatformUIElement element, AtkStateType stateType)
209 {
210     if (!ATK_IS_OBJECT(element.get()))
211         return false;
212
213     GRefPtr<AtkStateSet> stateSet = adoptGRef(atk_object_ref_state_set(ATK_OBJECT(element.get())));
214     return atk_state_set_contains_state(stateSet.get(), stateType);
215 }
216
217 JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
218 {
219     GUniquePtr<gchar> rangeString(g_strdup("{0, 0}"));
220 #if ATK_CHECK_VERSION(2,11,90)
221     if (!ATK_IS_TABLE_CELL(element.get()))
222         return JSStringCreateWithUTF8CString(rangeString.get());
223 #else
224     if (!ATK_IS_OBJECT(element.get()))
225         return JSStringCreateWithUTF8CString(rangeString.get());
226
227     AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element.get()));
228     if (!axTable || !ATK_IS_TABLE(axTable))
229         return JSStringCreateWithUTF8CString(rangeString.get());
230
231     // Look for the cell in the table.
232     gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element.get()));
233     if (indexInParent == -1)
234         return JSStringCreateWithUTF8CString(rangeString.get());
235 #endif
236
237     gint row = -1;
238     gint column = -1;
239     gint rowSpan = -1;
240     gint columnSpan = -1;
241 #if ATK_CHECK_VERSION(2,11,90)
242     atk_table_cell_get_row_column_span(ATK_TABLE_CELL(element.get()), &row, &column, &rowSpan, &columnSpan);
243 #else
244     row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
245     column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
246     rowSpan = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
247     columnSpan = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
248 #endif
249
250     // Get the actual values, if row and columns are valid values.
251     if (row != -1 && column != -1) {
252         int base = 0;
253         int length = 0;
254         if (isRowRange) {
255             base = row;
256             length = rowSpan;
257         } else {
258             base = column;
259             length = columnSpan;
260         }
261         rangeString.reset(g_strdup_printf("{%d, %d}", base, length));
262     }
263
264     return JSStringCreateWithUTF8CString(rangeString.get());
265 }
266
267 void alterCurrentValue(PlatformUIElement element, int factor)
268 {
269     if (!ATK_IS_VALUE(element.get()))
270         return;
271
272 #if ATK_CHECK_VERSION(2,11,92)
273     double currentValue;
274     atk_value_get_value_and_text(ATK_VALUE(element.get()), &currentValue, nullptr);
275
276     double increment = atk_value_get_increment(ATK_VALUE(element.get()));
277     atk_value_set_value(ATK_VALUE(element.get()), currentValue + factor * increment);
278 #else
279     GValue currentValue = G_VALUE_INIT;
280     atk_value_get_current_value(ATK_VALUE(element.get()), &currentValue);
281
282     GValue increment = G_VALUE_INIT;
283     atk_value_get_minimum_increment(ATK_VALUE(element.get()), &increment);
284
285     GValue newValue = G_VALUE_INIT;
286     g_value_init(&newValue, G_TYPE_FLOAT);
287
288     g_value_set_float(&newValue, g_value_get_float(&currentValue) + factor * g_value_get_float(&increment));
289     atk_value_set_current_value(ATK_VALUE(element.get()), &newValue);
290
291     g_value_unset(&newValue);
292     g_value_unset(&increment);
293     g_value_unset(&currentValue);
294 #endif
295 }
296
297 gchar* replaceCharactersForResults(gchar* str)
298 {
299     WTF::String uString = WTF::String::fromUTF8(str);
300
301     // The object replacement character is passed along to ATs so we need to be
302     // able to test for their presence and do so without causing test failures.
303     uString.replace(objectReplacementCharacter, "<obj>");
304
305     // The presence of newline characters in accessible text of a single object
306     // is appropriate, but it makes test results (especially the accessible tree)
307     // harder to read.
308     uString.replace("\n", "<\\n>");
309
310     return g_strdup(uString.utf8().data());
311 }
312
313 const gchar* roleToString(AtkObject* object)
314 {
315     AtkRole role = atk_object_get_role(object);
316
317 #if ATK_CHECK_VERSION(2, 11, 3)
318     if (role == ATK_ROLE_LANDMARK) {
319         String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles");
320         if (equalIgnoringCase(xmlRolesValue, "banner"))
321             return landmarkStringBanner;
322         if (equalIgnoringCase(xmlRolesValue, "complementary"))
323             return landmarkStringComplementary;
324         if (equalIgnoringCase(xmlRolesValue, "contentinfo"))
325             return landmarkStringContentinfo;
326         if (equalIgnoringCase(xmlRolesValue, "main"))
327             return landmarkStringMain;
328         if (equalIgnoringCase(xmlRolesValue, "navigation"))
329             return landmarkStringNavigation;
330         if (equalIgnoringCase(xmlRolesValue, "search"))
331             return landmarkStringSearch;
332     }
333 #endif
334
335     switch (role) {
336     case ATK_ROLE_ALERT:
337         return "AXAlert";
338     case ATK_ROLE_DIALOG:
339         return "AXDialog";
340     case ATK_ROLE_CANVAS:
341         return "AXCanvas";
342     case ATK_ROLE_CHECK_BOX:
343         return "AXCheckBox";
344     case ATK_ROLE_COLOR_CHOOSER:
345         return "AXColorWell";
346     case ATK_ROLE_COLUMN_HEADER:
347         return "AXColumnHeader";
348     case ATK_ROLE_COMBO_BOX:
349         return "AXComboBox";
350     case ATK_ROLE_COMMENT:
351         return "AXComment";
352     case ATK_ROLE_DOCUMENT_FRAME:
353         return "AXDocument";
354     case ATK_ROLE_DOCUMENT_WEB:
355         return "AXWebArea";
356     case ATK_ROLE_EMBEDDED:
357         return "AXEmbedded";
358     case ATK_ROLE_ENTRY:
359         return "AXTextField";
360     case ATK_ROLE_FOOTER:
361         return "AXFooter";
362     case ATK_ROLE_FORM:
363         return "AXForm";
364     case ATK_ROLE_GROUPING:
365         return "AXGroup";
366     case ATK_ROLE_HEADING:
367         return "AXHeading";
368     case ATK_ROLE_IMAGE:
369         return "AXImage";
370     case ATK_ROLE_IMAGE_MAP:
371         return "AXImageMap";
372     case ATK_ROLE_INVALID:
373         return "AXInvalid";
374     case ATK_ROLE_LABEL:
375         return "AXLabel";
376     case ATK_ROLE_LINK:
377         return "AXLink";
378     case ATK_ROLE_LIST:
379         return "AXList";
380     case ATK_ROLE_LIST_BOX:
381         return "AXListBox";
382     case ATK_ROLE_LIST_ITEM:
383         return "AXListItem";
384     case ATK_ROLE_MENU:
385         return "AXMenu";
386     case ATK_ROLE_MENU_BAR:
387         return "AXMenuBar";
388     case ATK_ROLE_MENU_ITEM:
389         return "AXMenuItem";
390     case ATK_ROLE_PAGE_TAB:
391         return "AXTab";
392     case ATK_ROLE_PAGE_TAB_LIST:
393         return "AXTabGroup";
394     case ATK_ROLE_PANEL:
395         return "AXGroup";
396     case ATK_ROLE_PARAGRAPH:
397         return "AXParagraph";
398     case ATK_ROLE_PASSWORD_TEXT:
399         return "AXPasswordField";
400     case ATK_ROLE_PROGRESS_BAR:
401         return "AXProgressIndicator";
402     case ATK_ROLE_PUSH_BUTTON:
403         return "AXButton";
404     case ATK_ROLE_RADIO_BUTTON:
405         return "AXRadioButton";
406     case ATK_ROLE_RADIO_MENU_ITEM:
407         return "AXRadioMenuItem";
408     case ATK_ROLE_ROW_HEADER:
409         return "AXRowHeader";
410     case ATK_ROLE_CHECK_MENU_ITEM:
411         return "AXCheckMenuItem";
412     case ATK_ROLE_RULER:
413         return "AXRuler";
414     case ATK_ROLE_SCROLL_BAR:
415         return "AXScrollBar";
416     case ATK_ROLE_SCROLL_PANE:
417         return "AXScrollArea";
418     case ATK_ROLE_SECTION:
419         return "AXSection";
420     case ATK_ROLE_SEPARATOR:
421         return "AXSeparator";
422     case ATK_ROLE_SLIDER:
423         return "AXSlider";
424     case ATK_ROLE_SPIN_BUTTON:
425         return "AXSpinButton";
426     case ATK_ROLE_STATUSBAR:
427         return "AXStatusBar";
428     case ATK_ROLE_TABLE:
429         return "AXTable";
430     case ATK_ROLE_TABLE_CELL:
431         return "AXCell";
432     case ATK_ROLE_TABLE_COLUMN_HEADER:
433         return "AXColumnHeader";
434     case ATK_ROLE_TABLE_ROW:
435         return "AXRow";
436     case ATK_ROLE_TABLE_ROW_HEADER:
437         return "AXRowHeader";
438     case ATK_ROLE_TOGGLE_BUTTON:
439         return "AXToggleButton";
440     case ATK_ROLE_TOOL_BAR:
441         return "AXToolbar";
442     case ATK_ROLE_TOOL_TIP:
443         return "AXUserInterfaceTooltip";
444     case ATK_ROLE_TREE:
445         return "AXTree";
446     case ATK_ROLE_TREE_TABLE:
447         return "AXTreeGrid";
448     case ATK_ROLE_TREE_ITEM:
449         return "AXTreeItem";
450     case ATK_ROLE_WINDOW:
451         return "AXWindow";
452     case ATK_ROLE_UNKNOWN:
453         return "AXUnknown";
454 #if ATK_CHECK_VERSION(2, 11, 3)
455     case ATK_ROLE_ARTICLE:
456         return "AXArticle";
457     case ATK_ROLE_AUDIO:
458         return "AXAudio";
459     case ATK_ROLE_BLOCK_QUOTE:
460         return "AXBlockquote";
461     case ATK_ROLE_DEFINITION:
462         return "AXDefinition";
463     case ATK_ROLE_LOG:
464         return "AXLog";
465     case ATK_ROLE_MARQUEE:
466         return "AXMarquee";
467     case ATK_ROLE_MATH:
468         return "AXMath";
469     case ATK_ROLE_TIMER:
470         return "AXTimer";
471     case ATK_ROLE_VIDEO:
472         return "AXVideo";
473 #endif
474 #if ATK_CHECK_VERSION(2, 11, 4)
475     case ATK_ROLE_DESCRIPTION_LIST:
476         return "AXDescriptionList";
477     case ATK_ROLE_DESCRIPTION_TERM:
478         return "AXDescriptionTerm";
479     case ATK_ROLE_DESCRIPTION_VALUE:
480         return "AXDescriptionValue";
481 #endif
482     default:
483         // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which
484         // our DRT isn't properly handling.
485         return "FIXME not identified";
486     }
487 }
488
489 String attributesOfElement(AccessibilityUIElement* element)
490 {
491     StringBuilder builder;
492
493     builder.append(String::format("%s\n", element->role()->string().utf8().data()));
494
495     // For the parent we print its role and its name, if available.
496     builder.append("AXParent: ");
497     RefPtr<AccessibilityUIElement> parent = element->parentElement();
498     AtkObject* atkParent = parent ? parent->platformUIElement().get() : nullptr;
499     if (atkParent) {
500         builder.append(roleToString(atkParent));
501         const char* parentName = atk_object_get_name(atkParent);
502         if (parentName && g_utf8_strlen(parentName, -1))
503             builder.append(String::format(": %s", parentName));
504     } else
505         builder.append("(null)");
506     builder.append("\n");
507
508     builder.append(String::format("AXChildren: %d\n", element->childrenCount()));
509     builder.append(String::format("AXPosition: { %f, %f }\n", element->x(), element->y()));
510     builder.append(String::format("AXSize: { %f, %f }\n", element->width(), element->height()));
511
512     String title = element->title()->string();
513     if (!title.isEmpty())
514         builder.append(String::format("%s\n", title.utf8().data()));
515
516     String description = element->description()->string();
517     if (!description.isEmpty())
518         builder.append(String::format("%s\n", description.utf8().data()));
519
520     String value = element->stringValue()->string();
521     if (!value.isEmpty())
522         builder.append(String::format("%s\n", value.utf8().data()));
523
524     builder.append(String::format("AXFocusable: %d\n", element->isFocusable()));
525     builder.append(String::format("AXFocused: %d\n", element->isFocused()));
526     builder.append(String::format("AXSelectable: %d\n", element->isSelectable()));
527     builder.append(String::format("AXSelected: %d\n", element->isSelected()));
528     builder.append(String::format("AXMultiSelectable: %d\n", element->isMultiSelectable()));
529     builder.append(String::format("AXEnabled: %d\n", element->isEnabled()));
530     builder.append(String::format("AXExpanded: %d\n", element->isExpanded()));
531     builder.append(String::format("AXRequired: %d\n", element->isRequired()));
532     builder.append(String::format("AXChecked: %d\n", element->isChecked()));
533
534     String url = element->url()->string();
535     if (!url.isEmpty())
536         builder.append(String::format("%s\n", url.utf8().data()));
537
538     // We append the ATK specific attributes as a single line at the end.
539     builder.append("AXPlatformAttributes: ");
540     builder.append(getAtkAttributeSetAsString(element->platformUIElement().get(), ObjectAttributeType));
541
542     return builder.toString();
543 }
544
545 static JSRetainPtr<JSStringRef> createStringWithAttributes(const Vector<RefPtr<AccessibilityUIElement> >& elements)
546 {
547     StringBuilder builder;
548
549     for (Vector<RefPtr<AccessibilityUIElement> >::const_iterator it = elements.begin(); it != elements.end(); ++it) {
550         builder.append(attributesOfElement(const_cast<AccessibilityUIElement*>(it->get())));
551         builder.append("\n------------\n");
552     }
553
554     return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
555 }
556
557 static Vector<RefPtr<AccessibilityUIElement> > getRowHeaders(AtkTable* accessible)
558 {
559     Vector<RefPtr<AccessibilityUIElement> > rowHeaders;
560
561     int rowsCount = atk_table_get_n_rows(accessible);
562     for (int row = 0; row < rowsCount; ++row)
563         rowHeaders.append(AccessibilityUIElement::create(atk_table_get_row_header(accessible, row)));
564
565     return rowHeaders;
566 }
567
568 static Vector<RefPtr<AccessibilityUIElement> > getColumnHeaders(AtkTable* accessible)
569 {
570     Vector<RefPtr<AccessibilityUIElement> > columnHeaders;
571
572     int columnsCount = atk_table_get_n_columns(accessible);
573     for (int column = 0; column < columnsCount; ++column)
574         columnHeaders.append(AccessibilityUIElement::create(atk_table_get_column_header(accessible, column)));
575
576     return columnHeaders;
577 }
578
579 static Vector<RefPtr<AccessibilityUIElement> > getVisibleCells(AccessibilityUIElement* element)
580 {
581     Vector<RefPtr<AccessibilityUIElement> > visibleCells;
582
583     AtkTable* accessible = ATK_TABLE(element->platformUIElement().get());
584     int rowsCount = atk_table_get_n_rows(accessible);
585     int columnsCount = atk_table_get_n_columns(accessible);
586
587     for (int row = 0; row < rowsCount; ++row) {
588         for (int column = 0; column < columnsCount; ++column)
589             visibleCells.append(element->cellForColumnAndRow(column, row));
590     }
591
592     return visibleCells;
593 }
594
595 #if ATK_CHECK_VERSION(2,11,90)
596 static Vector<RefPtr<AccessibilityUIElement>> convertGPtrArrayToVector(const GPtrArray* array)
597 {
598     Vector<RefPtr<AccessibilityUIElement>> cells;
599     for (guint i = 0; i < array->len; i++) {
600         if (AtkObject* atkObject = static_cast<AtkObject*>(g_ptr_array_index(array, i)))
601             cells.append(AccessibilityUIElement::create(atkObject));
602     }
603     return cells;
604 }
605
606 static JSValueRef convertToJSObjectArray(const Vector<RefPtr<AccessibilityUIElement>>& children)
607 {
608     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
609     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
610
611     size_t elementCount = children.size();
612     auto valueElements = std::make_unique<JSValueRef[]>(elementCount);
613     for (size_t i = 0; i < elementCount; i++)
614         valueElements[i] = JSObjectMake(context, children[i]->wrapperClass(), children[i].get());
615
616     return JSObjectMakeArray(context, elementCount, valueElements.get(), nullptr);
617 }
618 #endif
619
620 #if ATK_CHECK_VERSION(2,11,92)
621 static double rangeMinMaxValue(AtkValue* atkValue, RangeLimit rangeLimit)
622 {
623     AtkRange* range = atk_value_get_range(atkValue);
624     if (!range)
625         return 0;
626
627     double rangeValue = 0;
628     switch (rangeLimit) {
629     case RangeLimitMinimum:
630         rangeValue = atk_range_get_lower_limit(range);
631         break;
632     case RangeLimitMaximum:
633         rangeValue = atk_range_get_upper_limit(range);
634         break;
635     };
636
637     atk_range_free(range);
638     return rangeValue;
639 }
640 #endif
641
642 } // namespace
643
644 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
645     : m_element(element)
646 {
647 }
648
649 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
650     : JSWrappable()
651     , m_element(other.m_element)
652 {
653 }
654
655 AccessibilityUIElement::~AccessibilityUIElement()
656 {
657 }
658
659 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
660 {
661     return m_element == otherElement->platformUIElement();
662 }
663
664 void AccessibilityUIElement::getChildren(Vector<RefPtr<AccessibilityUIElement> >& children)
665 {
666     if (!ATK_IS_OBJECT(m_element.get()))
667         return;
668
669     int count = childrenCount();
670     for (int i = 0; i < count; i++) {
671         GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), i));
672         children.append(AccessibilityUIElement::create(child.get()));
673     }
674 }
675
676 void AccessibilityUIElement::getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >& children, unsigned location, unsigned length)
677 {
678     if (!ATK_IS_OBJECT(m_element.get()))
679         return;
680     unsigned end = location + length;
681     for (unsigned i = location; i < end; i++) {
682         GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), i));
683         children.append(AccessibilityUIElement::create(child.get()));
684     }
685 }
686
687 int AccessibilityUIElement::childrenCount()
688 {
689     if (!ATK_IS_OBJECT(m_element.get()))
690         return 0;
691
692     return atk_object_get_n_accessible_children(ATK_OBJECT(m_element.get()));
693 }
694
695 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
696 {
697     if (!ATK_IS_COMPONENT(m_element.get()))
698         return nullptr;
699
700     GRefPtr<AtkObject> objectAtPoint = adoptGRef(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element.get()), x, y, ATK_XY_WINDOW));
701     return AccessibilityUIElement::create(objectAtPoint ? objectAtPoint.get() : m_element.get());
702 }
703
704 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
705 {
706     if (!ATK_IS_OBJECT(m_element.get()))
707         return 0;
708
709     Vector<RefPtr<AccessibilityUIElement> > children;
710     getChildren(children);
711
712     unsigned count = children.size();
713     for (unsigned i = 0; i < count; i++)
714         if (children[i]->isEqual(element))
715             return i;
716
717     return 0;
718 }
719
720 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
721 {
722     if (!ATK_IS_OBJECT(m_element.get()))
723         return nullptr;
724
725     Vector<RefPtr<AccessibilityUIElement> > children;
726     getChildrenWithRange(children, index, 1);
727
728     if (children.size() == 1)
729         return children[0];
730
731     return nullptr;
732 }
733
734 static PassRefPtr<AccessibilityUIElement> accessibilityElementAtIndex(AtkObject* element, AtkRelationType relationType, unsigned index)
735 {
736     if (!ATK_IS_OBJECT(element))
737         return nullptr;
738
739     AtkRelationSet* relationSet = atk_object_ref_relation_set(element);
740     if (!relationSet)
741         return nullptr;
742
743     AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, relationType);
744     if (!relation)
745         return nullptr;
746
747     GPtrArray* targetList = atk_relation_get_target(relation);
748     if (!targetList || !targetList->len || index >= targetList->len)
749         return nullptr;
750
751     AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index));
752     g_object_unref(relationSet);
753
754     return target ? AccessibilityUIElement::create(target) : nullptr;
755 }
756
757 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
758 {
759     // FIXME: implement
760     return nullptr;
761 }
762
763 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
764 {
765     // FIXME: implement
766     return nullptr;
767 }
768
769 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
770 {
771     return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_FLOWS_TO, index);
772 }
773
774 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
775 {
776     return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_CONTROLLER_FOR, index);
777 }
778
779 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
780 {
781     // FIXME: implement
782     return nullptr;
783 }
784
785 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
786 {
787     // FIXME: implement
788     return nullptr;
789 }
790
791 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
792 {
793     if (!ATK_SELECTION(m_element.get()))
794         return nullptr;
795
796     GRefPtr<AtkObject> child = adoptGRef(atk_selection_ref_selection(ATK_SELECTION(m_element.get()), index));
797     return child ? AccessibilityUIElement::create(child.get()) : nullptr;
798 }
799
800 unsigned AccessibilityUIElement::selectedChildrenCount() const
801 {
802     if (!ATK_IS_SELECTION(m_element.get()))
803         return 0;
804     return atk_selection_get_selection_count(ATK_SELECTION(m_element.get()));
805 }
806
807 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
808 {
809     // FIXME: implement
810     return nullptr;
811 }
812
813 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
814 {
815     if (!ATK_IS_OBJECT(m_element.get()))
816         return nullptr;
817
818     AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
819     if (!set)
820         return nullptr;
821
822     AtkObject* target = nullptr;
823     int count = atk_relation_set_get_n_relations(set);
824     for (int i = 0; i < count; i++) {
825         AtkRelation* relation = atk_relation_set_get_relation(set, i);
826         if (atk_relation_get_relation_type(relation) == ATK_RELATION_LABELLED_BY) {
827             GPtrArray* targetList = atk_relation_get_target(relation);
828             if (targetList->len)
829                 target = static_cast<AtkObject*>(g_ptr_array_index(targetList, 0));
830         }
831     }
832
833     g_object_unref(set);
834     return target ? AccessibilityUIElement::create(target) : nullptr;
835 }
836
837 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
838 {
839     if (!ATK_IS_OBJECT(m_element.get()))
840         return nullptr;
841
842     AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element.get()));
843     return parent ? AccessibilityUIElement::create(parent) : nullptr;
844 }
845
846 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
847 {
848     // FIXME: implement
849     return nullptr;
850 }
851
852 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
853 {
854     // FIXME: implement
855     return JSStringCreateWithCharacters(0, 0);
856 }
857
858 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
859 {
860     // FIXME: implement
861     return JSStringCreateWithCharacters(0, 0);
862 }
863
864 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
865 {
866     if (!ATK_IS_OBJECT(m_element.get()))
867         return JSStringCreateWithCharacters(0, 0);
868
869     Vector<RefPtr<AccessibilityUIElement> > children;
870     getChildren(children);
871
872     return createStringWithAttributes(children);
873 }
874
875 JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
876 {
877     if (!ATK_IS_OBJECT(m_element.get()))
878         return JSStringCreateWithCharacters(0, 0);
879
880     return JSStringCreateWithUTF8CString(attributesOfElement(this).utf8().data());
881 }
882
883 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
884 {
885     if (!ATK_IS_OBJECT(m_element.get()))
886         return JSStringCreateWithCharacters(0, 0);
887
888     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
889
890     // Try object attributes first.
891     String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
892
893     // Try text attributes if the requested one was not found and we have an AtkText object.
894     if (attributeValue.isEmpty() && ATK_IS_TEXT(m_element.get()))
895         attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), TextAttributeType, atkAttributeName);
896
897     // Additional check to make sure that the exposure of the state ATK_STATE_INVALID_ENTRY
898     // is consistent with the exposure of aria-invalid as a text attribute, if present.
899     if (atkAttributeName == attributesMap[InvalidNameIndex][AtkDomain]) {
900         bool isInvalidState = checkElementState(m_element.get(), ATK_STATE_INVALID_ENTRY);
901         if (attributeValue.isEmpty())
902             return JSStringCreateWithUTF8CString(isInvalidState ? "true" : "false");
903
904         // If the text attribute was there, check that it's consistent with
905         // what the state says or force the test to fail otherwise.
906         bool isAriaInvalid = attributeValue != "false";
907         if (isInvalidState != isAriaInvalid)
908             return JSStringCreateWithCharacters(0, 0);
909     }
910
911     return JSStringCreateWithUTF8CString(attributeValue.utf8().data());
912 }
913
914 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
915 {
916     if (!ATK_IS_OBJECT(m_element.get()))
917         return 0;
918
919     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
920     if (atkAttributeName.isEmpty())
921         return 0;
922
923     if (atkAttributeName == "setsize" || atkAttributeName == "posinset") {
924         String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
925         if (!attributeValue.isEmpty())
926             return attributeValue.toDouble();
927     }
928
929     return 0;
930 }
931
932 JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attribute) const
933 {
934     // FIXME: implement
935     return nullptr;
936 }
937
938 JSValueRef AccessibilityUIElement::rowHeaders() const
939 {
940 #if ATK_CHECK_VERSION(2,11,90)
941     if (!ATK_IS_TABLE_CELL(m_element.get()))
942         return nullptr;
943
944     GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_row_header_cells(ATK_TABLE_CELL(m_element.get())));
945     if (!array)
946         return nullptr;
947
948     Vector<RefPtr<AccessibilityUIElement>> rows = convertGPtrArrayToVector(array.get());
949     return convertToJSObjectArray(rows);
950 #else
951     return nullptr;
952 #endif
953 }
954
955 JSValueRef AccessibilityUIElement::columnHeaders() const
956 {
957 #if ATK_CHECK_VERSION(2,11,90)
958     if (!ATK_IS_TABLE_CELL(m_element.get()))
959         return nullptr;
960
961     GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_column_header_cells(ATK_TABLE_CELL(m_element.get())));
962     if (!array)
963         return nullptr;
964
965     Vector<RefPtr<AccessibilityUIElement>> columns = convertGPtrArrayToVector(array.get());
966     return convertToJSObjectArray(columns);
967 #else
968     return nullptr;
969 #endif
970 }
971
972 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
973 {
974     // FIXME: implement
975     return nullptr;
976 }
977
978 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
979 {
980     // FIXME: implement
981     return false;
982 }
983
984 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
985 {
986     if (!ATK_IS_OBJECT(m_element.get()))
987         return false;
988
989     String attributeString = jsStringToWTFString(attribute);
990     if (attributeString == "AXValue")
991         return checkElementState(m_element.get(), ATK_STATE_EDITABLE);
992
993     return false;
994 }
995
996 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
997 {
998     if (!ATK_IS_OBJECT(m_element.get()))
999         return false;
1000
1001     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
1002     if (atkAttributeName.isEmpty())
1003         return false;
1004
1005     // For now, an attribute is supported whether it's exposed as a object or a text attribute.
1006     String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
1007     if (attributeValue.isEmpty())
1008         attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), TextAttributeType, atkAttributeName);
1009
1010     return !attributeValue.isEmpty();
1011 }
1012
1013 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
1014 {
1015     // FIXME: implement
1016     return JSStringCreateWithCharacters(0, 0);
1017 }
1018
1019 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
1020 {
1021     if (!ATK_IS_OBJECT(m_element.get()))
1022         return JSStringCreateWithCharacters(0, 0);
1023
1024     GUniquePtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(ATK_OBJECT(m_element.get()))));
1025     return JSStringCreateWithUTF8CString(roleStringWithPrefix.get());
1026 }
1027
1028 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
1029 {
1030     // FIXME: implement
1031     return JSStringCreateWithCharacters(0, 0);
1032 }
1033
1034 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
1035 {
1036     // FIXME: implement
1037     return JSStringCreateWithCharacters(0, 0);
1038 }
1039
1040 JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
1041 {
1042     // FIXME: implement http://webkit.org/b/128420
1043     return JSStringCreateWithCharacters(0, 0);
1044 }
1045
1046 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
1047 {
1048     if (!ATK_IS_OBJECT(m_element.get()))
1049         return JSStringCreateWithCharacters(0, 0);
1050
1051     const gchar* name = atk_object_get_name(ATK_OBJECT(m_element.get()));
1052     GUniquePtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
1053
1054     return JSStringCreateWithUTF8CString(axTitle.get());
1055 }
1056
1057 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
1058 {
1059     if (!ATK_IS_OBJECT(m_element.get()))
1060         return JSStringCreateWithCharacters(0, 0);
1061
1062     const gchar* description = atk_object_get_description(ATK_OBJECT(m_element.get()));
1063     if (!description)
1064         return JSStringCreateWithCharacters(0, 0);
1065
1066     GUniquePtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
1067
1068     return JSStringCreateWithUTF8CString(axDesc.get());
1069 }
1070
1071 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
1072 {
1073     if (!ATK_IS_OBJECT(m_element.get()))
1074         return JSStringCreateWithCharacters(0, 0);
1075
1076     const gchar* axOrientation = nullptr;
1077     if (checkElementState(m_element.get(), ATK_STATE_HORIZONTAL))
1078         axOrientation = "AXOrientation: AXHorizontalOrientation";
1079     else if (checkElementState(m_element.get(), ATK_STATE_VERTICAL))
1080         axOrientation = "AXOrientation: AXVerticalOrientation";
1081
1082     if (!axOrientation)
1083         return JSStringCreateWithCharacters(0, 0);
1084
1085     return JSStringCreateWithUTF8CString(axOrientation);
1086 }
1087
1088 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
1089 {
1090     if (!ATK_IS_TEXT(m_element.get()))
1091         return JSStringCreateWithCharacters(0, 0);
1092
1093     GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, -1));
1094     GUniquePtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
1095     GUniquePtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
1096
1097     return JSStringCreateWithUTF8CString(axValue.get());
1098 }
1099
1100 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
1101 {
1102     if (!ATK_IS_OBJECT(m_element.get()))
1103         return JSStringCreateWithCharacters(0, 0);
1104
1105     const gchar* locale = atk_object_get_object_locale(ATK_OBJECT(m_element.get()));
1106     if (!locale)
1107         return JSStringCreateWithCharacters(0, 0);
1108
1109     GUniquePtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale));
1110     return JSStringCreateWithUTF8CString(axValue.get());
1111 }
1112
1113 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
1114 {
1115     if (!ATK_IS_OBJECT(m_element.get()))
1116         return JSStringCreateWithCharacters(0, 0);
1117
1118     AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
1119     if (!relationSet)
1120         return nullptr;
1121
1122     AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
1123     if (!relation)
1124         return nullptr;
1125
1126     GPtrArray* targetList = atk_relation_get_target(relation);
1127     if (!targetList || !targetList->len)
1128         return nullptr;
1129
1130     StringBuilder builder;
1131     builder.append("AXHelp: ");
1132
1133     for (int targetCount = 0; targetCount < targetList->len; targetCount++) {
1134         if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
1135             GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
1136             if (targetCount)
1137                 builder.append(" ");
1138             builder.append(text.get());
1139         }
1140     }
1141
1142     g_object_unref(relationSet);
1143
1144     return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
1145 }
1146
1147 double AccessibilityUIElement::x()
1148 {
1149     if (!ATK_IS_COMPONENT(m_element.get()))
1150         return 0;
1151
1152     int x;
1153 #if ATK_CHECK_VERSION(2,11,90)
1154     atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, nullptr, nullptr, ATK_XY_SCREEN);
1155 #else
1156     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_SCREEN);
1157 #endif
1158     return x;
1159 }
1160
1161 double AccessibilityUIElement::y()
1162 {
1163     if (!ATK_IS_COMPONENT(m_element.get()))
1164         return 0;
1165
1166     int y;
1167 #if ATK_CHECK_VERSION(2,11,90)
1168     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, nullptr, ATK_XY_SCREEN);
1169 #else
1170     atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_SCREEN);
1171 #endif
1172     return y;
1173 }
1174
1175 double AccessibilityUIElement::width()
1176 {
1177     if (!ATK_IS_COMPONENT(m_element.get()))
1178         return 0;
1179
1180     int width;
1181 #if ATK_CHECK_VERSION(2,11,90)
1182     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, &width, nullptr, ATK_XY_WINDOW);
1183 #else
1184     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
1185 #endif
1186     return width;
1187 }
1188
1189 double AccessibilityUIElement::height()
1190 {
1191     if (!ATK_IS_COMPONENT(m_element.get()))
1192         return 0;
1193
1194     int height;
1195 #if ATK_CHECK_VERSION(2,11,90)
1196     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, nullptr, &height, ATK_XY_WINDOW);
1197 #else
1198     atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
1199 #endif
1200     return height;
1201 }
1202
1203 double AccessibilityUIElement::clickPointX()
1204 {
1205     if (!ATK_IS_COMPONENT(m_element.get()))
1206         return 0;
1207
1208     int x, width;
1209 #if ATK_CHECK_VERSION(2,11,90)
1210     atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, &width, nullptr, ATK_XY_WINDOW);
1211 #else
1212     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_WINDOW);
1213     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
1214 #endif
1215
1216     return x + width / 2.0;
1217 }
1218
1219 double AccessibilityUIElement::clickPointY()
1220 {
1221     if (!ATK_IS_COMPONENT(m_element.get()))
1222         return 0;
1223
1224     int y, height;
1225 #if ATK_CHECK_VERSION(2,11,90)
1226     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, &height, ATK_XY_WINDOW);
1227 #else
1228     atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_WINDOW);
1229     atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
1230 #endif
1231
1232     return y + height / 2.0;
1233 }
1234
1235 double AccessibilityUIElement::intValue() const
1236 {
1237     if (!ATK_IS_OBJECT(m_element.get()))
1238         return 0;
1239
1240     if (ATK_IS_VALUE(m_element.get())) {
1241 #if ATK_CHECK_VERSION(2,11,92)
1242         double value;
1243         atk_value_get_value_and_text(ATK_VALUE(m_element.get()), &value, nullptr);
1244         return value;
1245 #else
1246         GValue value = G_VALUE_INIT;
1247         atk_value_get_current_value(ATK_VALUE(m_element.get()), &value);
1248         if (!G_VALUE_HOLDS_FLOAT(&value))
1249             return 0;
1250         return g_value_get_float(&value);
1251 #endif
1252     }
1253
1254     // Consider headings as an special case when returning the "int value" of
1255     // an AccessibilityUIElement, so we can reuse some tests to check the level
1256     // both for HTML headings and objects with the aria-level attribute.
1257     if (atk_object_get_role(ATK_OBJECT(m_element.get())) == ATK_ROLE_HEADING) {
1258         String headingLevel = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "level");
1259         bool ok;
1260         double headingLevelValue = headingLevel.toDouble(&ok);
1261         if (ok)
1262             return headingLevelValue;
1263     }
1264
1265     return 0;
1266 }
1267
1268 double AccessibilityUIElement::minValue()
1269 {
1270     if (!ATK_IS_VALUE(m_element.get()))
1271         return 0;
1272 #if ATK_CHECK_VERSION(2,11,92)
1273     return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMinimum);
1274 #else
1275     GValue value = G_VALUE_INIT;
1276     atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value);
1277     if (!G_VALUE_HOLDS_FLOAT(&value))
1278         return 0;
1279
1280     return g_value_get_float(&value);
1281 #endif
1282 }
1283
1284 double AccessibilityUIElement::maxValue()
1285 {
1286     if (!ATK_IS_VALUE(m_element.get()))
1287         return 0;
1288
1289 #if ATK_CHECK_VERSION(2,11,92)
1290     return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMaximum);
1291 #else
1292     GValue value = G_VALUE_INIT;
1293     atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value);
1294     if (!G_VALUE_HOLDS_FLOAT(&value))
1295         return 0;
1296
1297     return g_value_get_float(&value);
1298 #endif
1299 }
1300
1301 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
1302 {
1303     // FIXME: implement
1304     return JSStringCreateWithCharacters(0, 0);
1305 }
1306
1307 int AccessibilityUIElement::insertionPointLineNumber()
1308 {
1309     // FIXME: implement
1310     return -1;
1311 }
1312
1313 bool AccessibilityUIElement::isPressActionSupported()
1314 {
1315     if (!ATK_IS_ACTION(m_element.get()))
1316         return false;
1317
1318     const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element.get()), 0);
1319     return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump"));
1320 }
1321
1322 bool AccessibilityUIElement::isIncrementActionSupported()
1323 {
1324     // FIXME: implement
1325     return false;
1326 }
1327
1328 bool AccessibilityUIElement::isDecrementActionSupported()
1329 {
1330     // FIXME: implement
1331     return false;
1332 }
1333
1334 bool AccessibilityUIElement::isEnabled()
1335 {
1336     return checkElementState(m_element.get(), ATK_STATE_ENABLED);
1337 }
1338
1339 bool AccessibilityUIElement::isRequired() const
1340 {
1341     return checkElementState(m_element.get(), ATK_STATE_REQUIRED);
1342 }
1343
1344 bool AccessibilityUIElement::isFocused() const
1345 {
1346     return checkElementState(m_element.get(), ATK_STATE_FOCUSED);
1347 }
1348
1349 bool AccessibilityUIElement::isSelected() const
1350 {
1351     return checkElementState(m_element.get(), ATK_STATE_SELECTED);
1352 }
1353
1354 bool AccessibilityUIElement::isSelectedOptionActive() const
1355 {
1356     return checkElementState(m_element.get(), ATK_STATE_ACTIVE);
1357 }
1358
1359 bool AccessibilityUIElement::isExpanded() const
1360 {
1361     return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
1362 }
1363
1364 bool AccessibilityUIElement::isChecked() const
1365 {
1366     return checkElementState(m_element.get(), ATK_STATE_CHECKED);
1367 }
1368
1369 bool AccessibilityUIElement::isIndeterminate() const
1370 {
1371     return checkElementState(m_element.get(), ATK_STATE_INDETERMINATE);
1372 }
1373
1374 int AccessibilityUIElement::hierarchicalLevel() const
1375 {
1376     // FIXME: implement
1377     return 0;
1378 }
1379
1380 JSRetainPtr<JSStringRef> AccessibilityUIElement::speak()
1381 {
1382     // FIXME: implement
1383     return JSStringCreateWithCharacters(0, 0);
1384 }
1385
1386 bool AccessibilityUIElement::ariaIsGrabbed() const
1387 {
1388     // FIXME: implement
1389     return false;
1390 }
1391
1392 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
1393 {
1394     // FIXME: implement
1395     return JSStringCreateWithCharacters(0, 0);
1396 }
1397
1398 // parameterized attributes
1399 int AccessibilityUIElement::lineForIndex(int index)
1400 {
1401     if (!ATK_IS_TEXT(m_element.get()))
1402         return -1;
1403
1404     if (index < 0 || index > atk_text_get_character_count(ATK_TEXT(m_element.get())))
1405         return -1;
1406
1407     GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, index));
1408     int lineNo = 0;
1409     for (gchar* offset = text.get(); *offset; ++offset) {
1410         if (*offset == '\n')
1411             ++lineNo;
1412     }
1413
1414     return lineNo;
1415 }
1416
1417 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
1418 {
1419     // FIXME: implement
1420     return JSStringCreateWithCharacters(0, 0);
1421 }
1422
1423 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
1424 {
1425     // FIXME: implement
1426     return JSStringCreateWithCharacters(0, 0);
1427 }
1428
1429 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
1430 {
1431     // FIXME: implement
1432     return JSStringCreateWithCharacters(0, 0);
1433 }
1434
1435 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
1436 {
1437     if (!ATK_IS_TEXT(m_element.get()))
1438         return JSStringCreateWithCharacters(0, 0);
1439
1440     String string = atk_text_get_text(ATK_TEXT(m_element.get()), location, location + length);
1441     return JSStringCreateWithUTF8CString(string.utf8().data());
1442 }
1443
1444 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
1445 {
1446     // FIXME: implement
1447     return JSStringCreateWithCharacters(0, 0);
1448 }
1449
1450 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
1451 {
1452     // FIXME: implement
1453     return false;
1454 }
1455
1456 unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
1457 {
1458     // FIXME: implement
1459     return 0;
1460 }
1461
1462 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
1463 {
1464     // FIXME: implement
1465     return nullptr;
1466 }
1467
1468 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
1469 {
1470     // FIXME: implement
1471     return nullptr;
1472 }
1473
1474 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
1475 {
1476     if (!ATK_IS_TABLE(m_element.get()))
1477         return JSStringCreateWithCharacters(0, 0);
1478
1479     Vector<RefPtr<AccessibilityUIElement> > columnHeaders = getColumnHeaders(ATK_TABLE(m_element.get()));
1480     return createStringWithAttributes(columnHeaders);
1481 }
1482
1483 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
1484 {
1485     if (!ATK_IS_TABLE(m_element.get()))
1486         return JSStringCreateWithCharacters(0, 0);
1487
1488     Vector<RefPtr<AccessibilityUIElement> > rowHeaders = getRowHeaders(ATK_TABLE(m_element.get()));
1489     return createStringWithAttributes(rowHeaders);
1490 }
1491
1492 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
1493 {
1494     // FIXME: implement
1495     return JSStringCreateWithCharacters(0, 0);
1496 }
1497
1498 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
1499 {
1500     // FIXME: implement
1501     return JSStringCreateWithCharacters(0, 0);
1502 }
1503
1504 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
1505 {
1506     if (!ATK_IS_TABLE(m_element.get()))
1507         return JSStringCreateWithCharacters(0, 0);
1508
1509     Vector<RefPtr<AccessibilityUIElement> > visibleCells = getVisibleCells(this);
1510     return createStringWithAttributes(visibleCells);
1511 }
1512
1513 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
1514 {
1515     // FIXME: implement
1516     return JSStringCreateWithCharacters(0, 0);
1517 }
1518
1519 int AccessibilityUIElement::rowCount()
1520 {
1521     if (!ATK_IS_TABLE(m_element.get()))
1522         return 0;
1523
1524     return atk_table_get_n_rows(ATK_TABLE(m_element.get()));
1525 }
1526
1527 int AccessibilityUIElement::columnCount()
1528 {
1529     if (!ATK_IS_TABLE(m_element.get()))
1530         return 0;
1531
1532     return atk_table_get_n_columns(ATK_TABLE(m_element.get()));
1533 }
1534
1535 int AccessibilityUIElement::indexInTable()
1536 {
1537     // FIXME: implement
1538     return -1;
1539 }
1540
1541 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
1542 {
1543     // Range in table for rows.
1544     return indexRangeInTable(m_element.get(), true);
1545 }
1546
1547 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
1548 {
1549     // Range in table for columns.
1550     return indexRangeInTable(m_element.get(), false);
1551 }
1552
1553 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
1554 {
1555     if (!ATK_IS_TABLE(m_element.get()))
1556         return nullptr;
1557
1558     // Adopt the AtkObject representing the cell because
1559     // at_table_ref_at() transfers full ownership.
1560     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col));
1561     return foundCell ? AccessibilityUIElement::create(foundCell.get()) : nullptr;
1562 }
1563
1564 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
1565 {
1566     // FIXME: implement
1567     return nullptr;
1568 }
1569
1570 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
1571 {
1572     // FIXME: implement
1573     return nullptr;
1574 }
1575
1576 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
1577 {
1578     if (!ATK_IS_TEXT(m_element.get()))
1579         return JSStringCreateWithCharacters(0, 0);
1580
1581     gint start, end;
1582     g_free(atk_text_get_selection(ATK_TEXT(m_element.get()), 0, &start, &end));
1583
1584     GUniquePtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start));
1585     return JSStringCreateWithUTF8CString(selection.get());
1586 }
1587
1588 bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
1589 {
1590     if (!ATK_IS_TEXT(m_element.get()))
1591         return false;
1592
1593     if (!length)
1594         return atk_text_set_caret_offset(ATK_TEXT(m_element.get()), location);
1595
1596     return atk_text_set_selection(ATK_TEXT(m_element.get()), 0, location, location + length);
1597 }
1598
1599 void AccessibilityUIElement::increment()
1600 {
1601     alterCurrentValue(m_element.get(), 1);
1602 }
1603
1604 void AccessibilityUIElement::decrement()
1605 {
1606     alterCurrentValue(m_element.get(), -1);
1607 }
1608
1609 void AccessibilityUIElement::showMenu()
1610 {
1611     // FIXME: implement
1612 }
1613
1614 void AccessibilityUIElement::press()
1615 {
1616     if (!ATK_IS_ACTION(m_element.get()))
1617         return;
1618
1619     // Only one action per object is supported so far.
1620     atk_action_do_action(ATK_ACTION(m_element.get()), 0);
1621 }
1622
1623 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
1624 {
1625     // FIXME: implement
1626 }
1627
1628 void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
1629 {
1630     if (!ATK_IS_SELECTION(m_element.get()))
1631         return;
1632
1633     atk_selection_add_selection(ATK_SELECTION(m_element.get()), index);
1634 }
1635
1636 void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
1637 {
1638     if (!ATK_IS_SELECTION(m_element.get()))
1639         return;
1640
1641     atk_selection_remove_selection(ATK_SELECTION(m_element.get()), index);
1642 }
1643
1644 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
1645 {
1646     // FIXME: implement
1647     return JSStringCreateWithCharacters(0, 0);
1648 }
1649
1650 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
1651 {
1652     if (!ATK_IS_DOCUMENT(m_element.get()))
1653         return JSStringCreateWithCharacters(0, 0);
1654
1655     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1656     if (role != ATK_ROLE_DOCUMENT_FRAME)
1657         return JSStringCreateWithCharacters(0, 0);
1658
1659     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding"));
1660 }
1661
1662 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
1663 {
1664     if (!ATK_IS_DOCUMENT(m_element.get()))
1665         return JSStringCreateWithCharacters(0, 0);
1666
1667     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1668     if (role != ATK_ROLE_DOCUMENT_FRAME)
1669         return JSStringCreateWithCharacters(0, 0);
1670
1671     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI"));
1672 }
1673
1674 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
1675 {
1676     if (!ATK_IS_HYPERLINK_IMPL(m_element.get()))
1677         return JSStringCreateWithCharacters(0, 0);
1678
1679     AtkHyperlink* hyperlink = atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(m_element.get()));
1680     GUniquePtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0));
1681
1682     // Build the result string, stripping the absolute URL paths if present.
1683     char* localURI = g_strstr_len(hyperlinkURI.get(), -1, "LayoutTests");
1684     String axURL = String::format("AXURL: %s", localURI ? localURI : hyperlinkURI.get());
1685     return JSStringCreateWithUTF8CString(axURL.utf8().data());
1686 }
1687
1688 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
1689 {
1690     if (!functionCallback)
1691         return false;
1692
1693     // Only one notification listener per element.
1694     if (m_notificationHandler)
1695         return false;
1696
1697     m_notificationHandler = AccessibilityNotificationHandler::create();
1698     m_notificationHandler->setPlatformElement(platformUIElement());
1699     m_notificationHandler->setNotificationFunctionCallback(functionCallback);
1700
1701     return true;
1702 }
1703
1704 bool AccessibilityUIElement::removeNotificationListener()
1705 {
1706     // Programmers should not be trying to remove a listener that's already removed.
1707     ASSERT(m_notificationHandler);
1708     m_notificationHandler = nullptr;
1709
1710     return true;
1711 }
1712
1713 bool AccessibilityUIElement::isFocusable() const
1714 {
1715     return checkElementState(m_element.get(), ATK_STATE_FOCUSABLE);
1716 }
1717
1718 bool AccessibilityUIElement::isSelectable() const
1719 {
1720     return checkElementState(m_element.get(), ATK_STATE_SELECTABLE);
1721 }
1722
1723 bool AccessibilityUIElement::isMultiSelectable() const
1724 {
1725     return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE);
1726 }
1727
1728 bool AccessibilityUIElement::isVisible() const
1729 {
1730     return checkElementState(m_element.get(), ATK_STATE_VISIBLE);
1731 }
1732
1733 bool AccessibilityUIElement::isOffScreen() const
1734 {
1735     // FIXME: implement
1736     return false;
1737 }
1738
1739 bool AccessibilityUIElement::isCollapsed() const
1740 {
1741     // FIXME: implement
1742     return false;
1743 }
1744
1745 bool AccessibilityUIElement::isIgnored() const
1746 {
1747     // FIXME: implement
1748     return false;
1749 }
1750
1751 bool AccessibilityUIElement::hasPopup() const
1752 {
1753     if (!ATK_IS_OBJECT(m_element.get()))
1754         return false;
1755
1756     String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "haspopup");
1757     return equalIgnoringCase(hasPopupValue, "true");
1758 }
1759
1760 void AccessibilityUIElement::takeFocus()
1761 {
1762     // FIXME: implement
1763 }
1764
1765 void AccessibilityUIElement::takeSelection()
1766 {
1767     // FIXME: implement
1768 }
1769
1770 void AccessibilityUIElement::addSelection()
1771 {
1772     // FIXME: implement
1773 }
1774
1775 void AccessibilityUIElement::removeSelection()
1776 {
1777     // FIXME: implement
1778 }
1779
1780 // Text markers
1781 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1782 {
1783     // FIXME: implement
1784     return nullptr;
1785 }
1786
1787 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1788 {
1789     // FIXME: implement
1790     return nullptr;
1791 }
1792
1793 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1794 {
1795     // FIXME: implement
1796     return 0;
1797 }
1798
1799 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1800 {
1801     // FIXME: implement
1802     return nullptr;
1803 }
1804
1805 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1806 {
1807     // FIXME: implement
1808     return nullptr;
1809 }
1810
1811 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1812 {
1813     // FIXME: implement
1814     return JSStringCreateWithCharacters(0, 0);
1815 }
1816
1817 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1818 {
1819     // FIXME: implement
1820     return nullptr;
1821 }
1822
1823 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1824 {
1825     // FIXME: implement
1826     return nullptr;
1827 }
1828
1829 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1830 {
1831     // FIXME: implement
1832     return nullptr;
1833 }
1834
1835 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
1836 {
1837     // FIXME: implement
1838     return nullptr;
1839 }
1840
1841 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
1842 {
1843     // FIXME: implement
1844     return nullptr;
1845 }
1846
1847 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1848 {
1849     // FIXME: implement
1850     return nullptr;
1851 }
1852
1853 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1854 {
1855     // FIXME: implement
1856     return nullptr;
1857 }
1858
1859 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1860 {
1861     // FIXME: implement
1862     return false;
1863 }
1864
1865 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1866 {
1867     // FIXME: implement
1868     return -1;
1869 }
1870
1871 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1872 {
1873     // FIXME: implement
1874     return false;
1875 }
1876
1877 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1878 {
1879     // FIXME: implement
1880     return nullptr;
1881 }
1882     
1883 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
1884 {
1885     // FIXME: implement
1886     return nullptr;    
1887 }
1888
1889 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
1890 {
1891     // FIXME: implement
1892     return nullptr;
1893 }
1894
1895 void AccessibilityUIElement::scrollToMakeVisible()
1896 {
1897     // FIXME: implement
1898 }
1899
1900 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1901 {
1902     // FIXME: implement
1903     return nullptr;
1904 }
1905
1906 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1907 {
1908     notImplemented();
1909     return nullptr;
1910 }
1911
1912 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1913 {
1914     notImplemented();
1915     return nullptr;
1916 }
1917
1918 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1919 {
1920     notImplemented();
1921     return nullptr;
1922 }
1923
1924 JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
1925 {
1926     notImplemented();
1927     return nullptr;
1928 }
1929
1930 JSRetainPtr<JSStringRef> stringAtOffset(PlatformUIElement element, AtkTextBoundary boundary, int offset)
1931 {
1932     if (!ATK_IS_TEXT(element.get()))
1933         return JSStringCreateWithCharacters(0, 0);
1934
1935     gint startOffset, endOffset;
1936     StringBuilder builder;
1937
1938 #if ATK_CHECK_VERSION(2, 10, 0)
1939     AtkTextGranularity granularity;
1940     switch (boundary) {
1941     case ATK_TEXT_BOUNDARY_CHAR:
1942         granularity = ATK_TEXT_GRANULARITY_CHAR;
1943         break;
1944     case ATK_TEXT_BOUNDARY_WORD_START:
1945         granularity = ATK_TEXT_GRANULARITY_WORD;
1946         break;
1947     case ATK_TEXT_BOUNDARY_LINE_START:
1948         granularity = ATK_TEXT_GRANULARITY_LINE;
1949         break;
1950     case ATK_TEXT_BOUNDARY_SENTENCE_START:
1951         granularity = ATK_TEXT_GRANULARITY_SENTENCE;
1952         break;
1953     default:
1954         return JSStringCreateWithCharacters(0, 0);
1955     }
1956
1957     builder.append(atk_text_get_string_at_offset(ATK_TEXT(element.get()), offset, granularity, &startOffset, &endOffset));
1958 #else
1959     builder.append(atk_text_get_text_at_offset(ATK_TEXT(element.get()), offset, boundary, &startOffset, &endOffset));
1960 #endif
1961     builder.append(String::format(", %i, %i", startOffset, endOffset));
1962     return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
1963 }
1964
1965 JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int offset)
1966 {
1967     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_CHAR, offset);
1968 }
1969
1970 JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int offset)
1971 {
1972     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_WORD_START, offset);
1973 }
1974
1975 JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int offset)
1976 {
1977     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_LINE_START, offset);
1978 }
1979
1980 JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int offset)
1981 {
1982     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_SENTENCE_START, offset);
1983 }
1984
1985 } // namespace WTR
1986
1987 #endif // HAVE(ACCESSIBILITY)