[CMake] Properly test if compiler supports compiler flags
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / atk / AccessibilityUIElementAtk.cpp
index 2b9b892..1430d94 100644 (file)
 #include "NotImplemented.h"
 #include <JavaScriptCore/JSStringRef.h>
 #include <JavaScriptCore/OpaqueJSString.h>
+#if ATK_CHECK_VERSION(2,11,90)
+#include <WebKit/WKBundleFrame.h>
+#endif
 #include <atk/atk.h>
 #include <wtf/Assertions.h>
-#include <wtf/gobject/GOwnPtr.h>
-#include <wtf/gobject/GRefPtr.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/GUniquePtr.h>
 #include <wtf/text/CString.h>
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/WTFString.h>
@@ -48,6 +51,13 @@ namespace WTR {
 
 namespace {
 
+#if ATK_CHECK_VERSION(2,11,92)
+enum RangeLimit {
+    RangeLimitMinimum,
+    RangeLimitMaximum
+};
+#endif
+
 enum AtkAttributeType {
     ObjectAttributeType,
     TextAttributeType
@@ -61,8 +71,17 @@ enum AttributeDomain {
 enum AttributesIndex {
     // Attribute names.
     InvalidNameIndex = 0,
+    ColumnCount,
+    ColumnIndex,
+    ColumnSpan,
+    RowCount,
+    RowIndex,
+    RowSpan,
+    PosInSetIndex,
+    SetSizeIndex,
     PlaceholderNameIndex,
     SortNameIndex,
+    CurrentNameIndex,
 
     // Attribute values.
     SortAscendingValueIndex,
@@ -76,8 +95,17 @@ enum AttributesIndex {
 const String attributesMap[][2] = {
     // Attribute names.
     { "AXInvalid", "invalid" },
+    { "AXARIAColumnCount", "colcount" },
+    { "AXARIAColumnIndex", "colindex" },
+    { "AXARIAColumnSpan", "colspan" },
+    { "AXARIARowCount", "rowcount" },
+    { "AXARIARowIndex", "rowindex" },
+    { "AXARIARowSpan", "rowspan" },
+    { "AXARIAPosInSet", "posinset" },
+    { "AXARIASetSize", "setsize" },
     { "AXPlaceholderValue", "placeholder-text" } ,
     { "AXSortDirection", "sort" },
+    { "AXARIACurrent", "current" },
 
     // Attribute values.
     { "AXAscendingSortDirection", "ascending" },
@@ -85,13 +113,28 @@ const String attributesMap[][2] = {
     { "AXUnknownSortDirection", "unknown" }
 };
 
-String coreAttributeToAtkAttribute(JSStringRef attribute)
+#if ATK_CHECK_VERSION(2, 11, 3)
+const char* landmarkStringBanner = "AXLandmarkBanner";
+const char* landmarkStringComplementary = "AXLandmarkComplementary";
+const char* landmarkStringContentinfo = "AXLandmarkContentInfo";
+const char* landmarkStringMain = "AXLandmarkMain";
+const char* landmarkStringNavigation = "AXLandmarkNavigation";
+const char* landmarkStringRegion = "AXLandmarkRegion";
+const char* landmarkStringSearch = "AXLandmarkSearch";
+#endif
+
+String jsStringToWTFString(JSStringRef attribute)
 {
     size_t bufferSize = JSStringGetMaximumUTF8CStringSize(attribute);
-    GOwnPtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize)));
+    GUniquePtr<gchar> buffer(static_cast<gchar*>(g_malloc(bufferSize)));
     JSStringGetUTF8CString(attribute, buffer.get(), bufferSize);
 
-    String attributeString = String::fromUTF8(buffer.get());
+    return String::fromUTF8(buffer.get());
+}
+
+String coreAttributeToAtkAttribute(JSStringRef attribute)
+{
+    String attributeString = jsStringToWTFString(attribute);
     for (int i = 0; i < NumberOfAttributes; ++i) {
         if (attributesMap[i][CoreDomain] == attributeString)
             return attributesMap[i][AtkDomain];
@@ -103,6 +146,10 @@ String coreAttributeToAtkAttribute(JSStringRef attribute)
 String atkAttributeValueToCoreAttributeValue(AtkAttributeType type, const String& id, const String& value)
 {
     if (type == ObjectAttributeType) {
+        // We don't expose the "current" attribute if there is no author-provided value.
+        if (id == attributesMap[CurrentNameIndex][AtkDomain] && value.isEmpty())
+            return "false";
+
         // We need to translate ATK values exposed for 'aria-sort' (e.g. 'ascending')
         // into those expected by the layout tests (e.g. 'AXAscendingSortDirection').
         if (id == attributesMap[SortNameIndex][AtkDomain] && !value.isEmpty()) {
@@ -130,13 +177,13 @@ AtkAttributeSet* getAttributeSet(AtkObject* accessible, AtkAttributeType type)
 
     if (type == TextAttributeType) {
         if (!ATK_IS_TEXT(accessible))
-            return 0;
+            return nullptr;
 
         return atk_text_get_default_attributes(ATK_TEXT(accessible));
     }
 
     ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
 String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, String id)
@@ -158,25 +205,29 @@ String getAttributeSetValueForId(AtkObject* accessible, AtkAttributeType type, S
     return atkAttributeValueToCoreAttributeValue(type, id, attributeValue);
 }
 
-String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type)
+String attributeSetToString(AtkAttributeSet* attributeSet, String separator=", ")
 {
-    AtkAttributeSet* attributeSet = getAttributeSet(accessible, type);
     if (!attributeSet)
         return String();
 
     StringBuilder builder;
     for (AtkAttributeSet* attributes = attributeSet; attributes; attributes = attributes->next) {
         AtkAttribute* attribute = static_cast<AtkAttribute*>(attributes->data);
-        GOwnPtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
+        GUniquePtr<gchar> attributeData(g_strconcat(attribute->name, ":", attribute->value, NULL));
         builder.append(attributeData.get());
         if (attributes->next)
-            builder.append(", ");
+            builder.append(separator);
     }
     atk_attribute_set_free(attributeSet);
 
     return builder.toString();
 }
 
+String getAtkAttributeSetAsString(AtkObject* accessible, AtkAttributeType type,  String separator=", ")
+{
+    return attributeSetToString(getAttributeSet(accessible, type), separator);
+}
+
 bool checkElementState(PlatformUIElement element, AtkStateType stateType)
 {
     if (!ATK_IS_OBJECT(element.get()))
@@ -188,8 +239,11 @@ bool checkElementState(PlatformUIElement element, AtkStateType stateType)
 
 JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
 {
-    GOwnPtr<gchar> rangeString(g_strdup("{0, 0}"));
-
+    GUniquePtr<gchar> rangeString(g_strdup("{0, 0}"));
+#if ATK_CHECK_VERSION(2,11,90)
+    if (!ATK_IS_TABLE_CELL(element.get()))
+        return JSStringCreateWithUTF8CString(rangeString.get());
+#else
     if (!ATK_IS_OBJECT(element.get()))
         return JSStringCreateWithUTF8CString(rangeString.get());
 
@@ -201,11 +255,20 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
     gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element.get()));
     if (indexInParent == -1)
         return JSStringCreateWithUTF8CString(rangeString.get());
-
-    int row = -1;
-    int column = -1;
+#endif
+
+    gint row = -1;
+    gint column = -1;
+    gint rowSpan = -1;
+    gint columnSpan = -1;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_table_cell_get_row_column_span(ATK_TABLE_CELL(element.get()), &row, &column, &rowSpan, &columnSpan);
+#else
     row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent);
     column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent);
+    rowSpan = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
+    columnSpan = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
+#endif
 
     // Get the actual values, if row and columns are valid values.
     if (row != -1 && column != -1) {
@@ -213,12 +276,12 @@ JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange)
         int length = 0;
         if (isRowRange) {
             base = row;
-            length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column);
+            length = rowSpan;
         } else {
             base = column;
-            length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column);
+            length = columnSpan;
         }
-        rangeString.set(g_strdup_printf("{%d, %d}", base, length));
+        rangeString.reset(g_strdup_printf("{%d, %d}", base, length));
     }
 
     return JSStringCreateWithUTF8CString(rangeString.get());
@@ -229,6 +292,13 @@ void alterCurrentValue(PlatformUIElement element, int factor)
     if (!ATK_IS_VALUE(element.get()))
         return;
 
+#if ATK_CHECK_VERSION(2,11,92)
+    double currentValue;
+    atk_value_get_value_and_text(ATK_VALUE(element.get()), &currentValue, nullptr);
+
+    double increment = atk_value_get_increment(ATK_VALUE(element.get()));
+    atk_value_set_value(ATK_VALUE(element.get()), currentValue + factor * increment);
+#else
     GValue currentValue = G_VALUE_INIT;
     atk_value_get_current_value(ATK_VALUE(element.get()), &currentValue);
 
@@ -244,6 +314,7 @@ void alterCurrentValue(PlatformUIElement element, int factor)
     g_value_unset(&newValue);
     g_value_unset(&increment);
     g_value_unset(&currentValue);
+#endif
 }
 
 gchar* replaceCharactersForResults(gchar* str)
@@ -262,13 +333,79 @@ gchar* replaceCharactersForResults(gchar* str)
     return g_strdup(uString.utf8().data());
 }
 
-const gchar* roleToString(AtkRole role)
-{
+const gchar* roleToString(AtkObject* object)
+{
+    AtkRole role = atk_object_get_role(object);
+
+#if ATK_CHECK_VERSION(2, 11, 3)
+    if (role == ATK_ROLE_LANDMARK) {
+        String xmlRolesValue = getAttributeSetValueForId(object, ObjectAttributeType, "xml-roles");
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "banner"))
+            return landmarkStringBanner;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "complementary"))
+            return landmarkStringComplementary;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "contentinfo"))
+            return landmarkStringContentinfo;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-acknowledgments"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-afterword"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-appendix"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-bibliography"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-chapter"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-conclusion"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-credits"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-endnotes"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-epilogue"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-errata"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-foreword"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-glossary"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-glossref"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-index"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-introduction"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-pagelist"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-part"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-preface"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-prologue"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "doc-toc"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "main"))
+            return landmarkStringMain;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "navigation"))
+            return landmarkStringNavigation;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "region"))
+            return landmarkStringRegion;
+        if (equalLettersIgnoringASCIICase(xmlRolesValue, "search"))
+            return landmarkStringSearch;
+    }
+#endif
+
     switch (role) {
     case ATK_ROLE_ALERT:
         return "AXAlert";
+    case ATK_ROLE_DIALOG:
+        return "AXDialog";
     case ATK_ROLE_CANVAS:
         return "AXCanvas";
+    case ATK_ROLE_CAPTION:
+        return "AXCaption";
     case ATK_ROLE_CHECK_BOX:
         return "AXCheckBox";
     case ATK_ROLE_COLOR_CHOOSER:
@@ -277,7 +414,11 @@ const gchar* roleToString(AtkRole role)
         return "AXColumnHeader";
     case ATK_ROLE_COMBO_BOX:
         return "AXComboBox";
+    case ATK_ROLE_COMMENT:
+        return "AXComment";
     case ATK_ROLE_DOCUMENT_FRAME:
+        return "AXDocument";
+    case ATK_ROLE_DOCUMENT_WEB:
         return "AXWebArea";
     case ATK_ROLE_EMBEDDED:
         return "AXEmbedded";
@@ -295,8 +436,12 @@ const gchar* roleToString(AtkRole role)
         return "AXImage";
     case ATK_ROLE_IMAGE_MAP:
         return "AXImageMap";
+    case ATK_ROLE_INVALID:
+        return "AXInvalid";
     case ATK_ROLE_LABEL:
         return "AXLabel";
+    case ATK_ROLE_LEVEL_BAR:
+        return "AXProgressIndicator";
     case ATK_ROLE_LINK:
         return "AXLink";
     case ATK_ROLE_LIST:
@@ -331,6 +476,8 @@ const gchar* roleToString(AtkRole role)
         return "AXRadioMenuItem";
     case ATK_ROLE_ROW_HEADER:
         return "AXRowHeader";
+    case ATK_ROLE_CHECK_MENU_ITEM:
+        return "AXCheckMenuItem";
     case ATK_ROLE_RULER:
         return "AXRuler";
     case ATK_ROLE_SCROLL_BAR:
@@ -338,13 +485,15 @@ const gchar* roleToString(AtkRole role)
     case ATK_ROLE_SCROLL_PANE:
         return "AXScrollArea";
     case ATK_ROLE_SECTION:
-        return "AXDiv";
+        return "AXSection";
     case ATK_ROLE_SEPARATOR:
-        return "AXHorizontalRule";
+        return "AXSeparator";
     case ATK_ROLE_SLIDER:
         return "AXSlider";
     case ATK_ROLE_SPIN_BUTTON:
         return "AXSpinButton";
+    case ATK_ROLE_STATUSBAR:
+        return "AXStatusBar";
     case ATK_ROLE_TABLE:
         return "AXTable";
     case ATK_ROLE_TABLE_CELL:
@@ -371,6 +520,52 @@ const gchar* roleToString(AtkRole role)
         return "AXWindow";
     case ATK_ROLE_UNKNOWN:
         return "AXUnknown";
+#if ATK_CHECK_VERSION(2, 11, 3)
+    case ATK_ROLE_ARTICLE:
+        return "AXArticle";
+    case ATK_ROLE_AUDIO:
+        return "AXAudio";
+    case ATK_ROLE_BLOCK_QUOTE:
+        return "AXBlockquote";
+    case ATK_ROLE_DEFINITION:
+        return "AXDefinition";
+    case ATK_ROLE_LOG:
+        return "AXLog";
+    case ATK_ROLE_MARQUEE:
+        return "AXMarquee";
+    case ATK_ROLE_MATH:
+        return "AXMath";
+    case ATK_ROLE_TIMER:
+        return "AXTimer";
+    case ATK_ROLE_VIDEO:
+        return "AXVideo";
+#endif
+#if ATK_CHECK_VERSION(2, 11, 4)
+    case ATK_ROLE_DESCRIPTION_LIST:
+        return "AXDescriptionList";
+    case ATK_ROLE_DESCRIPTION_TERM:
+        return "AXDescriptionTerm";
+    case ATK_ROLE_DESCRIPTION_VALUE:
+        return "AXDescriptionValue";
+#endif
+#if ATK_CHECK_VERSION(2, 15, 2)
+    case ATK_ROLE_STATIC:
+        return "AXStatic";
+#endif
+#if ATK_CHECK_VERSION(2, 15, 4)
+    case ATK_ROLE_MATH_FRACTION:
+        return "AXMathFraction";
+    case ATK_ROLE_MATH_ROOT:
+        return "AXMathRoot";
+    case ATK_ROLE_SUBSCRIPT:
+        return "AXSubscript";
+    case ATK_ROLE_SUPERSCRIPT:
+        return "AXSuperscript";
+#endif
+#if ATK_CHECK_VERSION(2, 25, 2)
+    case ATK_ROLE_FOOTNOTE:
+        return "AXFootnote";
+#endif
     default:
         // We want to distinguish ATK_ROLE_UNKNOWN from a known AtkRole which
         // our DRT isn't properly handling.
@@ -378,6 +573,19 @@ const gchar* roleToString(AtkRole role)
     }
 }
 
+String selectedText(AtkObject* accessible)
+{
+    if (!ATK_IS_TEXT(accessible))
+        return String();
+
+    AtkText* text = ATK_TEXT(accessible);
+
+    gint start, end;
+    g_free(atk_text_get_selection(text, 0, &start, &end));
+
+    return atk_text_get_text(text, start, end);
+}
+
 String attributesOfElement(AccessibilityUIElement* element)
 {
     StringBuilder builder;
@@ -387,9 +595,9 @@ String attributesOfElement(AccessibilityUIElement* element)
     // For the parent we print its role and its name, if available.
     builder.append("AXParent: ");
     RefPtr<AccessibilityUIElement> parent = element->parentElement();
-    AtkObject* atkParent = parent ? parent->platformUIElement().get() : 0;
+    AtkObject* atkParent = parent ? parent->platformUIElement().get() : nullptr;
     if (atkParent) {
-        builder.append(roleToString(atk_object_get_role(atkParent)));
+        builder.append(roleToString(atkParent));
         const char* parentName = atk_object_get_name(atkParent);
         if (parentName && g_utf8_strlen(parentName, -1))
             builder.append(String::format(": %s", parentName));
@@ -484,6 +692,53 @@ static Vector<RefPtr<AccessibilityUIElement> > getVisibleCells(AccessibilityUIEl
     return visibleCells;
 }
 
+#if ATK_CHECK_VERSION(2,11,90)
+static Vector<RefPtr<AccessibilityUIElement>> convertGPtrArrayToVector(const GPtrArray* array)
+{
+    Vector<RefPtr<AccessibilityUIElement>> cells;
+    for (guint i = 0; i < array->len; i++) {
+        if (AtkObject* atkObject = static_cast<AtkObject*>(g_ptr_array_index(array, i)))
+            cells.append(AccessibilityUIElement::create(atkObject));
+    }
+    return cells;
+}
+
+static JSValueRef convertToJSObjectArray(const Vector<RefPtr<AccessibilityUIElement>>& children)
+{
+    WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+    JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+
+    size_t elementCount = children.size();
+    auto valueElements = std::make_unique<JSValueRef[]>(elementCount);
+    for (size_t i = 0; i < elementCount; i++)
+        valueElements[i] = JSObjectMake(context, children[i]->wrapperClass(), children[i].get());
+
+    return JSObjectMakeArray(context, elementCount, valueElements.get(), nullptr);
+}
+#endif
+
+#if ATK_CHECK_VERSION(2,11,92)
+static double rangeMinMaxValue(AtkValue* atkValue, RangeLimit rangeLimit)
+{
+    AtkRange* range = atk_value_get_range(atkValue);
+    if (!range)
+        return 0;
+
+    double rangeValue = 0;
+    switch (rangeLimit) {
+    case RangeLimitMinimum:
+        rangeValue = atk_range_get_lower_limit(range);
+        break;
+    case RangeLimitMaximum:
+        rangeValue = atk_range_get_upper_limit(range);
+        break;
+    };
+
+    atk_range_free(range);
+    return rangeValue;
+}
+#endif
+
 } // namespace
 
 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
@@ -537,10 +792,10 @@ int AccessibilityUIElement::childrenCount()
     return atk_object_get_n_accessible_children(ATK_OBJECT(m_element.get()));
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
 {
     if (!ATK_IS_COMPONENT(m_element.get()))
-        return 0;
+        return nullptr;
 
     GRefPtr<AtkObject> objectAtPoint = adoptGRef(atk_component_ref_accessible_at_point(ATK_COMPONENT(m_element.get()), x, y, ATK_XY_WINDOW));
     return AccessibilityUIElement::create(objectAtPoint ? objectAtPoint.get() : m_element.get());
@@ -562,10 +817,10 @@ unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
     return 0;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
 {
     if (!ATK_IS_OBJECT(m_element.get()))
-        return 0;
+        return nullptr;
 
     Vector<RefPtr<AccessibilityUIElement> > children;
     getChildrenWithRange(children, index, 1);
@@ -573,67 +828,175 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned
     if (children.size() == 1)
         return children[0];
 
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
+static RefPtr<AccessibilityUIElement> accessibilityElementAtIndex(AtkObject* element, AtkRelationType relationType, unsigned index)
 {
-    // FIXME: implement
-    return 0;
+    if (!ATK_IS_OBJECT(element))
+        return nullptr;
+
+    AtkRelationSet* relationSet = atk_object_ref_relation_set(element);
+    if (!relationSet)
+        return nullptr;
+
+    AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, relationType);
+    if (!relation)
+        return nullptr;
+
+    GPtrArray* targetList = atk_relation_get_target(relation);
+    if (!targetList || !targetList->len || index >= targetList->len)
+        return nullptr;
+
+    AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, index));
+    g_object_unref(relationSet);
+
+    return target ? AccessibilityUIElement::create(target).ptr() : nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
 {
-    // FIXME: implement
-    return 0;
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_NODE_PARENT_OF, index);
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsReferencingElementAtIndex(unsigned index)
 {
-    // FIXME: implement
-    return 0;
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_NODE_CHILD_OF, index);
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
 {
-    // FIXME: implement
-    return 0;
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_FLOWS_TO, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToReferencingElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_FLOWS_FROM, index);
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_CONTROLLER_FOR, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsReferencingElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_CONTROLLED_BY, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaLabelledByElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_LABELLED_BY, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaLabelledByReferencingElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_LABEL_FOR, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaDescribedByElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_DESCRIBED_BY, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaDescribedByReferencingElementAtIndex(unsigned index)
+{
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_DESCRIPTION_FOR, index);
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaDetailsElementAtIndex(unsigned index)
+{
+#if ATK_CHECK_VERSION(2, 25, 2)
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_DETAILS, index);
+#endif
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaDetailsReferencingElementAtIndex(unsigned index)
+{
+#if ATK_CHECK_VERSION(2, 25, 2)
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_DETAILS_FOR, index);
+#endif
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaErrorMessageElementAtIndex(unsigned index)
+{
+#if ATK_CHECK_VERSION(2, 25, 2)
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_ERROR_MESSAGE, index);
+#endif
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaErrorMessageReferencingElementAtIndex(unsigned index)
+{
+#if ATK_CHECK_VERSION(2, 25, 2)
+    return accessibilityElementAtIndex(m_element.get(), ATK_RELATION_ERROR_FOR, index);
+#endif
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
+{
+    // ATK doesn't have API to get an accessible row by index directly. It does, however, have
+    // API to get cells in the row specified by index. The parent of a cell should be the row.
+    AtkTable* axTable = ATK_TABLE(m_element.get());
+    unsigned nColumns = columnCount();
+    for (unsigned col = 0; col < nColumns; col++) {
+        // Find the first cell in this row that only spans one row.
+        if (atk_table_get_row_extent_at(axTable, index, col) == 1) {
+            AtkObject* cell = atk_table_ref_at(axTable, index, col);
+            return cell ? AccessibilityUIElement::create(atk_object_get_parent(cell)).ptr() : nullptr;
+        }
+    }
+
+    return nullptr;
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
+{
+    if (!ATK_SELECTION(m_element.get()))
+        return nullptr;
+
+    GRefPtr<AtkObject> child = adoptGRef(atk_selection_ref_selection(ATK_SELECTION(m_element.get()), index));
+    return child ? AccessibilityUIElement::create(child.get()).ptr() : nullptr;
 }
 
 unsigned AccessibilityUIElement::selectedChildrenCount() const
 {
-    // FIXME: implement
-    return 0;
+    if (!ATK_IS_SELECTION(m_element.get()))
+        return 0;
+    return atk_selection_get_selection_count(ATK_SELECTION(m_element.get()));
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
 {
     if (!ATK_IS_OBJECT(m_element.get()))
-        return 0;
+        return nullptr;
 
     AtkRelationSet* set = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
     if (!set)
-        return 0;
+        return nullptr;
 
-    AtkObject* target = 0;
+    AtkObject* target = nullptr;
     int count = atk_relation_set_get_n_relations(set);
     for (int i = 0; i < count; i++) {
         AtkRelation* relation = atk_relation_set_get_relation(set, i);
@@ -645,22 +1008,22 @@ PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
     }
 
     g_object_unref(set);
-    return target ? AccessibilityUIElement::create(target) : 0;
+    return target ? AccessibilityUIElement::create(target).ptr() : nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
 {
     if (!ATK_IS_OBJECT(m_element.get()))
-        return 0;
+        return nullptr;
 
     AtkObject* parent = atk_object_get_parent(ATK_OBJECT(m_element.get()));
-    return parent ? AccessibilityUIElement::create(parent) : 0;
+    return parent ? AccessibilityUIElement::create(parent).ptr() : nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
@@ -701,7 +1064,13 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe
 
     String atkAttributeName = coreAttributeToAtkAttribute(attribute);
 
-    // Try object attributes first.
+    // The value of AXSelectedText is not exposed through any AtkAttribute.
+    if (atkAttributeName == "AXSelectedText") {
+        String string = selectedText(m_element.get());
+        return JSStringCreateWithUTF8CString(string.utf8().data());
+    }
+
+    // Try object attributes before text attributes.
     String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
 
     // Try text attributes if the requested one was not found and we have an AtkText object.
@@ -727,25 +1096,181 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRe
 
 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
 {
-    // FIXME: implement
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return 0;
+
+    String atkAttributeName = coreAttributeToAtkAttribute(attribute);
+    if (atkAttributeName.isEmpty())
+        return 0;
+
+    if (atkAttributeName == "setsize" || atkAttributeName == "posinset") {
+        String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
+        if (!attributeValue.isEmpty())
+            return attributeValue.toDouble();
+    }
+
+    if (atkAttributeName.startsWith("row") || atkAttributeName.startsWith("col")) {
+        String attributeValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, atkAttributeName);
+        if (!attributeValue.isEmpty())
+            return attributeValue.toInt();
+    }
+
     return 0;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
+JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attribute) const
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
+}
+
+JSValueRef AccessibilityUIElement::rowHeaders() const
+{
+#if ATK_CHECK_VERSION(2,11,90)
+    if (!ATK_IS_TABLE_CELL(m_element.get()))
+        return nullptr;
+
+    GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_row_header_cells(ATK_TABLE_CELL(m_element.get())));
+    if (!array)
+        return nullptr;
+
+    Vector<RefPtr<AccessibilityUIElement>> rows = convertGPtrArrayToVector(array.get());
+    return convertToJSObjectArray(rows);
+#else
+    return nullptr;
+#endif
+}
+
+JSValueRef AccessibilityUIElement::columnHeaders() const
+{
+#if ATK_CHECK_VERSION(2,11,90)
+    if (!ATK_IS_TABLE_CELL(m_element.get()) && !ATK_IS_TABLE(m_element.get()))
+        return nullptr;
+
+    Vector<RefPtr<AccessibilityUIElement>> columns;
+    if (ATK_IS_TABLE_CELL(m_element.get())) {
+        GRefPtr<GPtrArray> array = adoptGRef(atk_table_cell_get_column_header_cells(ATK_TABLE_CELL(m_element.get())));
+        if (!array)
+            return nullptr;
+
+        columns = convertGPtrArrayToVector(array.get());
+    } else
+        columns = getColumnHeaders(ATK_TABLE(m_element.get()));
+    return convertToJSObjectArray(columns);
+#else
+    return nullptr;
+#endif
+}
+
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
+{
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return nullptr;
+
+    // ATK does not have this API. So we're "faking it" here on a case-by-case basis.
+    String attributeString = jsStringToWTFString(attribute);
+    AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
+    if (role == ATK_ROLE_SPIN_BUTTON && const_cast<AccessibilityUIElement*>(this)->childrenCount() == 2) {
+        if (attributeString == "AXDecrementButton")
+            return const_cast<AccessibilityUIElement*>(this)->childAtIndex(0);
+        if (attributeString == "AXIncrementButton")
+            return const_cast<AccessibilityUIElement*>(this)->childAtIndex(1);
+    }
+
+    return nullptr;
 }
 
 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
 {
-    // FIXME: implement
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return false;
+
+    String attributeString = jsStringToWTFString(attribute);
+    if (attributeString == "AXElementBusy")
+        return checkElementState(m_element.get(), ATK_STATE_BUSY);
+    if (attributeString == "AXChecked")
+        return checkElementState(m_element.get(), ATK_STATE_CHECKED);
+    if (attributeString == "AXEnabled")
+        return checkElementState(m_element.get(), ATK_STATE_ENABLED);
+    if (attributeString == "AXExpanded")
+        return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
+    if (attributeString == "AXFocused")
+        return checkElementState(m_element.get(), ATK_STATE_FOCUSED);
+    if (attributeString == "AXInvalid")
+        return checkElementState(m_element.get(), ATK_STATE_INVALID);
+    if (attributeString == "AXModal")
+        return checkElementState(m_element.get(), ATK_STATE_MODAL);
+    if (attributeString == "AXMultiSelectable")
+        return checkElementState(m_element.get(), ATK_STATE_MULTISELECTABLE);
+    if (attributeString == "AXRequired")
+        return checkElementState(m_element.get(), ATK_STATE_REQUIRED);
+    if (attributeString == "AXSelected")
+        return checkElementState(m_element.get(), ATK_STATE_SELECTED);
+    if (attributeString == "AXSupportsAutoCompletion")
+        return checkElementState(m_element.get(), ATK_STATE_SUPPORTS_AUTOCOMPLETION);
+    if (attributeString == "AXVisited")
+        return checkElementState(m_element.get(), ATK_STATE_VISITED);
+
+    if (attributeString == "AXInterfaceTable")
+        return ATK_IS_TABLE(m_element.get());
+    if (attributeString == "AXInterfaceTableCell")
+        return ATK_IS_TABLE_CELL(m_element.get());
+
     return false;
 }
 
 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
 {
-    // FIXME: implement
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return false;
+
+    String attributeString = jsStringToWTFString(attribute);
+    if (attributeString != "AXValue")
+        return false;
+
+    // ATK does not have a single state or property to indicate whether or not the value
+    // of an accessible object can be set. ATs look at several states and properties based
+    // on the type of object. If nothing explicitly indicates the value can or cannot be
+    // set, ATs make role- and interface-based decisions. We'll do something similar here.
+
+    // This state is expected to be present only for text widgets and contenteditable elements.
+    if (checkElementState(m_element.get(), ATK_STATE_EDITABLE))
+        return true;
+
+#if ATK_CHECK_VERSION(2,11,2)
+    // This state is applicable to checkboxes, radiobuttons, switches, etc.
+    if (checkElementState(m_element.get(), ATK_STATE_CHECKABLE))
+        return true;
+#endif
+
+#if ATK_CHECK_VERSION(2,15,3)
+    // This state is expected to be present only for controls and only if explicitly set.
+    if (checkElementState(m_element.get(), ATK_STATE_READ_ONLY))
+        return false;
+#endif
+
+    // We expose an object attribute to ATs when there is an author-provided ARIA property
+    // and also when there is a supported ARIA role but no author-provided value.
+    String isReadOnly = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "readonly");
+    if (!isReadOnly.isEmpty())
+        return isReadOnly == "true" ? false : true;
+
+    // If we have a native listbox or combobox and the value can be set, the options should
+    // have ATK_STATE_SELECTABLE.
+    AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
+    if (role == ATK_ROLE_LIST_BOX || role == ATK_ROLE_COMBO_BOX) {
+        if (GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(m_element.get()), 0))) {
+            if (atk_object_get_role(ATK_OBJECT(child.get())) == ATK_ROLE_MENU)
+                child = adoptGRef(atk_object_ref_accessible_child(ATK_OBJECT(child.get()), 0));
+            return child && checkElementState(child.get(), ATK_STATE_SELECTABLE);
+        }
+    }
+
+    // If we have a native element which exposes a range whose value can be set, it should
+    // be focusable and have a true range.
+    if (ATK_IS_VALUE(m_element.get()) && checkElementState(m_element.get(), ATK_STATE_FOCUSABLE))
+        return minValue() != maxValue();
+
     return false;
 }
 
@@ -777,11 +1302,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
     if (!ATK_IS_OBJECT(m_element.get()))
         return JSStringCreateWithCharacters(0, 0);
 
-    AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
-    if (!role)
-        return JSStringCreateWithCharacters(0, 0);
-
-    GOwnPtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(role)));
+    GUniquePtr<char> roleStringWithPrefix(g_strdup_printf("AXRole: %s", roleToString(ATK_OBJECT(m_element.get()))));
     return JSStringCreateWithUTF8CString(roleStringWithPrefix.get());
 }
 
@@ -793,7 +1314,18 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
 {
-    // FIXME: implement
+    String roleDescription = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "roledescription");
+    GUniquePtr<gchar> axRoleDescription(g_strdup_printf("AXRoleDescription: %s", roleDescription.utf8().data()));
+
+    return JSStringCreateWithUTF8CString(axRoleDescription.get());
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
+{
+    String role = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "computed-role");
+    if (!role.isEmpty())
+        return JSStringCreateWithUTF8CString(role.utf8().data());
+
     return JSStringCreateWithCharacters(0, 0);
 }
 
@@ -803,7 +1335,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
         return JSStringCreateWithCharacters(0, 0);
 
     const gchar* name = atk_object_get_name(ATK_OBJECT(m_element.get()));
-    GOwnPtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
+    GUniquePtr<gchar> axTitle(g_strdup_printf("AXTitle: %s", name ? name : ""));
 
     return JSStringCreateWithUTF8CString(axTitle.get());
 }
@@ -817,7 +1349,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
     if (!description)
         return JSStringCreateWithCharacters(0, 0);
 
-    GOwnPtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
+    GUniquePtr<gchar> axDesc(g_strdup_printf("AXDescription: %s", description));
 
     return JSStringCreateWithUTF8CString(axDesc.get());
 }
@@ -827,14 +1359,13 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
     if (!ATK_IS_OBJECT(m_element.get()))
         return JSStringCreateWithCharacters(0, 0);
 
-    const gchar* axOrientation = 0;
+    const gchar* axOrientation = nullptr;
     if (checkElementState(m_element.get(), ATK_STATE_HORIZONTAL))
         axOrientation = "AXOrientation: AXHorizontalOrientation";
     else if (checkElementState(m_element.get(), ATK_STATE_VERTICAL))
         axOrientation = "AXOrientation: AXVerticalOrientation";
-
-    if (!axOrientation)
-        return JSStringCreateWithCharacters(0, 0);
+    else
+        axOrientation = "AXOrientation: AXUnknownOrientation";
 
     return JSStringCreateWithUTF8CString(axOrientation);
 }
@@ -844,9 +1375,9 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
     if (!ATK_IS_TEXT(m_element.get()))
         return JSStringCreateWithCharacters(0, 0);
 
-    GOwnPtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, -1));
-    GOwnPtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
-    GOwnPtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
+    GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, -1));
+    GUniquePtr<gchar> textWithReplacedCharacters(replaceCharactersForResults(text.get()));
+    GUniquePtr<gchar> axValue(g_strdup_printf("AXValue: %s", textWithReplacedCharacters.get()));
 
     return JSStringCreateWithUTF8CString(axValue.get());
 }
@@ -860,16 +1391,42 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
     if (!locale)
         return JSStringCreateWithCharacters(0, 0);
 
-    GOwnPtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale));
+    GUniquePtr<char> axValue(g_strdup_printf("AXLanguage: %s", locale));
     return JSStringCreateWithUTF8CString(axValue.get());
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
 {
-    // FIXME: We need to provide a proper implementation for this that does
-    // not depend on Mac specific concepts such as ATK_RELATION_DESCRIBED_BY,
-    // once it's implemented (see http://webkit.org/b/121684).
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_OBJECT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkRelationSet* relationSet = atk_object_ref_relation_set(ATK_OBJECT(m_element.get()));
+    if (!relationSet)
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkRelation* relation = atk_relation_set_get_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY);
+    if (!relation)
+        return JSStringCreateWithCharacters(0, 0);
+
+    GPtrArray* targetList = atk_relation_get_target(relation);
+    if (!targetList || !targetList->len)
+        return JSStringCreateWithCharacters(0, 0);
+
+    StringBuilder builder;
+    builder.append("AXHelp: ");
+
+    for (guint targetCount = 0; targetCount < targetList->len; targetCount++) {
+        if (AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targetList, targetCount))) {
+            GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(target), 0, -1));
+            if (targetCount)
+                builder.append(" ");
+            builder.append(text.get());
+        }
+    }
+
+    g_object_unref(relationSet);
+
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
 }
 
 double AccessibilityUIElement::x()
@@ -877,8 +1434,12 @@ double AccessibilityUIElement::x()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int x, y;
-    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
+    int x;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, nullptr, nullptr, ATK_XY_SCREEN);
+#else
+    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_SCREEN);
+#endif
     return x;
 }
 
@@ -887,8 +1448,12 @@ double AccessibilityUIElement::y()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int x, y;
-    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_SCREEN);
+    int y;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, nullptr, ATK_XY_SCREEN);
+#else
+    atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_SCREEN);
+#endif
     return y;
 }
 
@@ -897,8 +1462,12 @@ double AccessibilityUIElement::width()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int width, height;
-    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+    int width;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, &width, nullptr, ATK_XY_WINDOW);
+#else
+    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
+#endif
     return width;
 }
 
@@ -907,8 +1476,12 @@ double AccessibilityUIElement::height()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int width, height;
-    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+    int height;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, nullptr, nullptr, &height, ATK_XY_WINDOW);
+#else
+    atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
+#endif
     return height;
 }
 
@@ -917,11 +1490,13 @@ double AccessibilityUIElement::clickPointX()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int x, y;
-    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW);
-
-    int width, height;
-    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+    int x, width;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), &x, nullptr, &width, nullptr, ATK_XY_WINDOW);
+#else
+    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, nullptr, ATK_XY_WINDOW);
+    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, nullptr);
+#endif
 
     return x + width / 2.0;
 }
@@ -931,11 +1506,13 @@ double AccessibilityUIElement::clickPointY()
     if (!ATK_IS_COMPONENT(m_element.get()))
         return 0;
 
-    int x, y;
-    atk_component_get_position(ATK_COMPONENT(m_element.get()), &x, &y, ATK_XY_WINDOW);
-
-    int width, height;
-    atk_component_get_size(ATK_COMPONENT(m_element.get()), &width, &height);
+    int y, height;
+#if ATK_CHECK_VERSION(2,11,90)
+    atk_component_get_extents(ATK_COMPONENT(m_element.get()), nullptr, &y, nullptr, &height, ATK_XY_WINDOW);
+#else
+    atk_component_get_position(ATK_COMPONENT(m_element.get()), nullptr, &y, ATK_XY_WINDOW);
+    atk_component_get_size(ATK_COMPONENT(m_element.get()), nullptr, &height);
+#endif
 
     return y + height / 2.0;
 }
@@ -946,11 +1523,17 @@ double AccessibilityUIElement::intValue() const
         return 0;
 
     if (ATK_IS_VALUE(m_element.get())) {
+#if ATK_CHECK_VERSION(2,11,92)
+        double value;
+        atk_value_get_value_and_text(ATK_VALUE(m_element.get()), &value, nullptr);
+        return value;
+#else
         GValue value = G_VALUE_INIT;
         atk_value_get_current_value(ATK_VALUE(m_element.get()), &value);
         if (!G_VALUE_HOLDS_FLOAT(&value))
             return 0;
         return g_value_get_float(&value);
+#endif
     }
 
     // Consider headings as an special case when returning the "int value" of
@@ -971,13 +1554,16 @@ double AccessibilityUIElement::minValue()
 {
     if (!ATK_IS_VALUE(m_element.get()))
         return 0;
-
+#if ATK_CHECK_VERSION(2,11,92)
+    return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMinimum);
+#else
     GValue value = G_VALUE_INIT;
     atk_value_get_minimum_value(ATK_VALUE(m_element.get()), &value);
     if (!G_VALUE_HOLDS_FLOAT(&value))
         return 0;
 
     return g_value_get_float(&value);
+#endif
 }
 
 double AccessibilityUIElement::maxValue()
@@ -985,18 +1571,23 @@ double AccessibilityUIElement::maxValue()
     if (!ATK_IS_VALUE(m_element.get()))
         return 0;
 
+#if ATK_CHECK_VERSION(2,11,92)
+    return rangeMinMaxValue(ATK_VALUE(m_element.get()), RangeLimitMaximum);
+#else
     GValue value = G_VALUE_INIT;
     atk_value_get_maximum_value(ATK_VALUE(m_element.get()), &value);
     if (!G_VALUE_HOLDS_FLOAT(&value))
         return 0;
 
     return g_value_get_float(&value);
+#endif
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
 {
-    // FIXME: implement
-    return JSStringCreateWithCharacters(0, 0);
+    String valueText = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "valuetext");
+    GUniquePtr<gchar> valueDescription(g_strdup_printf("AXValueDescription: %s", valueText.utf8().data()));
+    return JSStringCreateWithUTF8CString(valueDescription.get());
 }
 
 int AccessibilityUIElement::insertionPointLineNumber()
@@ -1011,7 +1602,7 @@ bool AccessibilityUIElement::isPressActionSupported()
         return false;
 
     const gchar* actionName = atk_action_get_name(ATK_ACTION(m_element.get()), 0);
-    return equalIgnoringCase(actionName, String("press")) || equalIgnoringCase(actionName, String("jump"));
+    return equalLettersIgnoringASCIICase(String(actionName), "press") || equalLettersIgnoringASCIICase(String(actionName), "jump");
 }
 
 bool AccessibilityUIElement::isIncrementActionSupported()
@@ -1046,6 +1637,11 @@ bool AccessibilityUIElement::isSelected() const
     return checkElementState(m_element.get(), ATK_STATE_SELECTED);
 }
 
+bool AccessibilityUIElement::isSelectedOptionActive() const
+{
+    return checkElementState(m_element.get(), ATK_STATE_ACTIVE);
+}
+
 bool AccessibilityUIElement::isExpanded() const
 {
     return checkElementState(m_element.get(), ATK_STATE_EXPANDED);
@@ -1056,6 +1652,11 @@ bool AccessibilityUIElement::isChecked() const
     return checkElementState(m_element.get(), ATK_STATE_CHECKED);
 }
 
+bool AccessibilityUIElement::isIndeterminate() const
+{
+    return checkElementState(m_element.get(), ATK_STATE_INDETERMINATE);
+}
+
 int AccessibilityUIElement::hierarchicalLevel() const
 {
     // FIXME: implement
@@ -1089,7 +1690,7 @@ int AccessibilityUIElement::lineForIndex(int index)
     if (index < 0 || index > atk_text_get_character_count(ATK_TEXT(m_element.get())))
         return -1;
 
-    GOwnPtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, index));
+    GUniquePtr<gchar> text(atk_text_get_text(ATK_TEXT(m_element.get()), 0, index));
     int lineNo = 0;
     for (gchar* offset = text.get(); *offset; ++offset) {
         if (*offset == '\n')
@@ -1101,8 +1702,16 @@ int AccessibilityUIElement::lineForIndex(int index)
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
 {
-    // FIXME: implement
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_TEXT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkText* text = ATK_TEXT(m_element.get());
+    gint startOffset = 0, endOffset = 0;
+    for (int i = 0; i <= line; ++i)
+        atk_text_get_string_at_offset(text, endOffset, ATK_TEXT_GRANULARITY_LINE, &startOffset, &endOffset);
+
+    GUniquePtr<gchar> range(g_strdup_printf("{%d, %d}", startOffset, endOffset - startOffset));
+    return JSStringCreateWithUTF8CString(range.get());
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
@@ -1113,20 +1722,50 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
 {
-    // FIXME: implement
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_TEXT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    AtkTextRectangle rect;
+    atk_text_get_range_extents(ATK_TEXT(m_element.get()), location, location + length, ATK_XY_WINDOW, &rect);
+
+    GUniquePtr<gchar> bounds(g_strdup_printf("{%d, %d, %d, %d}", rect.x, rect.y, rect.width, rect.height));
+    return JSStringCreateWithUTF8CString(bounds.get());
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
 {
-    // FIXME: implement
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_TEXT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    String string = atk_text_get_text(ATK_TEXT(m_element.get()), location, location + length);
+    return JSStringCreateWithUTF8CString(string.utf8().data());
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
 {
-    // FIXME: implement
-    return JSStringCreateWithCharacters(0, 0);
+    if (!ATK_IS_TEXT(m_element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    StringBuilder builder;
+
+    // The default text attributes apply to the entire element.
+    builder.append("\n\tDefault text attributes:\n\t\t");
+    builder.append(attributeSetToString(getAttributeSet(m_element.get(), TextAttributeType), "\n\t\t"));
+
+    // The attribute run provides attributes specific to the range of text at the specified offset.
+    AtkAttributeSet* attributeSet;
+    AtkText* text = ATK_TEXT(m_element.get());
+    gint start = 0, end = 0;
+    for (unsigned i = location; i < location + length; i = end) {
+        AtkAttributeSet* attributeSet = atk_text_get_run_attributes(text, i, &start, &end);
+        GUniquePtr<gchar> substring(replaceCharactersForResults(atk_text_get_text(text, start, end)));
+        builder.append(String::format("\n\tRange attributes for '%s':\n\t\t", substring.get()));
+        builder.append(attributeSetToString(attributeSet, "\n\t\t"));
+    }
+
+    atk_attribute_set_free(attributeSet);
+
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
 }
 
 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
@@ -1135,12 +1774,24 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location
     return false;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
+unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
 {
     // FIXME: implement
     return 0;
 }
 
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
+{
+    // FIXME: implement
+    return nullptr;
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
+{
+    // FIXME: implement
+    return nullptr;
+}
+
 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
 {
     if (!ATK_IS_TABLE(m_element.get()))
@@ -1220,27 +1871,27 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
     return indexRangeInTable(m_element.get(), false);
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
 {
     if (!ATK_IS_TABLE(m_element.get()))
-        return 0;
+        return nullptr;
 
     // Adopt the AtkObject representing the cell because
     // at_table_ref_at() transfers full ownership.
     GRefPtr<AtkObject> foundCell = adoptGRef(atk_table_ref_at(ATK_TABLE(m_element.get()), row, col));
-    return foundCell ? AccessibilityUIElement::create(foundCell.get()) : 0;
+    return foundCell ? AccessibilityUIElement::create(foundCell.get()).ptr() : nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
@@ -1251,16 +1902,19 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
     gint start, end;
     g_free(atk_text_get_selection(ATK_TEXT(m_element.get()), 0, &start, &end));
 
-    GOwnPtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start));
+    GUniquePtr<gchar> selection(g_strdup_printf("{%d, %d}", start, end - start));
     return JSStringCreateWithUTF8CString(selection.get());
 }
 
-void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
+bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
 {
     if (!ATK_IS_TEXT(m_element.get()))
-        return;
+        return false;
+
+    if (!length)
+        return atk_text_set_caret_offset(ATK_TEXT(m_element.get()), location);
 
-    atk_text_set_selection(ATK_TEXT(m_element.get()), 0, location, location + length);
+    return atk_text_set_selection(ATK_TEXT(m_element.get()), 0, location, location + length);
 }
 
 void AccessibilityUIElement::increment()
@@ -1292,6 +1946,30 @@ void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) c
     // FIXME: implement
 }
 
+void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
+{
+    if (!ATK_IS_SELECTION(m_element.get()))
+        return;
+
+    atk_selection_add_selection(ATK_SELECTION(m_element.get()), index);
+}
+
+void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
+{
+    if (!ATK_IS_SELECTION(m_element.get()))
+        return;
+
+    atk_selection_remove_selection(ATK_SELECTION(m_element.get()), index);
+}
+
+void AccessibilityUIElement::clearSelectedChildren() const
+{
+    if (!ATK_IS_SELECTION(m_element.get()))
+        return;
+
+    atk_selection_clear_selection(ATK_SELECTION(m_element.get()));
+}
+
 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
 {
     // FIXME: implement
@@ -1304,7 +1982,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
         return JSStringCreateWithCharacters(0, 0);
 
     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
-    if (role != ATK_ROLE_DOCUMENT_FRAME)
+    if (role != ATK_ROLE_DOCUMENT_WEB)
         return JSStringCreateWithCharacters(0, 0);
 
     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "Encoding"));
@@ -1316,7 +1994,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
         return JSStringCreateWithCharacters(0, 0);
 
     AtkRole role = atk_object_get_role(ATK_OBJECT(m_element.get()));
-    if (role != ATK_ROLE_DOCUMENT_FRAME)
+    if (role != ATK_ROLE_DOCUMENT_WEB)
         return JSStringCreateWithCharacters(0, 0);
 
     return JSStringCreateWithUTF8CString(atk_document_get_attribute_value(ATK_DOCUMENT(m_element.get()), "URI"));
@@ -1328,7 +2006,7 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
         return JSStringCreateWithCharacters(0, 0);
 
     AtkHyperlink* hyperlink = atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(m_element.get()));
-    GOwnPtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0));
+    GUniquePtr<char> hyperlinkURI(atk_hyperlink_get_uri(hyperlink, 0));
 
     // Build the result string, stripping the absolute URL paths if present.
     char* localURI = g_strstr_len(hyperlinkURI.get(), -1, "LayoutTests");
@@ -1356,7 +2034,7 @@ bool AccessibilityUIElement::removeNotificationListener()
 {
     // Programmers should not be trying to remove a listener that's already removed.
     ASSERT(m_notificationHandler);
-    m_notificationHandler = 0;
+    m_notificationHandler = nullptr;
 
     return true;
 }
@@ -1399,13 +2077,19 @@ bool AccessibilityUIElement::isIgnored() const
     return false;
 }
 
-bool AccessibilityUIElement::hasPopup() const
+bool AccessibilityUIElement::isSingleLine() const
 {
-    if (!ATK_IS_OBJECT(m_element.get()))
-        return false;
+    return checkElementState(m_element.get(), ATK_STATE_SINGLE_LINE);
+}
 
-    String hasPopupValue = getAttributeSetValueForId(ATK_OBJECT(m_element.get()), ObjectAttributeType, "haspopup");
-    return equalIgnoringCase(hasPopupValue, "true");
+bool AccessibilityUIElement::isMultiLine() const
+{
+    return checkElementState(m_element.get(), ATK_STATE_MULTI_LINE);
+}
+
+bool AccessibilityUIElement::hasPopup() const
+{
+    return checkElementState(m_element.get(), ATK_STATE_HAS_POPUP);
 }
 
 void AccessibilityUIElement::takeFocus()
@@ -1429,10 +2113,16 @@ void AccessibilityUIElement::removeSelection()
 }
 
 // Text markers
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
+}
+
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
+{
+    // FIXME: implement
+    return nullptr;
 }
 
 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
@@ -1441,16 +2131,16 @@ int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange*
     return 0;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
@@ -1459,46 +2149,46 @@ JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(Access
     return JSStringCreateWithCharacters(0, 0);
 }
 
-PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
+RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
+RefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
@@ -1519,57 +2209,127 @@ bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMark
     return false;
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
     
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
 {
     // FIXME: implement
     return nullptr;    
 }
 
-PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
+RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
 {
     // FIXME: implement
     return nullptr;
 }
 
+bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*)
+{
+    return false;
+}
+
 void AccessibilityUIElement::scrollToMakeVisible()
 {
     // FIXME: implement
 }
+    
+void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
+{
+    // FIXME: implement
+}
+    
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
+{
+    // FIXME: implement
+}
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
 {
     // FIXME: implement
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
 {
     notImplemented();
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
 {
     notImplemented();
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
 {
     notImplemented();
-    return 0;
+    return nullptr;
 }
 
 JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
 {
     notImplemented();
-    return 0;
+    return nullptr;
+}
+
+JSRetainPtr<JSStringRef> stringAtOffset(PlatformUIElement element, AtkTextBoundary boundary, int offset)
+{
+    if (!ATK_IS_TEXT(element.get()))
+        return JSStringCreateWithCharacters(0, 0);
+
+    gint startOffset, endOffset;
+    StringBuilder builder;
+
+#if ATK_CHECK_VERSION(2, 10, 0)
+    AtkTextGranularity granularity;
+    switch (boundary) {
+    case ATK_TEXT_BOUNDARY_CHAR:
+        granularity = ATK_TEXT_GRANULARITY_CHAR;
+        break;
+    case ATK_TEXT_BOUNDARY_WORD_START:
+        granularity = ATK_TEXT_GRANULARITY_WORD;
+        break;
+    case ATK_TEXT_BOUNDARY_LINE_START:
+        granularity = ATK_TEXT_GRANULARITY_LINE;
+        break;
+    case ATK_TEXT_BOUNDARY_SENTENCE_START:
+        granularity = ATK_TEXT_GRANULARITY_SENTENCE;
+        break;
+    default:
+        return JSStringCreateWithCharacters(0, 0);
+    }
+
+    builder.append(atk_text_get_string_at_offset(ATK_TEXT(element.get()), offset, granularity, &startOffset, &endOffset));
+#else
+    builder.append(atk_text_get_text_at_offset(ATK_TEXT(element.get()), offset, boundary, &startOffset, &endOffset));
+#endif
+    builder.append(String::format(", %i, %i", startOffset, endOffset));
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::characterAtOffset(int offset)
+{
+    return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_CHAR, offset);
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::wordAtOffset(int offset)
+{
+    return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_WORD_START, offset);
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::lineAtOffset(int offset)
+{
+    return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_LINE_START, offset);
+}
+
+JSRetainPtr<JSStringRef> AccessibilityUIElement::sentenceAtOffset(int offset)
+{
+    return stringAtOffset(m_element, ATK_TEXT_BOUNDARY_SENTENCE_START, offset);
 }
 
 } // namespace WTR