[ATK] Allowing the use of AccessibilityUIElement::columnHeaders method for table.
[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()) && !ATK_IS_TABLE(m_element.get()))
959         return nullptr;
960
961     Vector<RefPtr<AccessibilityUIElement>> columns;
962     if (ATK_IS_TABLE_CELL(m_element.get())) {
963         GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_column_header_cells(ATK_TABLE_CELL(m_element.get())));
964         if (!array)
965             return nullptr;
966
967         columns = convertGPtrArrayToVector(array.get());
968     } else
969         columns = getColumnHeaders(ATK_TABLE(m_element.get()));
970     return convertToJSObjectArray(columns);
971 #else
972     return nullptr;
973 #endif
974 }
975
976 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
977 {
978     // FIXME: implement
979     return nullptr;
980 }
981
982 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
983 {
984     // FIXME: implement
985     return false;
986 }
987
988 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
989 {
990     if (!ATK_IS_OBJECT(m_element.get()))
991         return false;
992
993     String attributeString = jsStringToWTFString(attribute);
994     if (attributeString == "AXValue")
995         return checkElementState(m_element.get(), ATK_STATE_EDITABLE);
996
997     return false;
998 }
999
1000 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
1001 {
1002     if (!ATK_IS_OBJECT(m_element.get()))
1003         return false;
1004
1005     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
1006     if (atkAttributeName.isEmpty())
1007         return false;
1008
1009     // For now, an attribute is supported whether it's exposed as a object or a text attribute.
1010     String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
1011     if (attributeValue.isEmpty())
1012         attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), TextAttributeType, atkAttributeName);
1013
1014     return !attributeValue.isEmpty();
1015 }
1016
1017 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
1018 {
1019     // FIXME: implement
1020     return JSStringCreateWithCharacters(0, 0);
1021 }
1022
1023 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
1024 {
1025     if (!ATK_IS_OBJECT(m_element.get()))
1026         return JSStringCreateWithCharacters(0, 0);
1027
1028     GUniquePtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(ATK_OBJECT(m_element.get()))));
1029     return JSStringCreateWithUTF8CString(roleStringWithPrefix.get());
1030 }
1031
1032 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
1033 {
1034     // FIXME: implement
1035     return JSStringCreateWithCharacters(0, 0);
1036 }
1037
1038 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
1039 {
1040     // FIXME: implement
1041     return JSStringCreateWithCharacters(0, 0);
1042 }
1043
1044 JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
1045 {
1046     // FIXME: implement http://webkit.org/b/128420
1047     return JSStringCreateWithCharacters(0, 0);
1048 }
1049
1050 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
1051 {
1052     if (!ATK_IS_OBJECT(m_element.get()))
1053         return JSStringCreateWithCharacters(0, 0);
1054
1055     const gchar* name = atk_object_get_name(ATK_OBJECT(m_element.get()));
1056     GUniquePtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
1057
1058     return JSStringCreateWithUTF8CString(axTitle.get());
1059 }
1060
1061 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
1062 {
1063     if (!ATK_IS_OBJECT(m_element.get()))
1064         return JSStringCreateWithCharacters(0, 0);
1065
1066     const gchar* description = atk_object_get_description(ATK_OBJECT(m_element.get()));
1067     if (!description)
1068         return JSStringCreateWithCharacters(0, 0);
1069
1070     GUniquePtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
1071
1072     return JSStringCreateWithUTF8CString(axDesc.get());
1073 }
1074
1075 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
1076 {
1077     if (!ATK_IS_OBJECT(m_element.get()))
1078         return JSStringCreateWithCharacters(0, 0);
1079
1080     const gchar* axOrientation = nullptr;
1081     if (checkElementState(m_element.get(), ATK_STATE_HORIZONTAL))
1082         axOrientation = "AXOrientation: AXHorizontalOrientation";
1083     else if (checkElementState(m_element.get(), ATK_STATE_VERTICAL))
1084         axOrientation = "AXOrientation: AXVerticalOrientation";
1085
1086     if (!axOrientation)
1087         return JSStringCreateWithCharacters(0, 0);
1088
1089     return JSStringCreateWithUTF8CString(axOrientation);
1090 }
1091
1092 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
1093 {
1094     if (!ATK_IS_TEXT(m_element.get()))
1095         return JSStringCreateWithCharacters(0, 0);
1096
1097     GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, -1));
1098     GUniquePtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
1099     GUniquePtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
1100
1101     return JSStringCreateWithUTF8CString(axValue.get());
1102 }
1103
1104 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
1105 {
1106     if (!ATK_IS_OBJECT(m_element.get()))
1107         return JSStringCreateWithCharacters(0, 0);
1108
1109     const gchar* locale = atk_object_get_object_locale(ATK_OBJECT(m_element.get()));
1110     if (!locale)
1111         return JSStringCreateWithCharacters(0, 0);
1112
1113     GUniquePtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale));
1114     return JSStringCreateWithUTF8CString(axValue.get());
1115 }
1116
1117 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
1118 {
1119     if (!ATK_IS_OBJECT(m_element.get()))
1120         return JSStringCreateWithCharacters(0, 0);
1121
1122     AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
1123     if (!relationSet)
1124         return nullptr;
1125
1126     AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
1127     if (!relation)
1128         return nullptr;
1129
1130     GPtrArray* targetList = atk_relation_get_target(relation);
1131     if (!targetList || !targetList->len)
1132         return nullptr;
1133
1134     StringBuilder builder;
1135     builder.append("AXHelp: ");
1136
1137     for (int targetCount = 0; targetCount < targetList->len; targetCount++) {
1138         if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
1139             GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
1140             if (targetCount)
1141                 builder.append(" ");
1142             builder.append(text.get());
1143         }
1144     }
1145
1146     g_object_unref(relationSet);
1147
1148     return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
1149 }
1150
1151 double AccessibilityUIElement::x()
1152 {
1153     if (!ATK_IS_COMPONENT(m_element.get()))
1154         return 0;
1155
1156     int x;
1157 #if ATK_CHECK_VERSION(2,11,90)
1158     atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, nullptr, nullptr, ATK_XY_SCREEN);
1159 #else
1160     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_SCREEN);
1161 #endif
1162     return x;
1163 }
1164
1165 double AccessibilityUIElement::y()
1166 {
1167     if (!ATK_IS_COMPONENT(m_element.get()))
1168         return 0;
1169
1170     int y;
1171 #if ATK_CHECK_VERSION(2,11,90)
1172     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, nullptr, ATK_XY_SCREEN);
1173 #else
1174     atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_SCREEN);
1175 #endif
1176     return y;
1177 }
1178
1179 double AccessibilityUIElement::width()
1180 {
1181     if (!ATK_IS_COMPONENT(m_element.get()))
1182         return 0;
1183
1184     int width;
1185 #if ATK_CHECK_VERSION(2,11,90)
1186     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, &width, nullptr, ATK_XY_WINDOW);
1187 #else
1188     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
1189 #endif
1190     return width;
1191 }
1192
1193 double AccessibilityUIElement::height()
1194 {
1195     if (!ATK_IS_COMPONENT(m_element.get()))
1196         return 0;
1197
1198     int height;
1199 #if ATK_CHECK_VERSION(2,11,90)
1200     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, nullptr, &height, ATK_XY_WINDOW);
1201 #else
1202     atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
1203 #endif
1204     return height;
1205 }
1206
1207 double AccessibilityUIElement::clickPointX()
1208 {
1209     if (!ATK_IS_COMPONENT(m_element.get()))
1210         return 0;
1211
1212     int x, width;
1213 #if ATK_CHECK_VERSION(2,11,90)
1214     atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, &width, nullptr, ATK_XY_WINDOW);
1215 #else
1216     atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_WINDOW);
1217     atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
1218 #endif
1219
1220     return x + width / 2.0;
1221 }
1222
1223 double AccessibilityUIElement::clickPointY()
1224 {
1225     if (!ATK_IS_COMPONENT(m_element.get()))
1226         return 0;
1227
1228     int y, height;
1229 #if ATK_CHECK_VERSION(2,11,90)
1230     atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, &height, ATK_XY_WINDOW);
1231 #else
1232     atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_WINDOW);
1233     atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
1234 #endif
1235
1236     return y + height / 2.0;
1237 }
1238
1239 double AccessibilityUIElement::intValue() const
1240 {
1241     if (!ATK_IS_OBJECT(m_element.get()))
1242         return 0;
1243
1244     if (ATK_IS_VALUE(m_element.get())) {
1245 #if ATK_CHECK_VERSION(2,11,92)
1246         double value;
1247         atk_value_get_value_and_text(ATK_VALUE(m_element.get()), &value, nullptr);
1248         return value;
1249 #else
1250         GValue value = G_VALUE_INIT;
1251         atk_value_get_current_value(ATK_VALUE(m_element.get()), &value);
1252         if (!G_VALUE_HOLDS_FLOAT(&value))
1253             return 0;
1254         return g_value_get_float(&value);
1255 #endif
1256     }
1257
1258     // Consider headings as an special case when returning the "int value" of
1259     // an AccessibilityUIElement, so we can reuse some tests to check the level
1260     // both for HTML headings and objects with the aria-level attribute.
1261     if (atk_object_get_role(ATK_OBJECT(m_element.get())) == ATK_ROLE_HEADING) {
1262         String headingLevel = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "level");
1263         bool ok;
1264         double headingLevelValue = headingLevel.toDouble(&ok);
1265         if (ok)
1266             return headingLevelValue;
1267     }
1268
1269     return 0;
1270 }
1271
1272 double AccessibilityUIElement::minValue()
1273 {
1274     if (!ATK_IS_VALUE(m_element.get()))
1275         return 0;
1276 #if ATK_CHECK_VERSION(2,11,92)
1277     return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMinimum);
1278 #else
1279     GValue value = G_VALUE_INIT;
1280     atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value);
1281     if (!G_VALUE_HOLDS_FLOAT(&value))
1282         return 0;
1283
1284     return g_value_get_float(&value);
1285 #endif
1286 }
1287
1288 double AccessibilityUIElement::maxValue()
1289 {
1290     if (!ATK_IS_VALUE(m_element.get()))
1291         return 0;
1292
1293 #if ATK_CHECK_VERSION(2,11,92)
1294     return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMaximum);
1295 #else
1296     GValue value = G_VALUE_INIT;
1297     atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value);
1298     if (!G_VALUE_HOLDS_FLOAT(&value))
1299         return 0;
1300
1301     return g_value_get_float(&value);
1302 #endif
1303 }
1304
1305 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
1306 {
1307     // FIXME: implement
1308     return JSStringCreateWithCharacters(0, 0);
1309 }
1310
1311 int AccessibilityUIElement::insertionPointLineNumber()
1312 {
1313     // FIXME: implement
1314     return -1;
1315 }
1316
1317 bool AccessibilityUIElement::isPressActionSupported()
1318 {
1319     if (!ATK_IS_ACTION(m_element.get()))
1320         return false;
1321
1322     const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element.get()), 0);
1323     return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump"));
1324 }
1325
1326 bool AccessibilityUIElement::isIncrementActionSupported()
1327 {
1328     // FIXME: implement
1329     return false;
1330 }
1331
1332 bool AccessibilityUIElement::isDecrementActionSupported()
1333 {
1334     // FIXME: implement
1335     return false;
1336 }
1337
1338 bool AccessibilityUIElement::isEnabled()
1339 {
1340     return checkElementState(m_element.get(), ATK_STATE_ENABLED);
1341 }
1342
1343 bool AccessibilityUIElement::isRequired() const
1344 {
1345     return checkElementState(m_element.get(), ATK_STATE_REQUIRED);
1346 }
1347
1348 bool AccessibilityUIElement::isFocused() const
1349 {
1350     return checkElementState(m_element.get(), ATK_STATE_FOCUSED);
1351 }
1352
1353 bool AccessibilityUIElement::isSelected() const
1354 {
1355     return checkElementState(m_element.get(), ATK_STATE_SELECTED);
1356 }
1357
1358 bool AccessibilityUIElement::isSelectedOptionActive() const
1359 {
1360     return checkElementState(m_element.get(), ATK_STATE_ACTIVE);
1361 }
1362
1363 bool AccessibilityUIElement::isExpanded() const
1364 {
1365     return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
1366 }
1367
1368 bool AccessibilityUIElement::isChecked() const
1369 {
1370     return checkElementState(m_element.get(), ATK_STATE_CHECKED);
1371 }
1372
1373 bool AccessibilityUIElement::isIndeterminate() const
1374 {
1375     return checkElementState(m_element.get(), ATK_STATE_INDETERMINATE);
1376 }
1377
1378 int AccessibilityUIElement::hierarchicalLevel() const
1379 {
1380     // FIXME: implement
1381     return 0;
1382 }
1383
1384 JSRetainPtr<JSStringRef> AccessibilityUIElement::speak()
1385 {
1386     // FIXME: implement
1387     return JSStringCreateWithCharacters(0, 0);
1388 }
1389
1390 bool AccessibilityUIElement::ariaIsGrabbed() const
1391 {
1392     // FIXME: implement
1393     return false;
1394 }
1395
1396 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
1397 {
1398     // FIXME: implement
1399     return JSStringCreateWithCharacters(0, 0);
1400 }
1401
1402 // parameterized attributes
1403 int AccessibilityUIElement::lineForIndex(int index)
1404 {
1405     if (!ATK_IS_TEXT(m_element.get()))
1406         return -1;
1407
1408     if (index < 0 || index > atk_text_get_character_count(ATK_TEXT(m_element.get())))
1409         return -1;
1410
1411     GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, index));
1412     int lineNo = 0;
1413     for (gchar* offset = text.get(); *offset; ++offset) {
1414         if (*offset == '\n')
1415             ++lineNo;
1416     }
1417
1418     return lineNo;
1419 }
1420
1421 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
1422 {
1423     // FIXME: implement
1424     return JSStringCreateWithCharacters(0, 0);
1425 }
1426
1427 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
1428 {
1429     // FIXME: implement
1430     return JSStringCreateWithCharacters(0, 0);
1431 }
1432
1433 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
1434 {
1435     // FIXME: implement
1436     return JSStringCreateWithCharacters(0, 0);
1437 }
1438
1439 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
1440 {
1441     if (!ATK_IS_TEXT(m_element.get()))
1442         return JSStringCreateWithCharacters(0, 0);
1443
1444     String string = atk_text_get_text(ATK_TEXT(m_element.get()), location, location + length);
1445     return JSStringCreateWithUTF8CString(string.utf8().data());
1446 }
1447
1448 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
1449 {
1450     // FIXME: implement
1451     return JSStringCreateWithCharacters(0, 0);
1452 }
1453
1454 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
1455 {
1456     // FIXME: implement
1457     return false;
1458 }
1459
1460 unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
1461 {
1462     // FIXME: implement
1463     return 0;
1464 }
1465
1466 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
1467 {
1468     // FIXME: implement
1469     return nullptr;
1470 }
1471
1472 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
1473 {
1474     // FIXME: implement
1475     return nullptr;
1476 }
1477
1478 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
1479 {
1480     if (!ATK_IS_TABLE(m_element.get()))
1481         return JSStringCreateWithCharacters(0, 0);
1482
1483     Vector<RefPtr<AccessibilityUIElement> > columnHeaders = getColumnHeaders(ATK_TABLE(m_element.get()));
1484     return createStringWithAttributes(columnHeaders);
1485 }
1486
1487 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
1488 {
1489     if (!ATK_IS_TABLE(m_element.get()))
1490         return JSStringCreateWithCharacters(0, 0);
1491
1492     Vector<RefPtr<AccessibilityUIElement> > rowHeaders = getRowHeaders(ATK_TABLE(m_element.get()));
1493     return createStringWithAttributes(rowHeaders);
1494 }
1495
1496 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
1497 {
1498     // FIXME: implement
1499     return JSStringCreateWithCharacters(0, 0);
1500 }
1501
1502 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
1503 {
1504     // FIXME: implement
1505     return JSStringCreateWithCharacters(0, 0);
1506 }
1507
1508 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
1509 {
1510     if (!ATK_IS_TABLE(m_element.get()))
1511         return JSStringCreateWithCharacters(0, 0);
1512
1513     Vector<RefPtr<AccessibilityUIElement> > visibleCells = getVisibleCells(this);
1514     return createStringWithAttributes(visibleCells);
1515 }
1516
1517 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
1518 {
1519     // FIXME: implement
1520     return JSStringCreateWithCharacters(0, 0);
1521 }
1522
1523 int AccessibilityUIElement::rowCount()
1524 {
1525     if (!ATK_IS_TABLE(m_element.get()))
1526         return 0;
1527
1528     return atk_table_get_n_rows(ATK_TABLE(m_element.get()));
1529 }
1530
1531 int AccessibilityUIElement::columnCount()
1532 {
1533     if (!ATK_IS_TABLE(m_element.get()))
1534         return 0;
1535
1536     return atk_table_get_n_columns(ATK_TABLE(m_element.get()));
1537 }
1538
1539 int AccessibilityUIElement::indexInTable()
1540 {
1541     // FIXME: implement
1542     return -1;
1543 }
1544
1545 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
1546 {
1547     // Range in table for rows.
1548     return indexRangeInTable(m_element.get(), true);
1549 }
1550
1551 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
1552 {
1553     // Range in table for columns.
1554     return indexRangeInTable(m_element.get(), false);
1555 }
1556
1557 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
1558 {
1559     if (!ATK_IS_TABLE(m_element.get()))
1560         return nullptr;
1561
1562     // Adopt the AtkObject representing the cell because
1563     // at_table_ref_at() transfers full ownership.
1564     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col));
1565     return foundCell ? AccessibilityUIElement::create(foundCell.get()) : nullptr;
1566 }
1567
1568 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
1569 {
1570     // FIXME: implement
1571     return nullptr;
1572 }
1573
1574 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
1575 {
1576     // FIXME: implement
1577     return nullptr;
1578 }
1579
1580 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
1581 {
1582     if (!ATK_IS_TEXT(m_element.get()))
1583         return JSStringCreateWithCharacters(0, 0);
1584
1585     gint start, end;
1586     g_free(atk_text_get_selection(ATK_TEXT(m_element.get()), 0, &start, &end));
1587
1588     GUniquePtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start));
1589     return JSStringCreateWithUTF8CString(selection.get());
1590 }
1591
1592 bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
1593 {
1594     if (!ATK_IS_TEXT(m_element.get()))
1595         return false;
1596
1597     if (!length)
1598         return atk_text_set_caret_offset(ATK_TEXT(m_element.get()), location);
1599
1600     return atk_text_set_selection(ATK_TEXT(m_element.get()), 0, location, location + length);
1601 }
1602
1603 void AccessibilityUIElement::increment()
1604 {
1605     alterCurrentValue(m_element.get(), 1);
1606 }
1607
1608 void AccessibilityUIElement::decrement()
1609 {
1610     alterCurrentValue(m_element.get(), -1);
1611 }
1612
1613 void AccessibilityUIElement::showMenu()
1614 {
1615     // FIXME: implement
1616 }
1617
1618 void AccessibilityUIElement::press()
1619 {
1620     if (!ATK_IS_ACTION(m_element.get()))
1621         return;
1622
1623     // Only one action per object is supported so far.
1624     atk_action_do_action(ATK_ACTION(m_element.get()), 0);
1625 }
1626
1627 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
1628 {
1629     // FIXME: implement
1630 }
1631
1632 void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
1633 {
1634     if (!ATK_IS_SELECTION(m_element.get()))
1635         return;
1636
1637     atk_selection_add_selection(ATK_SELECTION(m_element.get()), index);
1638 }
1639
1640 void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
1641 {
1642     if (!ATK_IS_SELECTION(m_element.get()))
1643         return;
1644
1645     atk_selection_remove_selection(ATK_SELECTION(m_element.get()), index);
1646 }
1647
1648 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
1649 {
1650     // FIXME: implement
1651     return JSStringCreateWithCharacters(0, 0);
1652 }
1653
1654 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
1655 {
1656     if (!ATK_IS_DOCUMENT(m_element.get()))
1657         return JSStringCreateWithCharacters(0, 0);
1658
1659     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1660     if (role != ATK_ROLE_DOCUMENT_FRAME)
1661         return JSStringCreateWithCharacters(0, 0);
1662
1663     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding"));
1664 }
1665
1666 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
1667 {
1668     if (!ATK_IS_DOCUMENT(m_element.get()))
1669         return JSStringCreateWithCharacters(0, 0);
1670
1671     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
1672     if (role != ATK_ROLE_DOCUMENT_FRAME)
1673         return JSStringCreateWithCharacters(0, 0);
1674
1675     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI"));
1676 }
1677
1678 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
1679 {
1680     if (!ATK_IS_HYPERLINK_IMPL(m_element.get()))
1681         return JSStringCreateWithCharacters(0, 0);
1682
1683     AtkHyperlink* hyperlink = atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(m_element.get()));
1684     GUniquePtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0));
1685
1686     // Build the result string, stripping the absolute URL paths if present.
1687     char* localURI = g_strstr_len(hyperlinkURI.get(), -1, "LayoutTests");
1688     String axURL = String::format("AXURL: %s", localURI ? localURI : hyperlinkURI.get());
1689     return JSStringCreateWithUTF8CString(axURL.utf8().data());
1690 }
1691
1692 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
1693 {
1694     if (!functionCallback)
1695         return false;
1696
1697     // Only one notification listener per element.
1698     if (m_notificationHandler)
1699         return false;
1700
1701     m_notificationHandler = AccessibilityNotificationHandler::create();
1702     m_notificationHandler->setPlatformElement(platformUIElement());
1703     m_notificationHandler->setNotificationFunctionCallback(functionCallback);
1704
1705     return true;
1706 }
1707
1708 bool AccessibilityUIElement::removeNotificationListener()
1709 {
1710     // Programmers should not be trying to remove a listener that's already removed.
1711     ASSERT(m_notificationHandler);
1712     m_notificationHandler = nullptr;
1713
1714     return true;
1715 }
1716
1717 bool AccessibilityUIElement::isFocusable() const
1718 {
1719     return checkElementState(m_element.get(), ATK_STATE_FOCUSABLE);
1720 }
1721
1722 bool AccessibilityUIElement::isSelectable() const
1723 {
1724     return checkElementState(m_element.get(), ATK_STATE_SELECTABLE);
1725 }
1726
1727 bool AccessibilityUIElement::isMultiSelectable() const
1728 {
1729     return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE);
1730 }
1731
1732 bool AccessibilityUIElement::isVisible() const
1733 {
1734     return checkElementState(m_element.get(), ATK_STATE_VISIBLE);
1735 }
1736
1737 bool AccessibilityUIElement::isOffScreen() const
1738 {
1739     // FIXME: implement
1740     return false;
1741 }
1742
1743 bool AccessibilityUIElement::isCollapsed() const
1744 {
1745     // FIXME: implement
1746     return false;
1747 }
1748
1749 bool AccessibilityUIElement::isIgnored() const
1750 {
1751     // FIXME: implement
1752     return false;
1753 }
1754
1755 bool AccessibilityUIElement::hasPopup() const
1756 {
1757     if (!ATK_IS_OBJECT(m_element.get()))
1758         return false;
1759
1760     String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "haspopup");
1761     return equalIgnoringCase(hasPopupValue, "true");
1762 }
1763
1764 void AccessibilityUIElement::takeFocus()
1765 {
1766     // FIXME: implement
1767 }
1768
1769 void AccessibilityUIElement::takeSelection()
1770 {
1771     // FIXME: implement
1772 }
1773
1774 void AccessibilityUIElement::addSelection()
1775 {
1776     // FIXME: implement
1777 }
1778
1779 void AccessibilityUIElement::removeSelection()
1780 {
1781     // FIXME: implement
1782 }
1783
1784 // Text markers
1785 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1786 {
1787     // FIXME: implement
1788     return nullptr;
1789 }
1790
1791 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1792 {
1793     // FIXME: implement
1794     return nullptr;
1795 }
1796
1797 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1798 {
1799     // FIXME: implement
1800     return 0;
1801 }
1802
1803 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1804 {
1805     // FIXME: implement
1806     return nullptr;
1807 }
1808
1809 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1810 {
1811     // FIXME: implement
1812     return nullptr;
1813 }
1814
1815 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1816 {
1817     // FIXME: implement
1818     return JSStringCreateWithCharacters(0, 0);
1819 }
1820
1821 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1822 {
1823     // FIXME: implement
1824     return nullptr;
1825 }
1826
1827 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1828 {
1829     // FIXME: implement
1830     return nullptr;
1831 }
1832
1833 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1834 {
1835     // FIXME: implement
1836     return nullptr;
1837 }
1838
1839 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
1840 {
1841     // FIXME: implement
1842     return nullptr;
1843 }
1844
1845 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
1846 {
1847     // FIXME: implement
1848     return nullptr;
1849 }
1850
1851 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1852 {
1853     // FIXME: implement
1854     return nullptr;
1855 }
1856
1857 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1858 {
1859     // FIXME: implement
1860     return nullptr;
1861 }
1862
1863 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1864 {
1865     // FIXME: implement
1866     return false;
1867 }
1868
1869 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1870 {
1871     // FIXME: implement
1872     return -1;
1873 }
1874
1875 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1876 {
1877     // FIXME: implement
1878     return false;
1879 }
1880
1881 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1882 {
1883     // FIXME: implement
1884     return nullptr;
1885 }
1886     
1887 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
1888 {
1889     // FIXME: implement
1890     return nullptr;    
1891 }
1892
1893 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
1894 {
1895     // FIXME: implement
1896     return nullptr;
1897 }
1898
1899 void AccessibilityUIElement::scrollToMakeVisible()
1900 {
1901     // FIXME: implement
1902 }
1903
1904 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1905 {
1906     // FIXME: implement
1907     return nullptr;
1908 }
1909
1910 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1911 {
1912     notImplemented();
1913     return nullptr;
1914 }
1915
1916 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1917 {
1918     notImplemented();
1919     return nullptr;
1920 }
1921
1922 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1923 {
1924     notImplemented();
1925     return nullptr;
1926 }
1927
1928 JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
1929 {
1930     notImplemented();
1931     return nullptr;
1932 }
1933
1934 JSRetainPtr<JSStringRef> stringAtOffset(PlatformUIElement element, AtkTextBoundary boundary, int offset)
1935 {
1936     if (!ATK_IS_TEXT(element.get()))
1937         return JSStringCreateWithCharacters(0, 0);
1938
1939     gint startOffset, endOffset;
1940     StringBuilder builder;
1941
1942 #if ATK_CHECK_VERSION(2, 10, 0)
1943     AtkTextGranularity granularity;
1944     switch (boundary) {
1945     case ATK_TEXT_BOUNDARY_CHAR:
1946         granularity = ATK_TEXT_GRANULARITY_CHAR;
1947         break;
1948     case ATK_TEXT_BOUNDARY_WORD_START:
1949         granularity = ATK_TEXT_GRANULARITY_WORD;
1950         break;
1951     case ATK_TEXT_BOUNDARY_LINE_START:
1952         granularity = ATK_TEXT_GRANULARITY_LINE;
1953         break;
1954     case ATK_TEXT_BOUNDARY_SENTENCE_START:
1955         granularity = ATK_TEXT_GRANULARITY_SENTENCE;
1956         break;
1957     default:
1958         return JSStringCreateWithCharacters(0, 0);
1959     }
1960
1961     builder.append(atk_text_get_string_at_offset(ATK_TEXT(element.get()), offset, granularity, &startOffset, &endOffset));
1962 #else
1963     builder.append(atk_text_get_text_at_offset(ATK_TEXT(element.get()), offset, boundary, &startOffset, &endOffset));
1964 #endif
1965     builder.append(String::format(", %i, %i", startOffset, endOffset));
1966     return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
1967 }
1968
1969 JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int offset)
1970 {
1971     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_CHAR, offset);
1972 }
1973
1974 JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int offset)
1975 {
1976     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_WORD_START, offset);
1977 }
1978
1979 JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int offset)
1980 {
1981     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_LINE_START, offset);
1982 }
1983
1984 JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int offset)
1985 {
1986     return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_SENTENCE_START, offset);
1987 }
1988
1989 } // namespace WTR
1990
1991 #endif // HAVE(ACCESSIBILITY)