File webkit2gtk3-restore-atk.patch of Package webkit2gtk3.30069

diff -urpN webkitgtk-2.39.91.glib244/Source/cmake/OptionsGTK.cmake webkitgtk-2.39.91.atk/Source/cmake/OptionsGTK.cmake
--- webkitgtk-2.39.91.glib244/Source/cmake/OptionsGTK.cmake	2023-03-09 13:26:06.418428134 -0600
+++ webkitgtk-2.39.91.atk/Source/cmake/OptionsGTK.cmake	2023-03-09 13:26:47.258643737 -0600
@@ -27,6 +27,7 @@ find_package(SQLite3 REQUIRED)
 find_package(Threads REQUIRED)
 find_package(Unifdef REQUIRED)
 find_package(ZLIB REQUIRED)
+find_package(ATK 2.16.0 REQUIRED)
 find_package(WebP REQUIRED COMPONENTS demux)
 find_package(ATSPI 2.5.3)
 find_package(EGL)
@@ -287,7 +288,17 @@ if (NOT EXISTS "${TOOLS_DIR}/glib/apply-
     set(BUILD_REVISION "tarball")
 endif ()
 
-SET_AND_EXPOSE_TO_BUILD(USE_ATSPI ${ENABLE_ACCESSIBILITY})
+if (ENABLE_ACCESSIBILITY)
+    if (USE_ATSPI)
+        SET_AND_EXPOSE_TO_BUILD(USE_ATK FALSE)
+    else ()
+        SET_AND_EXPOSE_TO_BUILD(USE_ATK TRUE)
+    endif ()
+else ()
+    SET_AND_EXPOSE_TO_BUILD(USE_ATK FALSE)
+    SET_AND_EXPOSE_TO_BUILD(USE_ATSPI FALSE)
+endif ()
+
 SET_AND_EXPOSE_TO_BUILD(HAVE_GTK_UNIX_PRINTING ${GTK_UNIX_PRINT_FOUND})
 SET_AND_EXPOSE_TO_BUILD(HAVE_OS_DARK_MODE_SUPPORT 1)
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityList.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityList.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityList.cpp	2023-02-20 03:22:15.241729000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityList.cpp	2023-03-09 13:26:47.258643737 -0600
@@ -117,7 +117,7 @@ bool AccessibilityList::childHasPseudoVi
     
     // Platforms which expose rendered text content through the parent element will treat
     // those renderers as "ignored" objects.
-#if USE(ATSPI)
+#if USE(ATK) || USE(ATSPI)
     String text = axObj->textUnderElement();
     return !text.isEmpty() && !text.isAllSpecialCharacters<isHTMLSpace>();
 #else
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityNodeObject.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityNodeObject.cpp	2023-02-20 03:22:15.261729200 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp	2023-03-09 13:26:47.258643737 -0600
@@ -2520,8 +2520,8 @@ bool AccessibilityNodeObject::canSetValu
     if (isProgressIndicator() || isSlider() || isScrollbar())
         return true;
 
-#if USE(ATSPI)
-    // In ATSPI, input types which support aria-readonly are treated as having a
+#if USE(ATK) || USE(ATSPI)
+    // In ATK, input types which support aria-readonly are treated as having a
     // settable value if the user can modify the widget's value or its state.
     if (supportsReadOnly())
         return true;
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObject.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObject.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObject.cpp	2023-03-03 03:33:24.892969400 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObject.cpp	2023-03-09 13:26:47.262643759 -0600
@@ -3572,8 +3572,8 @@ TextIteratorBehaviors AccessibilityObjec
 {
     TextIteratorBehaviors behaviors { TextIteratorBehavior::IgnoresStyleVisibility };
 
-#if USE(ATSPI)
-    // We need to emit replaced elements for ATSPI, and present
+#if USE(ATK) || USE(ATSPI)
+    // We need to emit replaced elements for GTK, and present
     // them with the 'object replacement character' (0xFFFC).
     behaviors.add(TextIteratorBehavior::EmitsObjectReplacementCharacters);
 #endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObject.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObject.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObject.h	2023-02-20 03:22:15.265729200 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObject.h	2023-03-09 13:26:47.266643779 -0600
@@ -42,6 +42,10 @@
 #include <wtf/RetainPtr.h>
 #endif
 
+#if USE(ATK)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
 #if PLATFORM(COCOA)
 
 OBJC_CLASS NSArray;
@@ -869,7 +873,7 @@ inline void AccessibilityObject::updateB
 inline void AccessibilityObject::detachPlatformWrapper(AccessibilityDetachmentType) { }
 #endif
 
-#if !(ENABLE(ACCESSIBILITY) && USE(ATSPI))
+#if !(ENABLE(ACCESSIBILITY) && (USE(ATK) || USE(ATSPI)))
 inline bool AccessibilityObject::allowsTextRanges() const { return true; }
 inline unsigned AccessibilityObject::getLengthForTextRange() const { return text().length(); }
 #endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObjectInterface.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObjectInterface.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityObjectInterface.h	2023-02-20 03:22:15.265729200 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityObjectInterface.h	2023-03-09 13:26:47.266643779 -0600
@@ -48,6 +48,10 @@
 #include "AccessibilityObjectAtspi.h"
 #endif
 
+#if USE(ATK)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
 #if PLATFORM(COCOA)
 OBJC_CLASS WebAccessibilityObjectWrapper;
 typedef WebAccessibilityObjectWrapper AccessibilityObjectWrapper;
@@ -56,6 +60,9 @@ typedef const struct __AXTextMarker* AXT
 typedef const struct __AXTextMarkerRange* AXTextMarkerRangeRef;
 #elif USE(ATSPI)
 typedef WebCore::AccessibilityObjectAtspi AccessibilityObjectWrapper;
+#elif USE(ATK)
+typedef struct _WebKitAccessible WebKitAccessible;
+typedef struct _WebKitAccessible AccessibilityObjectWrapper;
 #else
 class AccessibilityObjectWrapper;
 #endif
@@ -1430,6 +1437,8 @@ private:
     COMPtr<AccessibilityObjectWrapper> m_wrapper;
 #elif USE(ATSPI)
     RefPtr<AccessibilityObjectAtspi> m_wrapper;
+#elif USE(ATK)
+    GRefPtr<WebKitAccessible> m_wrapper;
 #endif
 };
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityRenderObject.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2023-03-03 03:33:24.896969600 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2023-03-09 13:26:47.270643800 -0600
@@ -2075,6 +2075,8 @@ int AccessibilityRenderObject::indexForV
     TextIteratorBehaviors behaviors;
 #if USE(ATSPI)
     behaviors.add(TextIteratorBehavior::EmitsObjectReplacementCharacters);
+#elif USE(ATK)
+    behaviors.add(TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
 #endif
 
     return WebCore::indexForVisiblePosition(*node, position, behaviors);
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityTableColumn.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityTableColumn.cpp	2023-02-20 03:22:15.277729300 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityTableColumn.cpp	2023-03-09 13:26:47.270643800 -0600
@@ -172,7 +172,7 @@ bool AccessibilityTableColumn::computeAc
     if (!m_parent)
         return true;
     
-#if PLATFORM(IOS_FAMILY) || USE(ATSPI)
+#if PLATFORM(IOS_FAMILY) || USE(ATK) || USE(ATSPI)
     return true;
 #endif
     
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp	2023-02-20 03:22:15.277729300 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp	2023-03-09 13:26:47.270643800 -0600
@@ -54,7 +54,7 @@ bool AccessibilityTableHeaderContainer::
     if (!m_parent)
         return true;
     
-#if PLATFORM(IOS_FAMILY) || USE(ATSPI)
+#if PLATFORM(IOS_FAMILY) || USE(ATK) || USE(ATSPI)
     return true;
 #endif
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/AccessibilityObjectAtk.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/AccessibilityObjectAtk.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/AccessibilityObjectAtk.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/AccessibilityObjectAtk.cpp	2023-03-09 13:26:47.274643822 -0600
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2008 Apple Ltd.
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "AccessibilityObject.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AXObjectCache.h"
+#include "HTMLSpanElement.h"
+#include "RenderBlock.h"
+#include "RenderInline.h"
+#include "RenderIterator.h"
+#include "RenderTableCell.h"
+#include "RenderText.h"
+#include "TextControlInnerElements.h"
+#include "WebKitAccessible.h"
+#include <glib-object.h>
+
+namespace WebCore {
+
+void AccessibilityObject::detachPlatformWrapper(AccessibilityDetachmentType detachmentType)
+{
+    if (detachmentType != AccessibilityDetachmentType::CacheDestroyed) {
+        if (auto* cache = axObjectCache()) {
+            cache->detachWrapper(this, detachmentType);
+            return;
+        }
+    }
+
+    auto* wrapper = this->wrapper();
+    ASSERT(wrapper);
+    webkitAccessibleDetach(WEBKIT_ACCESSIBLE(wrapper));
+}
+
+bool AccessibilityObject::accessibilityIgnoreAttachment() const
+{
+    return false;
+}
+
+AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const
+{
+    AccessibilityObject* parent = parentObject();
+    if (!parent)
+        return AccessibilityObjectInclusion::DefaultBehavior;
+
+    // If the author has provided a role, platform-specific inclusion likely doesn't apply.
+    if (ariaRoleAttribute() != AccessibilityRole::Unknown)
+        return AccessibilityObjectInclusion::DefaultBehavior;
+
+    AccessibilityRole role = roleValue();
+    // We expose the slider as a whole but not its value indicator.
+    if (role == AccessibilityRole::SliderThumb)
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    // When a list item is made up entirely of children (e.g. paragraphs)
+    // the list item gets ignored. We need it.
+    if (isGroup() && parent->isList())
+        return AccessibilityObjectInclusion::IncludeObject;
+
+    // Entries and password fields have extraneous children which we want to ignore.
+    if (parent->isPasswordField() || parent->isTextControl())
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    // Include all tables, even layout tables. The AT can decide what to do with each.
+    if (role == AccessibilityRole::Cell || role == AccessibilityRole::Table || role == AccessibilityRole::ColumnHeader || role == AccessibilityRole::RowHeader)
+        return AccessibilityObjectInclusion::IncludeObject;
+
+    // The object containing the text should implement AtkText itself.
+    // However, WebCore also maps ARIA's "text" role to the StaticTextRole.
+    if (role == AccessibilityRole::StaticText)
+        return ariaRoleAttribute() != AccessibilityRole::Unknown ? AccessibilityObjectInclusion::DefaultBehavior : AccessibilityObjectInclusion::IgnoreObject;
+
+    // Include all list items, regardless they have or not inline children
+    if (role == AccessibilityRole::ListItem)
+        return AccessibilityObjectInclusion::IncludeObject;
+
+    // Bullets/numbers for list items shouldn't be exposed as AtkObjects.
+    if (role == AccessibilityRole::ListMarker)
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    // Never expose an unknown object, since AT's won't know what to
+    // do with them. This is what is done on the Mac as well.
+    if (role == AccessibilityRole::Unknown)
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    if (role == AccessibilityRole::Inline)
+        return AccessibilityObjectInclusion::IncludeObject;
+
+    // Lines past this point only make sense for AccessibilityRenderObjects.
+    RenderObject* renderObject = renderer();
+    if (!renderObject)
+        return AccessibilityObjectInclusion::DefaultBehavior;
+
+    // We always want to include paragraphs that have rendered content.
+    // WebCore Accessibility does so unless there is a RenderBlock child.
+    if (role == AccessibilityRole::Paragraph) {
+        auto child = childrenOfType<RenderBlock>(downcast<RenderElement>(*renderObject)).first();
+        return child ? AccessibilityObjectInclusion::IncludeObject : AccessibilityObjectInclusion::DefaultBehavior;
+    }
+
+    // We always want to include table cells (layout and CSS) that have rendered text content.
+    if (is<RenderTableCell>(renderObject)) {
+        for (const auto& child : childrenOfType<RenderObject>(downcast<RenderElement>(*renderObject))) {
+            if (is<RenderInline>(child) || is<RenderText>(child) || is<HTMLSpanElement>(child.node()))
+                return AccessibilityObjectInclusion::IncludeObject;
+        }
+        return AccessibilityObjectInclusion::DefaultBehavior;
+    }
+
+    if (renderObject->isAnonymousBlock()) {
+        // The text displayed by an ARIA menu item is exposed through the accessible name.
+        if (parent->isMenuItem())
+            return AccessibilityObjectInclusion::IgnoreObject;
+
+        // The text displayed in headings is typically exposed in the heading itself.
+        if (parent->isHeading())
+            return AccessibilityObjectInclusion::IgnoreObject;
+
+        // The text displayed in list items is typically exposed in the list item itself.
+        if (parent->isListItem())
+            return AccessibilityObjectInclusion::IgnoreObject;
+
+        // The text displayed in links is typically exposed in the link itself.
+        if (parent->isLink())
+            return AccessibilityObjectInclusion::IgnoreObject;
+
+        // FIXME: This next one needs some further consideration. But paragraphs are not
+        // typically huge (like divs). And ignoring anonymous block children of paragraphs
+        // will preserve existing behavior.
+        if (parent->roleValue() == AccessibilityRole::Paragraph)
+            return AccessibilityObjectInclusion::IgnoreObject;
+
+        return AccessibilityObjectInclusion::DefaultBehavior;
+    }
+
+    Node* node = renderObject->node();
+    if (!node)
+        return AccessibilityObjectInclusion::DefaultBehavior;
+
+    // We don't want <span> elements to show up in the accessibility hierarchy unless
+    // we have good reasons for that (e.g. focusable or visible because of containing
+    // a meaningful accessible name, maybe set through ARIA), so we can use
+    // atk_component_grab_focus() to set the focus to it.
+    if (is<HTMLSpanElement>(node) && !canSetFocusAttribute() && !hasAttributesRequiredForInclusion() && !supportsARIAAttributes())
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    // If we include TextControlInnerTextElement children, changes to those children
+    // will result in focus and text notifications that suggest the user is no longer
+    // in the control. This can be especially problematic for screen reader users with
+    // key echo enabled when typing in a password input.
+    if (is<TextControlInnerTextElement>(node))
+        return AccessibilityObjectInclusion::IgnoreObject;
+
+    return AccessibilityObjectInclusion::DefaultBehavior;
+}
+
+bool AccessibilityObject::allowsTextRanges() const
+{
+    // Check type for the AccessibilityObject.
+    if (isTextControl() || isWebArea() || isGroup() || isLink() || isHeading() || isListItem() || isTableCell())
+        return true;
+
+    // Check roles as the last fallback mechanism.
+    AccessibilityRole role = roleValue();
+    return role == AccessibilityRole::Paragraph || role == AccessibilityRole::Label || role == AccessibilityRole::Div || role == AccessibilityRole::Form || role == AccessibilityRole::Pre;
+}
+
+unsigned AccessibilityObject::getLengthForTextRange() const
+{
+    unsigned textLength = text().length();
+
+    if (textLength)
+        return textLength;
+
+    // Gtk ATs need this for all text objects; not just text controls.
+    Node* node = this->node();
+    RenderObject* renderer = node ? node->renderer() : nullptr;
+    if (is<RenderText>(renderer))
+        textLength = downcast<RenderText>(*renderer).text().length();
+
+    // Get the text length from the elements under the
+    // accessibility object if the value is still zero.
+    if (!textLength && allowsTextRanges())
+        textLength = textUnderElement(AccessibilityTextUnderElementMode(AccessibilityTextUnderElementMode::TextUnderElementModeIncludeAllChildren)).length();
+
+    return textLength;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/AXObjectCacheAtk.cpp	2023-03-09 13:26:47.274643822 -0600
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "AXObjectCache.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "AccessibilityRenderObject.h"
+#include "Document.h"
+#include "Element.h"
+#include "HTMLSelectElement.h"
+#include "Range.h"
+#include "TextIterator.h"
+#include "WebKitAccessible.h"
+#include <wtf/NeverDestroyed.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+static AtkObject* wrapperParent(WebKitAccessible* wrapper)
+{
+    // Look for the right object to emit the signal from, but using the implementation
+    // of atk_object_get_parent from AtkObject class (which uses a cached pointer if set)
+    // since the accessibility hierarchy in WebCore will no longer be navigable.
+    gpointer webkitAccessibleClass = g_type_class_peek_parent(WEBKIT_ACCESSIBLE_GET_CLASS(wrapper));
+    gpointer atkObjectClass = g_type_class_peek_parent(webkitAccessibleClass);
+    AtkObject* atkParent = ATK_OBJECT_CLASS(atkObjectClass)->get_parent(ATK_OBJECT(wrapper));
+    // We don't want to emit any signal from an object outside WebKit's world.
+    return WEBKIT_IS_ACCESSIBLE(atkParent) ? atkParent : nullptr;
+}
+
+void AXObjectCache::detachWrapper(AXCoreObject* obj, AccessibilityDetachmentType detachmentType)
+{
+    auto* wrapper = obj->wrapper();
+    ASSERT(wrapper);
+
+    // If an object is being detached NOT because of the AXObjectCache being destroyed,
+    // then it's being removed from the accessibility tree and we should emit a signal.
+    if (detachmentType != AccessibilityDetachmentType::CacheDestroyed && obj->document() && wrapperParent(wrapper))
+        m_deferredDetachedWrapperList.add(wrapper);
+
+    webkitAccessibleDetach(WEBKIT_ACCESSIBLE(wrapper));
+}
+
+void AXObjectCache::attachWrapper(AccessibilityObject* accessibilityObject)
+{
+    GRefPtr<WebKitAccessible> wrapper = adoptGRef(webkitAccessibleNew(accessibilityObject));
+    accessibilityObject->setWrapper(wrapper.get());
+
+    // If an object is being attached and we are not in the middle of a layout update, then
+    // we should report ATs by emitting the children-changed::add signal from the parent.
+    Document* document = accessibilityObject->document();
+    if (!document || document->childNeedsStyleRecalc())
+        return;
+
+    // Don't emit the signal when the actual object being added is not going to be exposed.
+    if (accessibilityObject->accessibilityIsIgnoredByDefault())
+        return;
+
+    // Don't emit the signal if the object being added is not -- or not yet -- rendered,
+    // which can occur in nested iframes. In these instances we don't want to ignore the
+    // child. But if an assistive technology is listening, AT-SPI2 will attempt to create
+    // and cache the state set for the child upon emission of the signal. If the object
+    // has not yet been rendered, this will result in a crash.
+    if (!accessibilityObject->renderer())
+        return;
+
+    m_deferredAttachedWrapperObjectList.add(accessibilityObject);
+}
+
+void AXObjectCache::platformPerformDeferredCacheUpdate()
+{
+    for (auto& coreObject : m_deferredAttachedWrapperObjectList) {
+        auto* wrapper = coreObject->wrapper();
+        if (!wrapper)
+            continue;
+
+        // Don't emit the signal for objects whose parents won't be exposed directly.
+        auto* coreParent = coreObject->parentObjectUnignored();
+        if (!coreParent || coreParent->accessibilityIsIgnoredByDefault())
+            continue;
+
+        // Look for the right object to emit the signal from.
+        auto* atkParent = coreParent->wrapper();
+        if (!atkParent)
+            continue;
+
+        size_t index = coreParent->children(false).find(coreObject);
+        g_signal_emit_by_name(atkParent, "children-changed::add", index != notFound ? index : -1, wrapper);
+    }
+    m_deferredAttachedWrapperObjectList.clear();
+
+    for (auto& wrapper : m_deferredDetachedWrapperList) {
+        if (auto* atkParent = wrapperParent(wrapper.get())) {
+            // The accessibility hierarchy is already invalid, so the parent-children relationships
+            // in the AccessibilityObject tree are not there anymore, so we can't know the offset.
+            g_signal_emit_by_name(atkParent, "children-changed::remove", -1, wrapper.get());
+        }
+    }
+    m_deferredDetachedWrapperList.clear();
+}
+
+static AXCoreObject* getListObject(AXCoreObject* object)
+{
+    // Only list boxes and menu lists supported so far.
+    if (!object->isListBox() && !object->isMenuList())
+        return 0;
+
+    // For list boxes the list object is just itself.
+    if (object->isListBox())
+        return object;
+
+    // For menu lists we need to return the first accessible child,
+    // with role MenuListPopupRole, since that's the one holding the list
+    // of items with role MenuListOptionRole.
+    const AccessibilityObject::AccessibilityChildrenVector& children = object->children();
+    if (!children.size())
+        return 0;
+
+    AXCoreObject* listObject = children.at(0).get();
+    if (!listObject->isMenuListPopup())
+        return 0;
+
+    return listObject;
+}
+
+static void notifyChildrenSelectionChange(AXCoreObject* object)
+{
+    // This static variables are needed to keep track of the old
+    // focused object and its associated list object, as per previous
+    // calls to this function, in order to properly decide whether to
+    // emit some signals or not.
+    static NeverDestroyed<RefPtr<AXCoreObject>> oldListObject;
+    static NeverDestroyed<RefPtr<AXCoreObject>> oldFocusedObject;
+
+    // Only list boxes and menu lists supported so far.
+    if (!object || !(object->isListBox() || object->isMenuList()))
+        return;
+
+    // Only support HTML select elements so far (ARIA selectors not supported).
+    Node* node = object->node();
+    if (!is<HTMLSelectElement>(node))
+        return;
+
+    // Emit signal from the listbox's point of view first.
+    g_signal_emit_by_name(object->wrapper(), "selection-changed");
+
+    // Find the item where the selection change was triggered from.
+    HTMLSelectElement& select = downcast<HTMLSelectElement>(*node);
+    int changedItemIndex = select.activeSelectionStartListIndex();
+
+    AXCoreObject* listObject = getListObject(object);
+    if (!listObject) {
+        oldListObject.get() = nullptr;
+        return;
+    }
+
+    const AccessibilityObject::AccessibilityChildrenVector& items = listObject->children();
+    if (changedItemIndex < 0 || changedItemIndex >= static_cast<int>(items.size()))
+        return;
+    AXCoreObject* item = items.at(changedItemIndex).get();
+
+    // Ensure the current list object is the same than the old one so
+    // further comparisons make sense. Otherwise, just reset
+    // oldFocusedObject so it won't be taken into account.
+    if (oldListObject.get() != listObject)
+        oldFocusedObject.get() = nullptr;
+
+    WebKitAccessible* axItem = item ? item->wrapper() : nullptr;
+    WebKitAccessible* axOldFocusedObject = oldFocusedObject.get() ? oldFocusedObject.get()->wrapper() : nullptr;
+
+    // Old focused object just lost focus, so emit the events.
+    if (axOldFocusedObject && axItem != axOldFocusedObject) {
+        g_signal_emit_by_name(axOldFocusedObject, "focus-event", false);
+        atk_object_notify_state_change(ATK_OBJECT(axOldFocusedObject), ATK_STATE_FOCUSED, false);
+    }
+
+    // Emit needed events for the currently (un)selected item.
+    if (axItem) {
+        bool isSelected = item->isSelected();
+        atk_object_notify_state_change(ATK_OBJECT(axItem), ATK_STATE_SELECTED, isSelected);
+        // When the selection changes in a collapsed widget such as a combo box
+        // whose child menu is not showing, that collapsed widget retains focus.
+        AccessibilityObject* accessibilityObject = downcast<AccessibilityObject>(object);
+        if (!accessibilityObject->isCollapsed()) {
+            g_signal_emit_by_name(axItem, "focus-event", isSelected);
+            atk_object_notify_state_change(ATK_OBJECT(axItem), ATK_STATE_FOCUSED, isSelected);
+        }
+    }
+
+    // Update pointers to the previously involved objects.
+    oldListObject.get() = listObject;
+    oldFocusedObject.get() = item;
+}
+
+void AXObjectCache::postPlatformNotification(AXCoreObject* coreObject, AXNotification notification)
+{
+    auto* axObject = ATK_OBJECT(coreObject->wrapper());
+    if (!axObject)
+        return;
+
+    switch (notification) {
+    case AXCheckedStateChanged:
+        if (!coreObject->isCheckboxOrRadio() && !coreObject->isSwitch())
+            return;
+        atk_object_notify_state_change(axObject, ATK_STATE_CHECKED, coreObject->isChecked());
+        break;
+
+    case AXSelectedChildrenChanged:
+    case AXMenuListValueChanged:
+        // Accessible focus claims should not be made if the associated widget is not focused.
+        if (notification == AXMenuListValueChanged && coreObject->isMenuList() && coreObject->isFocused()) {
+            g_signal_emit_by_name(axObject, "focus-event", true);
+            atk_object_notify_state_change(axObject, ATK_STATE_FOCUSED, true);
+        }
+        notifyChildrenSelectionChange(coreObject);
+        break;
+
+    case AXValueChanged:
+        if (ATK_IS_VALUE(axObject)) {
+            AtkPropertyValues propertyValues;
+            propertyValues.property_name = "accessible-value";
+
+            memset(&propertyValues.new_value,  0, sizeof(GValue));
+
+            double value;
+            atk_value_get_value_and_text(ATK_VALUE(axObject), &value, nullptr);
+            g_value_set_double(g_value_init(&propertyValues.new_value, G_TYPE_DOUBLE), value);
+
+            g_signal_emit_by_name(axObject, "property-change::accessible-value", &propertyValues, NULL);
+        }
+        break;
+
+    case AXInvalidStatusChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_INVALID_ENTRY, coreObject->invalidStatus() != "false"_s);
+        break;
+
+    case AXElementBusyChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_BUSY, coreObject->isBusy());
+        break;
+
+    case AXCurrentStateChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_ACTIVE, coreObject->currentState() != AccessibilityCurrentState::False);
+        break;
+
+    case AXRowExpanded:
+        atk_object_notify_state_change(axObject, ATK_STATE_EXPANDED, true);
+        break;
+
+    case AXRowCollapsed:
+        atk_object_notify_state_change(axObject, ATK_STATE_EXPANDED, false);
+        break;
+
+    case AXExpandedChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_EXPANDED, coreObject->isExpanded());
+        break;
+
+    case AXDisabledStateChanged: {
+        bool enabledState = coreObject->isEnabled();
+        atk_object_notify_state_change(axObject, ATK_STATE_ENABLED, enabledState);
+        atk_object_notify_state_change(axObject, ATK_STATE_SENSITIVE, enabledState);
+        break;
+    }
+
+    case AXPressedStateChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_PRESSED, coreObject->isPressed());
+        break;
+
+    case AXReadOnlyStatusChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_READ_ONLY, !coreObject->canSetValueAttribute());
+        break;
+
+    case AXRequiredStatusChanged:
+        atk_object_notify_state_change(axObject, ATK_STATE_REQUIRED, coreObject->isRequired());
+        break;
+
+    case AXActiveDescendantChanged:
+        if (AXCoreObject* descendant = coreObject->activeDescendant())
+            platformHandleFocusedUIElementChanged(nullptr, descendant->node());
+        break;
+
+    default:
+        break;
+    }
+}
+
+void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, const String& text)
+{
+    if (!object || text.isEmpty())
+        return;
+
+    AXCoreObject* parentObject = object->isNonNativeTextControl() ? object : object->parentObjectUnignored();
+    if (!parentObject)
+        return;
+
+    auto* wrapper = parentObject->wrapper();
+    if (!wrapper || !ATK_IS_TEXT(wrapper))
+        return;
+
+    Node* node = object->node();
+    if (!node)
+        return;
+
+    // Ensure document's layout is up-to-date before using TextIterator.
+    Document& document = node->document();
+    document.updateLayout();
+
+    // Select the right signal to be emitted
+    CString detail;
+    switch (textChange) {
+    case AXTextInserted:
+        detail = "text-insert";
+        break;
+    case AXTextDeleted:
+        detail = "text-remove";
+        break;
+    case AXTextAttributesChanged:
+        detail = "text-attributes-changed";
+        break;
+    }
+
+    String textToEmit = text;
+    unsigned offsetToEmit = offset;
+
+    // If the object we're emitting the signal from represents a
+    // password field, we will emit the masked text.
+    if (parentObject->isPasswordField()) {
+        AccessibilityObject* accessibilityObject = downcast<AccessibilityObject>(parentObject);
+        String maskedText = accessibilityObject->passwordFieldValue();
+        textToEmit = maskedText.substring(offset, text.length());
+    } else {
+        // Consider previous text objects that might be present for
+        // the current accessibility object to ensure we emit the
+        // right offset (e.g. multiline text areas).
+        offsetToEmit = offset + characterCount(SimpleRange { { *node->parentNode(), 0 }, { *node, 0 } });
+    }
+
+    g_signal_emit_by_name(wrapper, detail.data(), offsetToEmit, textToEmit.length(), textToEmit.utf8().data());
+}
+
+void AXObjectCache::frameLoadingEventPlatformNotification(AccessibilityObject* object, AXLoadingEvent loadingEvent)
+{
+    if (!object)
+        return;
+
+    auto* axObject = ATK_OBJECT(object->wrapper());
+    if (!axObject || !ATK_IS_DOCUMENT(axObject))
+        return;
+
+    switch (loadingEvent) {
+    case AXObjectCache::AXLoadingStarted:
+        atk_object_notify_state_change(axObject, ATK_STATE_BUSY, true);
+        break;
+    case AXObjectCache::AXLoadingReloaded:
+        atk_object_notify_state_change(axObject, ATK_STATE_BUSY, true);
+        g_signal_emit_by_name(axObject, "reload");
+        break;
+    case AXObjectCache::AXLoadingFailed:
+        g_signal_emit_by_name(axObject, "load-stopped");
+        atk_object_notify_state_change(axObject, ATK_STATE_BUSY, false);
+        break;
+    case AXObjectCache::AXLoadingFinished:
+        g_signal_emit_by_name(axObject, "load-complete");
+        atk_object_notify_state_change(axObject, ATK_STATE_BUSY, false);
+        break;
+    }
+}
+
+void AXObjectCache::platformHandleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode)
+{
+    RefPtr<AccessibilityObject> oldObject = getOrCreate(oldFocusedNode);
+    if (oldObject) {
+        auto* axObject = oldObject->wrapper();
+        g_signal_emit_by_name(axObject, "focus-event", false);
+        atk_object_notify_state_change(ATK_OBJECT(axObject), ATK_STATE_FOCUSED, false);
+    }
+    RefPtr<AccessibilityObject> newObject = getOrCreate(newFocusedNode);
+    if (newObject) {
+        auto* axObject = newObject->wrapper();
+        g_signal_emit_by_name(axObject, "focus-event", true);
+        atk_object_notify_state_change(ATK_OBJECT(axObject), ATK_STATE_FOCUSED, true);
+    }
+}
+
+void AXObjectCache::handleScrolledToAnchor(const Node*)
+{
+}
+
+} // namespace WebCore
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessible.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessible.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessible.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessible.cpp	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,1386 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012, 2019 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessible.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AXObjectCache.h"
+#include "AccessibilityList.h"
+#include "AccessibilityListBoxOption.h"
+#include "AccessibilityTable.h"
+#include "AccessibilityTableCell.h"
+#include "AccessibilityTableRow.h"
+#include "Document.h"
+#include "Editing.h"
+#include "ElementInlines.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HTMLNames.h"
+#include "HTMLTableElement.h"
+#include "HostWindow.h"
+#include "RenderAncestorIterator.h"
+#include "RenderBlock.h"
+#include "RenderObject.h"
+#include "SVGElement.h"
+#include "Settings.h"
+#include "TextIterator.h"
+#include "VisibleUnits.h"
+#include "WebKitAccessibleHyperlink.h"
+#include "WebKitAccessibleInterfaceAction.h"
+#include "WebKitAccessibleInterfaceComponent.h"
+#include "WebKitAccessibleInterfaceDocument.h"
+#include "WebKitAccessibleInterfaceEditableText.h"
+#include "WebKitAccessibleInterfaceHyperlinkImpl.h"
+#include "WebKitAccessibleInterfaceHypertext.h"
+#include "WebKitAccessibleInterfaceImage.h"
+#include "WebKitAccessibleInterfaceSelection.h"
+#include "WebKitAccessibleInterfaceTable.h"
+#include "WebKitAccessibleInterfaceTableCell.h"
+#include "WebKitAccessibleInterfaceText.h"
+#include "WebKitAccessibleInterfaceValue.h"
+#include "WebKitAccessibleUtil.h"
+#include <glib/gprintf.h>
+#include <wtf/glib/WTFGType.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+struct _WebKitAccessiblePrivate {
+    AccessibilityObject* object;
+
+    // Cached data for AtkObject.
+    CString accessibleName;
+    CString accessibleDescription;
+
+    // Cached data for AtkAction.
+    CString actionName;
+    CString actionKeyBinding;
+
+    // Cached data for AtkDocument.
+    CString documentLocale;
+    CString documentType;
+    CString documentEncoding;
+    CString documentURI;
+
+    // Cached data for AtkImage.
+    CString imageDescription;
+};
+
+WEBKIT_DEFINE_TYPE(WebKitAccessible, webkit_accessible, ATK_TYPE_OBJECT)
+
+static const gchar* webkitAccessibleGetName(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    if (!accessible->priv->object)
+        return "";
+
+    Vector<AccessibilityText> textOrder;
+    accessible->priv->object->accessibilityText(textOrder);
+
+    for (const auto& text : textOrder) {
+        // FIXME: This check is here because AccessibilityNodeObject::titleElementText()
+        // appends an empty String for the LabelByElementText source when there is a
+        // titleUIElement(). Removing this check makes some fieldsets lose their name.
+        if (text.text.isEmpty())
+            continue;
+
+        // WebCore Accessibility should provide us with the text alternative computation
+        // in the order defined by that spec. So take the first thing that our platform
+        // does not expose via the AtkObject description.
+        if (text.textSource != AccessibilityTextSource::Help && text.textSource != AccessibilityTextSource::Summary)
+            return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedAccessibleName, text.text.utf8());
+    }
+
+    return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedAccessibleName, "");
+}
+
+static const gchar* webkitAccessibleGetDescription(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    if (!accessible->priv->object)
+        return "";
+
+    Vector<AccessibilityText> textOrder;
+    accessible->priv->object->accessibilityText(textOrder);
+
+    bool nameTextAvailable = false;
+    for (const auto& text : textOrder) {
+        // WebCore Accessibility should provide us with the text alternative computation
+        // in the order defined by that spec. So take the first thing that our platform
+        // does not expose via the AtkObject name.
+        if (text.textSource == AccessibilityTextSource::Help || text.textSource == AccessibilityTextSource::Summary)
+            return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedAccessibleDescription, text.text.utf8());
+
+        // If there is no other text alternative, the title tag contents will have been
+        // used for the AtkObject name. We don't want to duplicate it here.
+        if (text.textSource == AccessibilityTextSource::TitleTag && nameTextAvailable)
+            return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedAccessibleDescription, text.text.utf8());
+
+        nameTextAvailable = true;
+    }
+
+    return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedAccessibleDescription, "");
+}
+
+static void removeAtkRelationByType(AtkRelationSet* relationSet, AtkRelationType relationType)
+{
+    int count = atk_relation_set_get_n_relations(relationSet);
+    for (int i = 0; i < count; i++) {
+        AtkRelation* relation = atk_relation_set_get_relation(relationSet, i);
+        if (atk_relation_get_relation_type(relation) == relationType) {
+            atk_relation_set_remove(relationSet, relation);
+            break;
+        }
+    }
+}
+
+static void setAtkRelationSetFromCoreObject(AccessibilityObject* coreObject, AtkRelationSet* relationSet)
+{
+    // Elements with aria-labelledby should have the labelled-by relation as per the ARIA AAM spec.
+    // Controls with a label element and fieldsets with a legend element should also use this relation
+    // as per the HTML AAM spec. The reciprocal label-for relation should also be used.
+    removeAtkRelationByType(relationSet, ATK_RELATION_LABELLED_BY);
+    removeAtkRelationByType(relationSet, ATK_RELATION_LABEL_FOR);
+    if (coreObject->isControl()) {
+        if (AccessibilityObject* label = coreObject->correspondingLabelForControlElement())
+            atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, ATK_OBJECT(label->wrapper()));
+    } else if (coreObject->isFieldset()) {
+        if (AccessibilityObject* label = coreObject->titleUIElement())
+            atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, ATK_OBJECT(label->wrapper()));
+    } else if (coreObject->roleValue() == AccessibilityRole::Legend) {
+        if (RenderBlock* renderFieldset = ancestorsOfType<RenderBlock>(*coreObject->renderer()).first()) {
+            if (renderFieldset->isFieldset()) {
+                AccessibilityObject* fieldset = coreObject->axObjectCache()->getOrCreate(renderFieldset);
+                atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, ATK_OBJECT(fieldset->wrapper()));
+            }
+        }
+    } else if (AccessibilityObject* control = coreObject->correspondingControlForLabelElement())
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, ATK_OBJECT(control->wrapper()));
+    else {
+        AccessibilityObject::AccessibilityChildrenVector ariaLabelledByElements;
+        ariaLabelledByElements = coreObject->labelledByObjects();
+        for (const auto& accessibilityObject : ariaLabelledByElements)
+            atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABELLED_BY, ATK_OBJECT(accessibilityObject->wrapper()));
+    }
+
+    // Elements referenced by aria-labelledby should have the label-for relation as per the ARIA AAM spec.
+    AccessibilityObject::AccessibilityChildrenVector labels;
+    labels = coreObject->labelForObjects();
+    for (const auto& accessibilityObject : labels)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_LABEL_FOR, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements with aria-flowto should have the flows-to relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_TO);
+    AccessibilityObject::AccessibilityChildrenVector ariaFlowToElements;
+    ariaFlowToElements = coreObject->flowToObjects();
+    for (const auto& accessibilityObject : ariaFlowToElements)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_TO, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-flowto should have the flows-from relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_FLOWS_FROM);
+    AccessibilityObject::AccessibilityChildrenVector flowFrom;
+    flowFrom = coreObject->flowFromObjects();
+    for (const auto& accessibilityObject : flowFrom)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_FLOWS_FROM, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements with aria-describedby should have the described-by relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIBED_BY);
+    AccessibilityObject::AccessibilityChildrenVector ariaDescribedByElements;
+    ariaDescribedByElements = coreObject->describedByObjects();
+    for (const auto& accessibilityObject : ariaDescribedByElements)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIBED_BY, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-describedby should have the description-for relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_DESCRIPTION_FOR);
+    AccessibilityObject::AccessibilityChildrenVector describers;
+    describers = coreObject->descriptionForObjects();
+    for (const auto& accessibilityObject : describers)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DESCRIPTION_FOR, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements with aria-controls should have the controller-for relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLER_FOR);
+    AccessibilityObject::AccessibilityChildrenVector ariaControls;
+    ariaControls = coreObject->controlledObjects();
+    for (const auto& accessibilityObject : ariaControls)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLER_FOR, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-controls should have the controlled-by relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_CONTROLLED_BY);
+    AccessibilityObject::AccessibilityChildrenVector controllers;
+    controllers = coreObject->controllers();
+    for (const auto& accessibilityObject : controllers)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_CONTROLLED_BY, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements with aria-owns should have the node-parent-of relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_NODE_PARENT_OF);
+    AccessibilityObject::AccessibilityChildrenVector ariaOwns;
+    ariaOwns = coreObject->ownedObjects();
+    for (const auto& accessibilityObject : ariaOwns)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_NODE_PARENT_OF, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-owns should have the node-child-of relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_NODE_CHILD_OF);
+    AccessibilityObject::AccessibilityChildrenVector owners;
+    owners = coreObject->owners();
+    for (const auto& accessibilityObject : owners)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_NODE_CHILD_OF, ATK_OBJECT(accessibilityObject->wrapper()));
+
+#if ATK_CHECK_VERSION(2, 25, 2)
+    // Elements with aria-details should have the details relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_DETAILS);
+    AccessibilityObject::AccessibilityChildrenVector ariaDetails;
+    ariaDetails = coreObject->detailsForObjects();
+    for (const auto& accessibilityObject : ariaDetails)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DETAILS, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-details should have the details-for relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_DETAILS_FOR);
+    AccessibilityObject::AccessibilityChildrenVector details;
+    details = coreObject->detailsForObjects();
+    for (const auto& accessibilityObject : details)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_DETAILS_FOR, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements with aria-errormessage should have the error-message relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_ERROR_MESSAGE);
+    AccessibilityObject::AccessibilityChildrenVector ariaErrorMessage;
+    ariaErrorMessage = coreObject->errorMessageObjects();
+    for (const auto& accessibilityObject : ariaErrorMessage)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_ERROR_MESSAGE, ATK_OBJECT(accessibilityObject->wrapper()));
+
+    // Elements referenced by aria-errormessage should have the error-for relation as per the ARIA AAM spec.
+    removeAtkRelationByType(relationSet, ATK_RELATION_ERROR_FOR);
+    AccessibilityObject::AccessibilityChildrenVector errors;
+    errors = coreObject->errorMessageForObjects();
+    for (const auto& accessibilityObject : errors)
+        atk_relation_set_add_relation_by_type(relationSet, ATK_RELATION_ERROR_FOR, ATK_OBJECT(accessibilityObject->wrapper()));
+#endif
+}
+
+static bool isRootObject(AccessibilityObject* coreObject)
+{
+    // The root accessible object in WebCore is always an object with
+    // the ScrolledArea role with one child with the WebArea role.
+    if (!coreObject || !coreObject->isScrollView())
+        return false;
+
+    AccessibilityObject* firstChild = coreObject->firstChild();
+    return firstChild && firstChild->isWebArea();
+}
+
+static AtkObject* webkitAccessibleGetParent(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    // Check first if the parent has been already set.
+    AtkObject* accessibleParent = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->get_parent(object);
+    if (accessibleParent)
+        return accessibleParent;
+
+    // Parent not set yet, so try to find it in the hierarchy.
+    auto* coreObject = accessible->priv->object;
+    if (!coreObject)
+        return nullptr;
+    auto* coreParent = coreObject->parentObjectUnignored();
+    if (!coreParent && isRootObject(coreObject)) {
+        // The top level object claims to not have a parent. This makes it
+        // impossible for assistive technologies to ascend the accessible
+        // hierarchy all the way to the application. (Bug 30489)
+        if (!coreObject->document())
+            return nullptr;
+    }
+
+    return coreParent ? ATK_OBJECT(coreParent->wrapper()) : nullptr;
+}
+
+static gint webkitAccessibleGetNChildren(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, 0);
+
+    if (!accessible->priv->object)
+        return 0;
+    return accessible->priv->object->children().size();
+}
+
+static AtkObject* webkitAccessibleRefChild(AtkObject* object, gint index)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    if (!accessible->priv->object || index < 0)
+        return nullptr;
+
+    const auto& children = accessible->priv->object->children();
+    if (static_cast<size_t>(index) >= children.size())
+        return nullptr;
+
+    auto& coreChild = children[index];
+    if (!coreChild)
+        return nullptr;
+
+    auto* child = coreChild->wrapper();
+    if (!child)
+        return nullptr;
+
+    atk_object_set_parent(ATK_OBJECT(child), object);
+    return ATK_OBJECT(g_object_ref(child));
+}
+
+static gint webkitAccessibleGetIndexInParent(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, -1);
+
+    auto* coreObject = accessible->priv->object;
+    if (!coreObject)
+        return -1;
+    auto* parent = coreObject->parentObjectUnignored();
+    if (!parent && isRootObject(coreObject)) {
+        if (!coreObject->document())
+            return -1;
+
+        auto* atkParent = parent ? ATK_OBJECT(parent->wrapper()) : nullptr;
+        if (!atkParent)
+            return -1;
+
+        unsigned count = atk_object_get_n_accessible_children(atkParent);
+        for (unsigned i = 0; i < count; ++i) {
+            GRefPtr<AtkObject> child = adoptGRef(atk_object_ref_accessible_child(atkParent, i));
+            if (child.get() == object)
+                return i;
+        }
+    }
+
+    if (!parent)
+        return -1;
+
+    size_t index = parent->children().find(coreObject);
+    return (index == notFound) ? -1 : index;
+}
+
+static AtkAttributeSet* webkitAccessibleGetAttributes(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    AtkAttributeSet* attributeSet = nullptr;
+#if PLATFORM(GTK)
+    attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WebKitGtk");
+#elif PLATFORM(WPE)
+    attributeSet = addToAtkAttributeSet(attributeSet, "toolkit", "WPEWebKit");
+#endif
+
+    auto* coreObject = accessible->priv->object;
+    if (!coreObject)
+        return attributeSet;
+
+    // Hack needed for WebKit2 tests because obtaining an element by its ID
+    // cannot be done from the UIProcess. Assistive technologies have no need
+    // for this information.
+    Element* element = coreObject->element() ? coreObject->element() : coreObject->actionElement();
+    if (element) {
+        String tagName = element->tagName();
+        if (!tagName.isEmpty())
+            attributeSet = addToAtkAttributeSet(attributeSet, "tag", tagName.convertToASCIILowercase().utf8().data());
+        String id = element->getIdAttribute().string();
+        if (!id.isEmpty())
+            attributeSet = addToAtkAttributeSet(attributeSet, "html-id", id.utf8().data());
+    }
+
+    int level = coreObject->isHeading() ? coreObject->headingLevel() : coreObject->hierarchicalLevel();
+    if (level) {
+        String value = String::number(level);
+        attributeSet = addToAtkAttributeSet(attributeSet, "level", value.utf8().data());
+    }
+
+    if (coreObject->roleValue() == AccessibilityRole::MathElement) {
+        if (coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PreSuperscript) || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PreSubscript))
+            attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "pre");
+        else if (coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PostSuperscript) || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PostSubscript))
+            attributeSet = addToAtkAttributeSet(attributeSet, "multiscript-type", "post");
+    }
+
+    if (is<AccessibilityTable>(*coreObject) && downcast<AccessibilityTable>(*coreObject).isExposable()) {
+        auto& table = downcast<AccessibilityTable>(*coreObject);
+        int rowCount = table.axRowCount();
+        if (rowCount)
+            attributeSet = addToAtkAttributeSet(attributeSet, "rowcount", String::number(rowCount).utf8().data());
+
+        int columnCount = table.axColumnCount();
+        if (columnCount)
+            attributeSet = addToAtkAttributeSet(attributeSet, "colcount", String::number(columnCount).utf8().data());
+    } else if (is<AccessibilityTableRow>(*coreObject)) {
+        auto& row = downcast<AccessibilityTableRow>(*coreObject);
+        int rowIndex = row.axRowIndex();
+        if (rowIndex != -1)
+            attributeSet = addToAtkAttributeSet(attributeSet, "rowindex", String::number(rowIndex).utf8().data());
+    } else if (is<AccessibilityTableCell>(*coreObject)) {
+        auto& cell = downcast<AccessibilityTableCell>(*coreObject);
+        int rowIndex = cell.axRowIndex();
+        if (rowIndex != -1)
+            attributeSet = addToAtkAttributeSet(attributeSet, "rowindex", String::number(rowIndex).utf8().data());
+
+        int columnIndex = cell.axColumnIndex();
+        if (columnIndex != -1)
+            attributeSet = addToAtkAttributeSet(attributeSet, "colindex", String::number(columnIndex).utf8().data());
+
+        int rowSpan = cell.axRowSpan();
+        if (rowSpan != -1)
+            attributeSet = addToAtkAttributeSet(attributeSet, "rowspan", String::number(rowSpan).utf8().data());
+
+        int columnSpan = cell.axColumnSpan();
+        if (columnSpan != -1)
+            attributeSet = addToAtkAttributeSet(attributeSet, "colspan", String::number(columnSpan).utf8().data());
+    }
+
+    String placeholder = coreObject->placeholderValue();
+    if (!placeholder.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "placeholder-text", placeholder.utf8().data());
+
+    if (coreObject->supportsAutoComplete())
+        attributeSet = addToAtkAttributeSet(attributeSet, "autocomplete", coreObject->autoCompleteValue().utf8().data());
+
+    if (coreObject->supportsHasPopup())
+        attributeSet = addToAtkAttributeSet(attributeSet, "haspopup", coreObject->popupValue().utf8().data());
+
+    if (coreObject->supportsCurrent())
+        attributeSet = addToAtkAttributeSet(attributeSet, "current", coreObject->currentValue().utf8().data());
+
+    // The Core AAM states that an explicitly-set value should be exposed, including "none".
+    if (coreObject->hasAttribute(HTMLNames::aria_sortAttr)) {
+        switch (coreObject->sortDirection()) {
+        case AccessibilitySortDirection::Invalid:
+            break;
+        case AccessibilitySortDirection::Ascending:
+            attributeSet = addToAtkAttributeSet(attributeSet, "sort", "ascending");
+            break;
+        case AccessibilitySortDirection::Descending:
+            attributeSet = addToAtkAttributeSet(attributeSet, "sort", "descending");
+            break;
+        case AccessibilitySortDirection::Other:
+            attributeSet = addToAtkAttributeSet(attributeSet, "sort", "other");
+            break;
+        case AccessibilitySortDirection::None:
+            attributeSet = addToAtkAttributeSet(attributeSet, "sort", "none");
+        }
+    }
+
+    if (coreObject->supportsPosInSet())
+        attributeSet = addToAtkAttributeSet(attributeSet, "posinset", String::number(coreObject->posInSet()).utf8().data());
+
+    if (coreObject->supportsSetSize())
+        attributeSet = addToAtkAttributeSet(attributeSet, "setsize", String::number(coreObject->setSize()).utf8().data());
+
+    String isReadOnly = coreObject->readOnlyValue();
+    if (!isReadOnly.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "readonly", isReadOnly.utf8().data());
+
+    String valueDescription = coreObject->valueDescription();
+    if (!valueDescription.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "valuetext", valueDescription.utf8().data());
+
+    // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
+    // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
+    // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
+    // We cannot use the computedRoleString for this purpose because it is not limited to elements
+    // with ARIA roles, and it might not contain the actual ARIA role value (e.g. DPub ARIA).
+    String roleString = coreObject->getAttribute(HTMLNames::roleAttr);
+    if (!roleString.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", roleString.utf8().data());
+
+    String computedRoleString = coreObject->computedRoleString();
+    if (!computedRoleString.isEmpty()) {
+        attributeSet = addToAtkAttributeSet(attributeSet, "computed-role", computedRoleString.utf8().data());
+
+        // The HTML AAM maps several elements to ARIA landmark roles. In order for the type of landmark
+        // to be obtainable in the same fashion as an ARIA landmark, fall back on the computedRoleString.
+        // We also want to do this for the style-format-group element types so that the type of format
+        // group it is doesn't get lost to a generic platform role.
+        if (coreObject->ariaRoleAttribute() == AccessibilityRole::Unknown
+            && (coreObject->isLandmark() || coreObject->isStyleFormatGroup()))
+            attributeSet = addToAtkAttributeSet(attributeSet, "xml-roles", computedRoleString.utf8().data());
+    }
+
+    String roleDescription = coreObject->roleDescription();
+    if (!roleDescription.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "roledescription", roleDescription.utf8().data());
+
+    // We need to expose the live region attributes even if the live region is currently disabled/off.
+    if (auto liveContainer = coreObject->liveRegionAncestor(false)) {
+        String liveStatus = liveContainer->liveRegionStatus();
+        String relevant = liveContainer->liveRegionRelevant();
+        bool isAtom = liveContainer->liveRegionAtomic();
+        String liveRole = roleString.isEmpty() ? computedRoleString : roleString;
+
+        // According to the Core AAM, we need to expose the above properties with "container-" prefixed
+        // object attributes regardless of whether the container is this object, or an ancestor of it.
+        attributeSet = addToAtkAttributeSet(attributeSet, "container-live", liveStatus.utf8().data());
+        attributeSet = addToAtkAttributeSet(attributeSet, "container-relevant", relevant.utf8().data());
+        if (isAtom)
+            attributeSet = addToAtkAttributeSet(attributeSet, "container-atomic", "true");
+        if (!liveRole.isEmpty())
+            attributeSet = addToAtkAttributeSet(attributeSet, "container-live-role", liveRole.utf8().data());
+
+        // According to the Core AAM, if this object is the live region (rather than its descendant),
+        // we must expose the above properties on the object without a "container-" prefix.
+        if (liveContainer == coreObject) {
+            attributeSet = addToAtkAttributeSet(attributeSet, "live", liveStatus.utf8().data());
+            attributeSet = addToAtkAttributeSet(attributeSet, "relevant", relevant.utf8().data());
+            if (isAtom)
+                attributeSet = addToAtkAttributeSet(attributeSet, "atomic", "true");
+        } else if (!isAtom && coreObject->liveRegionAtomic())
+            attributeSet = addToAtkAttributeSet(attributeSet, "atomic", "true");
+    }
+
+    // The Core AAM states the author-provided value should be exposed as-is.
+    String dropEffect = coreObject->getAttribute(HTMLNames::aria_dropeffectAttr);
+    if (!dropEffect.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "dropeffect", dropEffect.utf8().data());
+
+    if (coreObject->isGrabbed())
+        attributeSet = addToAtkAttributeSet(attributeSet, "grabbed", "true");
+    else if (coreObject->supportsDragging())
+        attributeSet = addToAtkAttributeSet(attributeSet, "grabbed", "false");
+
+    // The Core AAM states the author-provided value should be exposed as-is.
+    const String& keyShortcuts = coreObject->keyShortcuts();
+    if (!keyShortcuts.isEmpty())
+        attributeSet = addToAtkAttributeSet(attributeSet, "keyshortcuts", keyShortcuts.utf8().data());
+
+    return attributeSet;
+}
+
+static AtkRole atkRole(AccessibilityObject* coreObject)
+{
+    switch (coreObject->roleValue()) {
+    case AccessibilityRole::ApplicationAlert:
+        return ATK_ROLE_NOTIFICATION;
+    case AccessibilityRole::ApplicationAlertDialog:
+        return ATK_ROLE_ALERT;
+    case AccessibilityRole::ApplicationDialog:
+        return ATK_ROLE_DIALOG;
+    case AccessibilityRole::ApplicationStatus:
+        return ATK_ROLE_STATUSBAR;
+    case AccessibilityRole::Unknown:
+        return ATK_ROLE_UNKNOWN;
+    case AccessibilityRole::Audio:
+        return ATK_ROLE_AUDIO;
+    case AccessibilityRole::Video:
+        return ATK_ROLE_VIDEO;
+    case AccessibilityRole::Button:
+        return ATK_ROLE_PUSH_BUTTON;
+    case AccessibilityRole::Switch:
+    case AccessibilityRole::ToggleButton:
+        return ATK_ROLE_TOGGLE_BUTTON;
+    case AccessibilityRole::RadioButton:
+        return ATK_ROLE_RADIO_BUTTON;
+    case AccessibilityRole::CheckBox:
+        return ATK_ROLE_CHECK_BOX;
+    case AccessibilityRole::Slider:
+        return ATK_ROLE_SLIDER;
+    case AccessibilityRole::TabGroup:
+    case AccessibilityRole::TabList:
+        return ATK_ROLE_PAGE_TAB_LIST;
+    case AccessibilityRole::TextField:
+    case AccessibilityRole::TextArea:
+    case AccessibilityRole::SearchField:
+        return ATK_ROLE_ENTRY;
+    case AccessibilityRole::StaticText:
+        return ATK_ROLE_STATIC;
+    case AccessibilityRole::Outline:
+    case AccessibilityRole::Tree:
+        return ATK_ROLE_TREE;
+    case AccessibilityRole::TreeItem:
+        return ATK_ROLE_TREE_ITEM;
+    case AccessibilityRole::MenuBar:
+        return ATK_ROLE_MENU_BAR;
+    case AccessibilityRole::MenuListPopup:
+    case AccessibilityRole::Menu:
+        return ATK_ROLE_MENU;
+    case AccessibilityRole::MenuListOption:
+    case AccessibilityRole::MenuItem:
+    case AccessibilityRole::MenuButton:
+        return ATK_ROLE_MENU_ITEM;
+    case AccessibilityRole::MenuItemCheckbox:
+        return ATK_ROLE_CHECK_MENU_ITEM;
+    case AccessibilityRole::MenuItemRadio:
+        return ATK_ROLE_RADIO_MENU_ITEM;
+    case AccessibilityRole::Column:
+        // return ATK_ROLE_TABLE_COLUMN_HEADER; // Is this right?
+        return ATK_ROLE_UNKNOWN; // Matches Mozilla
+    case AccessibilityRole::Row:
+        return ATK_ROLE_TABLE_ROW;
+    case AccessibilityRole::Toolbar:
+        return ATK_ROLE_TOOL_BAR;
+    case AccessibilityRole::Meter:
+        return ATK_ROLE_LEVEL_BAR;
+    case AccessibilityRole::BusyIndicator:
+    case AccessibilityRole::ProgressIndicator:
+        return ATK_ROLE_PROGRESS_BAR;
+    case AccessibilityRole::Window:
+        return ATK_ROLE_WINDOW;
+    case AccessibilityRole::PopUpButton:
+        return coreObject->hasPopup() ? ATK_ROLE_PUSH_BUTTON : ATK_ROLE_COMBO_BOX;
+    case AccessibilityRole::ComboBox:
+        return ATK_ROLE_COMBO_BOX;
+    case AccessibilityRole::SplitGroup:
+        return ATK_ROLE_SPLIT_PANE;
+    case AccessibilityRole::Splitter:
+        return ATK_ROLE_SEPARATOR;
+#if PLATFORM(GTK)
+    case AccessibilityRole::ColorWell:
+        // ATK_ROLE_COLOR_CHOOSER is defined as a dialog (i.e. it's what appears when you push the button).
+        return ATK_ROLE_PUSH_BUTTON;
+#endif
+    case AccessibilityRole::List:
+        return ATK_ROLE_LIST;
+    case AccessibilityRole::ScrollBar:
+        return ATK_ROLE_SCROLL_BAR;
+    case AccessibilityRole::ScrollArea:
+    case AccessibilityRole::TabPanel:
+        return ATK_ROLE_SCROLL_PANE;
+    case AccessibilityRole::Grid:
+    case AccessibilityRole::Table:
+        return ATK_ROLE_TABLE;
+    case AccessibilityRole::TreeGrid:
+        return ATK_ROLE_TREE_TABLE;
+    case AccessibilityRole::Application:
+        return ATK_ROLE_APPLICATION;
+    case AccessibilityRole::ApplicationGroup:
+    case AccessibilityRole::Feed:
+    case AccessibilityRole::Figure:
+    case AccessibilityRole::GraphicsObject:
+    case AccessibilityRole::Group:
+    case AccessibilityRole::RadioGroup:
+    case AccessibilityRole::SVGRoot:
+        return ATK_ROLE_PANEL;
+    case AccessibilityRole::RowHeader:
+        return ATK_ROLE_ROW_HEADER;
+    case AccessibilityRole::ColumnHeader:
+        return ATK_ROLE_COLUMN_HEADER;
+    case AccessibilityRole::Caption:
+        return ATK_ROLE_CAPTION;
+    case AccessibilityRole::Cell:
+    case AccessibilityRole::GridCell:
+        return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_TABLE_CELL;
+    case AccessibilityRole::Link:
+    case AccessibilityRole::WebCoreLink:
+    case AccessibilityRole::ImageMapLink:
+        return ATK_ROLE_LINK;
+    case AccessibilityRole::ImageMap:
+        return ATK_ROLE_IMAGE_MAP;
+    case AccessibilityRole::GraphicsSymbol:
+    case AccessibilityRole::Image:
+        return ATK_ROLE_IMAGE;
+    case AccessibilityRole::ListMarker:
+        return ATK_ROLE_TEXT;
+    case AccessibilityRole::DocumentArticle:
+        return ATK_ROLE_ARTICLE;
+    case AccessibilityRole::Document:
+    case AccessibilityRole::GraphicsDocument:
+        return ATK_ROLE_DOCUMENT_FRAME;
+    case AccessibilityRole::DocumentNote:
+        return ATK_ROLE_COMMENT;
+    case AccessibilityRole::Heading:
+        return ATK_ROLE_HEADING;
+    case AccessibilityRole::ListBox:
+        // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-listbox
+        return coreObject->isDescendantOfRole(AccessibilityRole::ComboBox) ? ATK_ROLE_MENU : ATK_ROLE_LIST_BOX;
+    case AccessibilityRole::ListItem:
+        return coreObject->inheritsPresentationalRole() ? ATK_ROLE_SECTION : ATK_ROLE_LIST_ITEM;
+    case AccessibilityRole::ListBoxOption:
+        return coreObject->isDescendantOfRole(AccessibilityRole::ComboBox) ? ATK_ROLE_MENU_ITEM : ATK_ROLE_LIST_ITEM;
+    case AccessibilityRole::Paragraph:
+        return ATK_ROLE_PARAGRAPH;
+    case AccessibilityRole::Label:
+    case AccessibilityRole::Legend:
+        return ATK_ROLE_LABEL;
+    case AccessibilityRole::Blockquote:
+        return ATK_ROLE_BLOCK_QUOTE;
+#if ATK_CHECK_VERSION(2, 25, 2)
+    case AccessibilityRole::Footnote:
+        return ATK_ROLE_FOOTNOTE;
+#endif
+    case AccessibilityRole::ApplicationTextGroup:
+    case AccessibilityRole::Div:
+    case AccessibilityRole::Pre:
+    case AccessibilityRole::SVGText:
+    case AccessibilityRole::TextGroup:
+        return ATK_ROLE_SECTION;
+    case AccessibilityRole::Footer:
+        return ATK_ROLE_FOOTER;
+    case AccessibilityRole::Form:
+        if (coreObject->ariaRoleAttribute() != AccessibilityRole::Unknown)
+            return ATK_ROLE_LANDMARK;
+        return ATK_ROLE_FORM;
+    case AccessibilityRole::Canvas:
+        return ATK_ROLE_CANVAS;
+    case AccessibilityRole::HorizontalRule:
+        return ATK_ROLE_SEPARATOR;
+    case AccessibilityRole::SpinButton:
+        return ATK_ROLE_SPIN_BUTTON;
+    case AccessibilityRole::Tab:
+        return ATK_ROLE_PAGE_TAB;
+    case AccessibilityRole::UserInterfaceTooltip:
+        return ATK_ROLE_TOOL_TIP;
+    case AccessibilityRole::WebArea:
+        return ATK_ROLE_DOCUMENT_WEB;
+    case AccessibilityRole::WebApplication:
+        return ATK_ROLE_EMBEDDED;
+    case AccessibilityRole::ApplicationLog:
+        return ATK_ROLE_LOG;
+    case AccessibilityRole::ApplicationMarquee:
+        return ATK_ROLE_MARQUEE;
+    case AccessibilityRole::ApplicationTimer:
+        return ATK_ROLE_TIMER;
+    case AccessibilityRole::Definition:
+        return ATK_ROLE_DEFINITION;
+    case AccessibilityRole::DocumentMath:
+        return ATK_ROLE_MATH;
+    case AccessibilityRole::MathElement:
+        if (coreObject->isMathRow())
+            return ATK_ROLE_PANEL;
+        if (coreObject->isMathTable())
+            return ATK_ROLE_TABLE;
+        if (coreObject->isMathTableRow())
+            return ATK_ROLE_TABLE_ROW;
+        if (coreObject->isMathTableCell())
+            return ATK_ROLE_TABLE_CELL;
+        if (coreObject->isMathSubscriptSuperscript() || coreObject->isMathMultiscript())
+            return ATK_ROLE_SECTION;
+        if (coreObject->isMathFraction())
+            return ATK_ROLE_MATH_FRACTION;
+        if (coreObject->isMathSquareRoot() || coreObject->isMathRoot())
+            return ATK_ROLE_MATH_ROOT;
+        if (coreObject->isMathScriptObject(AccessibilityMathScriptObjectType::Subscript)
+            || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PreSubscript) || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PostSubscript))
+            return ATK_ROLE_SUBSCRIPT;
+        if (coreObject->isMathScriptObject(AccessibilityMathScriptObjectType::Superscript)
+            || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PreSuperscript) || coreObject->isMathMultiscriptObject(AccessibilityMathMultiscriptObjectType::PostSuperscript))
+            return ATK_ROLE_SUPERSCRIPT;
+        if (coreObject->isMathToken())
+            return ATK_ROLE_STATIC;
+        return ATK_ROLE_UNKNOWN;
+    case AccessibilityRole::LandmarkBanner:
+    case AccessibilityRole::LandmarkComplementary:
+    case AccessibilityRole::LandmarkContentInfo:
+    case AccessibilityRole::LandmarkDocRegion:
+    case AccessibilityRole::LandmarkMain:
+    case AccessibilityRole::LandmarkNavigation:
+    case AccessibilityRole::LandmarkRegion:
+    case AccessibilityRole::LandmarkSearch:
+        return ATK_ROLE_LANDMARK;
+    case AccessibilityRole::DescriptionList:
+        return ATK_ROLE_DESCRIPTION_LIST;
+    case AccessibilityRole::Term:
+    case AccessibilityRole::DescriptionListTerm:
+        return ATK_ROLE_DESCRIPTION_TERM;
+    case AccessibilityRole::DescriptionListDetail:
+        return ATK_ROLE_DESCRIPTION_VALUE;
+    case AccessibilityRole::Deletion:
+#if ATK_CHECK_VERSION(2, 33, 3)
+        return ATK_ROLE_CONTENT_DELETION;
+#else
+        return ATK_ROLE_STATIC;
+#endif
+    case AccessibilityRole::Insertion:
+#if ATK_CHECK_VERSION(2, 33, 3)
+        return ATK_ROLE_CONTENT_INSERTION;
+#else
+        return ATK_ROLE_STATIC;
+#endif
+    case AccessibilityRole::Subscript:
+        return ATK_ROLE_SUBSCRIPT;
+    case AccessibilityRole::Superscript:
+        return ATK_ROLE_SUPERSCRIPT;
+    case AccessibilityRole::Inline:
+    case AccessibilityRole::SVGTextPath:
+    case AccessibilityRole::SVGTSpan:
+    case AccessibilityRole::Time:
+        return ATK_ROLE_STATIC;
+    default:
+        return ATK_ROLE_UNKNOWN;
+    }
+}
+
+static AtkRole webkitAccessibleGetRole(AtkObject* object)
+{
+    // ATK_ROLE_UNKNOWN should only be applied in cases where there is a valid
+    // WebCore accessible object for which the platform role mapping is unknown.
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, ATK_ROLE_INVALID);
+
+    if (!accessible->priv->object)
+        return ATK_ROLE_INVALID;
+    
+    // Note: Why doesn't WebCore have a password field for this
+    if (accessible->priv->object->isPasswordField())
+        return ATK_ROLE_PASSWORD_TEXT;
+
+    return atkRole(accessible->priv->object);
+}
+
+static bool isTextWithCaret(AccessibilityObject* coreObject)
+{
+    if (!coreObject || !coreObject->isAccessibilityRenderObject())
+        return false;
+
+    Document* document = coreObject->document();
+    if (!document)
+        return false;
+
+    Frame* frame = document->frame();
+    if (!frame)
+        return false;
+
+    if (!frame->settings().caretBrowsingEnabled())
+        return false;
+
+    // Check text objects and paragraphs only.
+    auto* axObject = coreObject->wrapper();
+    AtkRole role = axObject ? atk_object_get_role(ATK_OBJECT(axObject)) : ATK_ROLE_INVALID;
+    if (role != ATK_ROLE_TEXT && role != ATK_ROLE_PARAGRAPH)
+        return false;
+
+    // Finally, check whether the caret is set in the current object.
+    VisibleSelection selection = coreObject->selection();
+    if (!selection.isCaret())
+        return false;
+
+    return selectionBelongsToObject(coreObject, selection);
+}
+
+static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkStateSet* stateSet)
+{
+    AccessibilityObject* parent = coreObject->parentObject();
+    bool isListBoxOption = parent && parent->isListBox();
+
+    // Please keep the state list in alphabetical order
+    if ((isListBoxOption && coreObject->isSelectedOptionActive())
+        || coreObject->currentState() != AccessibilityCurrentState::False)
+        atk_state_set_add_state(stateSet, ATK_STATE_ACTIVE);
+
+    if (coreObject->isBusy())
+        atk_state_set_add_state(stateSet, ATK_STATE_BUSY);
+
+    if (coreObject->supportsChecked() && coreObject->canSetValueAttribute())
+        atk_state_set_add_state(stateSet, ATK_STATE_CHECKABLE);
+
+    if (coreObject->isChecked())
+        atk_state_set_add_state(stateSet, ATK_STATE_CHECKED);
+
+    if ((coreObject->isTextControl() || coreObject->isNonNativeTextControl()) && coreObject->canSetValueAttribute())
+        atk_state_set_add_state(stateSet, ATK_STATE_EDITABLE);
+
+    // FIXME: Put both ENABLED and SENSITIVE together here for now
+    if (coreObject->isEnabled()) {
+        atk_state_set_add_state(stateSet, ATK_STATE_ENABLED);
+        atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE);
+    }
+
+    if (coreObject->canSetExpandedAttribute())
+        atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE);
+
+    if (coreObject->isExpanded())
+        atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED);
+
+    if (coreObject->canSetFocusAttribute())
+        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
+
+    // According to the Core AAM, if the element which is focused has a valid aria-activedescendant,
+    // we should not expose the focused state on the element which is actually focused, but instead
+    // on its active descendant.
+    if ((coreObject->isFocused() && !coreObject->activeDescendant()) || isTextWithCaret(coreObject))
+        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
+    else if (coreObject->isActiveDescendantOfFocusedContainer()) {
+        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
+        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
+    }
+
+    if (coreObject->orientation() == AccessibilityOrientation::Horizontal)
+        atk_state_set_add_state(stateSet, ATK_STATE_HORIZONTAL);
+    else if (coreObject->orientation() == AccessibilityOrientation::Vertical)
+        atk_state_set_add_state(stateSet, ATK_STATE_VERTICAL);
+
+    if (coreObject->hasPopup())
+        atk_state_set_add_state(stateSet, ATK_STATE_HAS_POPUP);
+
+    if (coreObject->isIndeterminate())
+        atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
+    else if (coreObject->isCheckboxOrRadio() || coreObject->isMenuItem() || coreObject->isToggleButton()) {
+        if (coreObject->checkboxOrRadioValue() == AccessibilityButtonState::Mixed)
+            atk_state_set_add_state(stateSet, ATK_STATE_INDETERMINATE);
+    }
+
+    if (coreObject->isModalNode())
+        atk_state_set_add_state(stateSet, ATK_STATE_MODAL);
+
+    if (coreObject->invalidStatus() != "false"_s)
+        atk_state_set_add_state(stateSet, ATK_STATE_INVALID_ENTRY);
+
+    if (coreObject->isMultiSelectable())
+        atk_state_set_add_state(stateSet, ATK_STATE_MULTISELECTABLE);
+
+    // TODO: ATK_STATE_OPAQUE
+
+    if (coreObject->isPressed())
+        atk_state_set_add_state(stateSet, ATK_STATE_PRESSED);
+
+    if (!coreObject->canSetValueAttribute() && (coreObject->supportsReadOnly()))
+        atk_state_set_add_state(stateSet, ATK_STATE_READ_ONLY);
+
+    if (coreObject->isRequired())
+        atk_state_set_add_state(stateSet, ATK_STATE_REQUIRED);
+
+    // TODO: ATK_STATE_SELECTABLE_TEXT
+
+    if (coreObject->canSetSelectedAttribute()) {
+        atk_state_set_add_state(stateSet, ATK_STATE_SELECTABLE);
+        // Items in focusable lists have both STATE_SELECT{ABLE,ED}
+        // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on
+        // the former.
+        if (isListBoxOption)
+            atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
+    }
+
+    if (coreObject->isSelected()) {
+        atk_state_set_add_state(stateSet, ATK_STATE_SELECTED);
+        // Items in focusable lists have both STATE_SELECT{ABLE,ED}
+        // and STATE_FOCUS{ABLE,ED}. We'll fake the latter based on the
+        // former.
+        if (isListBoxOption)
+            atk_state_set_add_state(stateSet, ATK_STATE_FOCUSED);
+    }
+
+    // FIXME: Group both SHOWING and VISIBLE here for now
+    // Not sure how to handle this in WebKit, see bug
+    // http://bugzilla.gnome.org/show_bug.cgi?id=509650 for other
+    // issues with SHOWING vs VISIBLE.
+    if (!coreObject->isOffScreen()) {
+        atk_state_set_add_state(stateSet, ATK_STATE_SHOWING);
+        atk_state_set_add_state(stateSet, ATK_STATE_VISIBLE);
+    }
+
+    // Mutually exclusive, so we group these two
+    if (coreObject->roleValue() == AccessibilityRole::TextArea || coreObject->ariaIsMultiline())
+        atk_state_set_add_state(stateSet, ATK_STATE_MULTI_LINE);
+    else if (coreObject->roleValue() == AccessibilityRole::TextField || coreObject->roleValue() == AccessibilityRole::SearchField)
+        atk_state_set_add_state(stateSet, ATK_STATE_SINGLE_LINE);
+
+    // TODO: ATK_STATE_SENSITIVE
+
+    if (coreObject->supportsAutoComplete() && coreObject->autoCompleteValue() != "none"_s)
+        atk_state_set_add_state(stateSet, ATK_STATE_SUPPORTS_AUTOCOMPLETION);
+
+    if (coreObject->isVisited())
+        atk_state_set_add_state(stateSet, ATK_STATE_VISITED);
+}
+
+static AtkStateSet* webkitAccessibleRefStateSet(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    AtkStateSet* stateSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_state_set(object);
+
+    // Make sure the layout is updated to really know whether the object
+    // is defunct or not, so we can return the proper state.
+    if (accessible->priv->object)
+        accessible->priv->object->updateBackingStore();
+    if (!accessible->priv->object) {
+        atk_state_set_add_state(stateSet, ATK_STATE_DEFUNCT);
+        return stateSet;
+    }
+
+    // Text objects must be focusable.
+    AtkRole role = atk_object_get_role(object);
+    if (role == ATK_ROLE_TEXT || role == ATK_ROLE_PARAGRAPH)
+        atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE);
+
+    setAtkStateSetFromCoreObject(accessible->priv->object, stateSet);
+    return stateSet;
+}
+
+static AtkRelationSet* webkitAccessibleRefRelationSet(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    AtkRelationSet* relationSet = ATK_OBJECT_CLASS(webkit_accessible_parent_class)->ref_relation_set(object);
+    if (accessible->priv->object)
+        setAtkRelationSetFromCoreObject(accessible->priv->object, relationSet);
+    return relationSet;
+}
+
+static void webkitAccessibleInit(AtkObject* object, gpointer data)
+{
+    if (ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize)
+        ATK_OBJECT_CLASS(webkit_accessible_parent_class)->initialize(object, data);
+
+    WebKitAccessible* accessible = WEBKIT_ACCESSIBLE(object);
+    accessible->priv->object = reinterpret_cast<AccessibilityObject*>(data);
+}
+
+static const gchar* webkitAccessibleGetObjectLocale(AtkObject* object)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(object);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    if (!accessible->priv->object)
+        return nullptr;
+    
+    if (ATK_IS_DOCUMENT(object)) {
+        // TODO: Should we fall back on lang xml:lang when the following comes up empty?
+        String language = accessible->priv->object->language();
+        if (!language.isEmpty())
+            return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedDocumentLocale, language.utf8());
+
+    } else if (ATK_IS_TEXT(object)) {
+        const gchar* locale = nullptr;
+
+        AtkAttributeSet* textAttributes = atk_text_get_default_attributes(ATK_TEXT(object));
+        for (auto* attributes = textAttributes; attributes; attributes = attributes->next) {
+            auto* atkAttribute = static_cast<AtkAttribute*>(attributes->data);
+            if (!strcmp(atkAttribute->name, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE))) {
+                locale = webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedDocumentLocale, atkAttribute->value);
+                break;
+            }
+        }
+        atk_attribute_set_free(textAttributes);
+
+        return locale;
+    }
+
+    return nullptr;
+}
+
+static void webkit_accessible_class_init(WebKitAccessibleClass* klass)
+{
+    auto* atkObjectClass = ATK_OBJECT_CLASS(klass);
+    atkObjectClass->initialize = webkitAccessibleInit;
+    atkObjectClass->get_name = webkitAccessibleGetName;
+    atkObjectClass->get_description = webkitAccessibleGetDescription;
+    atkObjectClass->get_parent = webkitAccessibleGetParent;
+    atkObjectClass->get_n_children = webkitAccessibleGetNChildren;
+    atkObjectClass->ref_child = webkitAccessibleRefChild;
+    atkObjectClass->get_role = webkitAccessibleGetRole;
+    atkObjectClass->ref_state_set = webkitAccessibleRefStateSet;
+    atkObjectClass->get_index_in_parent = webkitAccessibleGetIndexInParent;
+    atkObjectClass->get_attributes = webkitAccessibleGetAttributes;
+    atkObjectClass->ref_relation_set = webkitAccessibleRefRelationSet;
+    atkObjectClass->get_object_locale = webkitAccessibleGetObjectLocale;
+}
+
+static const GInterfaceInfo atkInterfacesInitFunctions[] = {
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleActionInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleSelectionInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleEditableTextInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleTextInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleComponentInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleImageInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleTableInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleTableCellInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleHypertextInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleHyperlinkImplInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleDocumentInterfaceInit)), nullptr, nullptr},
+    {reinterpret_cast<GInterfaceInitFunc>(reinterpret_cast<GCallback>(webkitAccessibleValueInterfaceInit)), nullptr, nullptr}
+};
+
+enum WAIType {
+    WAIAction,
+    WAISelection,
+    WAIEditableText,
+    WAIText,
+    WAIComponent,
+    WAIImage,
+    WAITable,
+    WAITableCell,
+    WAIHypertext,
+    WAIHyperlink,
+    WAIDocument,
+    WAIValue,
+};
+
+static GType atkInterfaceTypeFromWAIType(WAIType type)
+{
+    switch (type) {
+    case WAIAction:
+        return ATK_TYPE_ACTION;
+    case WAISelection:
+        return ATK_TYPE_SELECTION;
+    case WAIEditableText:
+        return ATK_TYPE_EDITABLE_TEXT;
+    case WAIText:
+        return ATK_TYPE_TEXT;
+    case WAIComponent:
+        return ATK_TYPE_COMPONENT;
+    case WAIImage:
+        return ATK_TYPE_IMAGE;
+    case WAITable:
+        return ATK_TYPE_TABLE;
+    case WAITableCell:
+        return ATK_TYPE_TABLE_CELL;
+    case WAIHypertext:
+        return ATK_TYPE_HYPERTEXT;
+    case WAIHyperlink:
+        return ATK_TYPE_HYPERLINK_IMPL;
+    case WAIDocument:
+        return ATK_TYPE_DOCUMENT;
+    case WAIValue:
+        return ATK_TYPE_VALUE;
+    }
+
+    return G_TYPE_INVALID;
+}
+
+static bool roleIsTextType(AccessibilityRole role)
+{
+    return role == AccessibilityRole::Paragraph
+        || role == AccessibilityRole::Heading
+        || role == AccessibilityRole::Div
+        || role == AccessibilityRole::Cell
+        || role == AccessibilityRole::Link
+        || role == AccessibilityRole::WebCoreLink
+        || role == AccessibilityRole::ListItem
+        || role == AccessibilityRole::Pre
+        || role == AccessibilityRole::GridCell
+        || role == AccessibilityRole::TextGroup
+        || role == AccessibilityRole::ApplicationTextGroup
+        || role == AccessibilityRole::ApplicationGroup;
+}
+
+static guint16 interfaceMaskFromObject(AXCoreObject* coreObject)
+{
+    guint16 interfaceMask = 0;
+
+    // Component interface is always supported
+    interfaceMask |= 1 << WAIComponent;
+
+    AccessibilityRole role = coreObject->roleValue();
+
+    // Action
+    // As the implementation of the AtkAction interface is a very
+    // basic one (just relays in executing the default action for each
+    // object, and only supports having one action per object), it is
+    // better just to implement this interface for every instance of
+    // the WebKitAccessible class and let WebCore decide what to do.
+    interfaceMask |= 1 << WAIAction;
+
+    // Selection
+    if (coreObject->canHaveSelectedChildren() || coreObject->isMenuList())
+        interfaceMask |= 1 << WAISelection;
+
+    // Get renderer if available.
+    RenderObject* renderer = nullptr;
+    if (coreObject->isAccessibilityRenderObject())
+        renderer = coreObject->renderer();
+
+    // Hyperlink (links and embedded objects).
+    if (coreObject->isLink() || (renderer && renderer->isReplacedOrInlineBlock()))
+        interfaceMask |= 1 << WAIHyperlink;
+
+    // Text, Editable Text & Hypertext
+    if (role == AccessibilityRole::StaticText || coreObject->isMenuListOption())
+        interfaceMask |= 1 << WAIText;
+    else if (coreObject->isTextControl() || coreObject->isNonNativeTextControl()) {
+        interfaceMask |= 1 << WAIText;
+        if (coreObject->canSetValueAttribute())
+            interfaceMask |= 1 << WAIEditableText;
+    } else if (!coreObject->isWebArea()) {
+        if (role != AccessibilityRole::Table) {
+            interfaceMask |= 1 << WAIHypertext;
+            if ((renderer && renderer->childrenInline()) || roleIsTextType(role) || coreObject->isMathToken())
+                interfaceMask |= 1 << WAIText;
+        }
+
+        // Add the TEXT interface for list items whose
+        // first accessible child has a text renderer
+        if (role == AccessibilityRole::ListItem) {
+            const auto& children = coreObject->children();
+            if (!children.isEmpty())
+                interfaceMask |= interfaceMaskFromObject(children[0].get());
+        }
+    }
+
+    // Image
+    if (coreObject->isImage())
+        interfaceMask |= 1 << WAIImage;
+
+    // Table
+    if (coreObject->isTable())
+        interfaceMask |= 1 << WAITable;
+
+    if (role == AccessibilityRole::Cell || role == AccessibilityRole::GridCell || role == AccessibilityRole::ColumnHeader || role == AccessibilityRole::RowHeader)
+        interfaceMask |= 1 << WAITableCell;
+
+    // Document
+    if (role == AccessibilityRole::WebArea)
+        interfaceMask |= 1 << WAIDocument;
+
+    // Value
+    if (coreObject->supportsRangeValue())
+        interfaceMask |= 1 << WAIValue;
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    // Color type.
+    if (role == AccessibilityRole::ColorWell)
+        interfaceMask |= 1 << WAIText;
+#endif
+
+    return interfaceMask;
+}
+
+static const char* uniqueAccessibilityTypeName(guint16 interfaceMask)
+{
+#define WAI_TYPE_NAME_LEN (30) // Enough for prefix + 5 hex characters (max).
+    static char name[WAI_TYPE_NAME_LEN + 1];
+
+    g_sprintf(name, "WAIType%x", interfaceMask);
+    name[WAI_TYPE_NAME_LEN] = '\0';
+
+    return name;
+}
+
+static GType accessibilityTypeFromObject(AccessibilityObject* coreObject)
+{
+    static const GTypeInfo typeInfo = {
+        sizeof(WebKitAccessibleClass),
+        nullptr, // GBaseInitFunc
+        nullptr, // GBaseFinalizeFunc
+        nullptr, // GClassInitFunc
+        nullptr, // GClassFinalizeFunc
+        nullptr, // class data
+        sizeof(WebKitAccessible), // instance size
+        0, // nb preallocs
+        nullptr, // GInstanceInitFunc
+        nullptr // value table
+    };
+
+    guint16 interfaceMask = interfaceMaskFromObject(coreObject);
+    const char* atkTypeName = uniqueAccessibilityTypeName(interfaceMask);
+    if (GType type = g_type_from_name(atkTypeName))
+        return type;
+
+    GType type = g_type_register_static(WEBKIT_TYPE_ACCESSIBLE, atkTypeName, &typeInfo, static_cast<GTypeFlags>(0));
+    for (unsigned i = 0; i < G_N_ELEMENTS(atkInterfacesInitFunctions); ++i) {
+        if (interfaceMask & (1 << i)) {
+            g_type_add_interface_static(type,
+                atkInterfaceTypeFromWAIType(static_cast<WAIType>(i)),
+                &atkInterfacesInitFunctions[i]);
+        }
+    }
+
+    return type;
+}
+
+WebKitAccessible* webkitAccessibleNew(AccessibilityObject* coreObject)
+{
+    auto* object = ATK_OBJECT(g_object_new(accessibilityTypeFromObject(coreObject), nullptr));
+    atk_object_initialize(object, coreObject);
+    return WEBKIT_ACCESSIBLE(object);
+}
+
+AccessibilityObject& webkitAccessibleGetAccessibilityObject(WebKitAccessible* accessible)
+{
+    ASSERT(WEBKIT_IS_ACCESSIBLE(accessible));
+    ASSERT(accessible->priv->object);
+    return *accessible->priv->object;
+}
+
+void webkitAccessibleDetach(WebKitAccessible* accessible)
+{
+    ASSERT(WEBKIT_IS_ACCESSIBLE(accessible));
+
+    if (accessible->priv->object && accessible->priv->object->roleValue() == AccessibilityRole::WebArea)
+        atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_DEFUNCT, TRUE);
+
+    accessible->priv->object = nullptr;
+}
+
+bool webkitAccessibleIsDetached(WebKitAccessible* accessible)
+{
+    ASSERT(WEBKIT_IS_ACCESSIBLE(accessible));
+    return !accessible->priv->object;
+}
+
+const char* webkitAccessibleCacheAndReturnAtkProperty(WebKitAccessible* accessible, AtkCachedProperty property, CString&& value)
+{
+    ASSERT(WEBKIT_IS_ACCESSIBLE(accessible));
+
+    WebKitAccessiblePrivate* priv = accessible->priv;
+    CString* propertyPtr = nullptr;
+
+    switch (property) {
+    case AtkCachedAccessibleName:
+        propertyPtr = &priv->accessibleName;
+        break;
+    case AtkCachedAccessibleDescription:
+        propertyPtr = &priv->accessibleDescription;
+        break;
+    case AtkCachedActionName:
+        propertyPtr = &priv->actionName;
+        break;
+    case AtkCachedActionKeyBinding:
+        propertyPtr = &priv->actionKeyBinding;
+        break;
+    case AtkCachedDocumentLocale:
+        propertyPtr = &priv->documentLocale;
+        break;
+    case AtkCachedDocumentType:
+        propertyPtr = &priv->documentType;
+        break;
+    case AtkCachedDocumentEncoding:
+        propertyPtr = &priv->documentEncoding;
+        break;
+    case AtkCachedDocumentURI:
+        propertyPtr = &priv->documentURI;
+        break;
+    case AtkCachedImageDescription:
+        propertyPtr = &priv->imageDescription;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // Don't invalidate old memory if not stricly needed, since other
+    // callers might be still holding on to it.
+    if (*propertyPtr != value)
+        *propertyPtr = WTFMove(value);
+
+    return (*propertyPtr).data();
+}
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessible.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessible.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessible.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessible.h	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012, 2019 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class AccessibilityObject;
+}
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_ACCESSIBLE            (webkit_accessible_get_type())
+#define WEBKIT_ACCESSIBLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessible))
+#define WEBKIT_ACCESSIBLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessibleClass))
+#define WEBKIT_IS_ACCESSIBLE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_ACCESSIBLE))
+#define WEBKIT_IS_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_ACCESSIBLE))
+#define WEBKIT_ACCESSIBLE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_ACCESSIBLE, WebKitAccessibleClass))
+
+typedef struct _WebKitAccessible        WebKitAccessible;
+typedef struct _WebKitAccessibleClass   WebKitAccessibleClass;
+typedef struct _WebKitAccessiblePrivate WebKitAccessiblePrivate;
+
+
+struct _WebKitAccessible {
+    AtkObject parent;
+
+    WebKitAccessiblePrivate *priv;
+};
+
+struct _WebKitAccessibleClass {
+    AtkObjectClass parentClass;
+};
+
+GType webkit_accessible_get_type(void);
+
+G_END_DECLS
+
+// The definitions below are only used in C++ code, and some use C++ types,
+// therefore they should be outside of the G_BEGIN_DECLS/G_END_DECLS block
+// to make them use the C++ ABI.
+
+enum AtkCachedProperty {
+    AtkCachedAccessibleName,
+    AtkCachedAccessibleDescription,
+    AtkCachedActionName,
+    AtkCachedActionKeyBinding,
+    AtkCachedDocumentLocale,
+    AtkCachedDocumentType,
+    AtkCachedDocumentEncoding,
+    AtkCachedDocumentURI,
+    AtkCachedImageDescription
+};
+
+WebKitAccessible* webkitAccessibleNew(WebCore::AccessibilityObject*);
+
+WebCore::AccessibilityObject& webkitAccessibleGetAccessibilityObject(WebKitAccessible*);
+
+void webkitAccessibleDetach(WebKitAccessible*);
+
+bool webkitAccessibleIsDetached(WebKitAccessible*);
+
+const char* webkitAccessibleCacheAndReturnAtkProperty(WebKitAccessible*, AtkCachedProperty, CString&&);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.cpp	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleHyperlink.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AXObjectCache.h"
+#include "AccessibilityObject.h"
+#include "Editing.h"
+#include "NotImplemented.h"
+#include "Position.h"
+#include "Range.h"
+#include "RenderListMarker.h"
+#include "RenderObject.h"
+#include "TextIterator.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+#include <wtf/glib/WTFGType.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+static void webkit_accessible_hyperlink_atk_action_interface_init(AtkActionIface*);
+
+struct _WebKitAccessibleHyperlinkPrivate {
+    WebKitAccessible* hyperlinkImpl;
+
+    // We cache these values so we can return them as const values.
+    CString actionName;
+    CString actionKeyBinding;
+};
+
+WEBKIT_DEFINE_TYPE_WITH_CODE(
+    WebKitAccessibleHyperlink, webkit_accessible_hyperlink, ATK_TYPE_HYPERLINK,
+    G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, webkit_accessible_hyperlink_atk_action_interface_init))
+
+enum {
+    PROP_0,
+
+    PROP_HYPERLINK_IMPL
+};
+
+static gboolean webkitAccessibleHyperlinkActionDoAction(AtkAction* action, gint)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);
+
+    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
+        return FALSE;
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    return coreObject.performDefaultAction();
+}
+
+static gint webkitAccessibleHyperlinkActionGetNActions(AtkAction* action)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);
+
+    return ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl) ? 1 : 0;
+}
+
+static const gchar* webkitAccessibleHyperlinkActionGetDescription(AtkAction* action, gint)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);
+
+    // TODO: Need a way to provide/localize action descriptions.
+    notImplemented();
+    return "";
+}
+
+static const gchar* webkitAccessibleHyperlinkActionGetKeybinding(AtkAction* action, gint)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);
+
+    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
+        return nullptr;
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    accessibleHyperlink->priv->actionKeyBinding = coreObject.accessKey().utf8();
+    return accessibleHyperlink->priv->actionKeyBinding.data();
+}
+
+static const gchar* webkitAccessibleHyperlinkActionGetName(AtkAction* action, gint)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(action);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);
+
+    if (!ATK_IS_ACTION(accessibleHyperlink->priv->hyperlinkImpl))
+        return nullptr;
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    accessibleHyperlink->priv->actionName = coreObject.localizedActionVerb().utf8();
+    return accessibleHyperlink->priv->actionName.data();
+}
+
+static void webkit_accessible_hyperlink_atk_action_interface_init(AtkActionIface* iface)
+{
+    iface->do_action = webkitAccessibleHyperlinkActionDoAction;
+    iface->get_n_actions = webkitAccessibleHyperlinkActionGetNActions;
+    iface->get_description = webkitAccessibleHyperlinkActionGetDescription;
+    iface->get_keybinding = webkitAccessibleHyperlinkActionGetKeybinding;
+    iface->get_name = webkitAccessibleHyperlinkActionGetName;
+}
+
+static gchar* webkitAccessibleHyperlinkGetURI(AtkHyperlink* link, gint index)
+{
+    // FIXME: Do NOT support more than one instance of an AtkObject
+    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
+    if (index)
+        return nullptr;
+
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, nullptr);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    return !coreObject.url().isNull() ? g_strdup(coreObject.url().string().utf8().data()) : nullptr;
+}
+
+static AtkObject* webkitAccessibleHyperlinkGetObject(AtkHyperlink* link, gint index)
+{
+    // FIXME: Do NOT support more than one instance of an AtkObject
+    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
+    if (index)
+        return nullptr;
+
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);
+
+    return ATK_OBJECT(accessibleHyperlink->priv->hyperlinkImpl);
+}
+
+static gint rangeLengthForObject(AccessibilityObject& obj, const std::optional<SimpleRange>& range)
+{
+    if (!range)
+        return 0;
+
+    // This is going to be the actual length in most of the cases
+    int baseLength = characterCount(*range, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
+
+    // Check whether the current hyperlink belongs to a list item.
+    // If so, we need to consider the length of the item's marker
+    AXCoreObject* parent = obj.parentObjectUnignored();
+    if (!parent || !parent->isAccessibilityRenderObject() || !parent->isListItem())
+        return baseLength;
+
+    // Even if we don't expose list markers to Assistive
+    // Technologies, we need to have a way to measure their length
+    // for those cases when it's needed to take it into account
+    // separately (as in getAccessibilityObjectForOffset)
+    AXCoreObject* markerObj = reinterpret_cast<AccessibilityObject *>(parent)->firstChild();
+    if (!markerObj)
+        return baseLength;
+
+    RenderObject* renderer = markerObj->renderer();
+    if (!is<RenderListMarker>(renderer))
+        return baseLength;
+
+    return baseLength + downcast<RenderListMarker>(*renderer).textWithSuffix().length();
+}
+
+static gint webkitAccessibleHyperlinkGetStartIndex(AtkHyperlink* link)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    AXCoreObject* parentUnignored = coreObject.parentObjectUnignored();
+    if (!parentUnignored)
+        return 0;
+
+    Node* node = coreObject.node();
+    if (!node)
+        return 0;
+
+    Node* parentNode = parentUnignored->node();
+    if (!parentNode)
+        return 0;
+
+    return rangeLengthForObject(coreObject, makeSimpleRange(firstPositionInOrBeforeNode(parentNode), firstPositionInOrBeforeNode(node)));
+}
+
+static gint webkitAccessibleHyperlinkGetEndIndex(AtkHyperlink* link)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessibleHyperlink->priv->hyperlinkImpl);
+    AXCoreObject* parentUnignored = coreObject.parentObjectUnignored();
+    if (!parentUnignored)
+        return 0;
+
+    Node* node = coreObject.node();
+    if (!node)
+        return 0;
+
+    Node* parentNode = parentUnignored->node();
+    if (!parentNode)
+        return 0;
+
+    return rangeLengthForObject(coreObject, makeSimpleRange(firstPositionInOrBeforeNode(parentNode), lastPositionInOrAfterNode(node)));
+}
+
+static gboolean webkitAccessibleHyperlinkIsValid(AtkHyperlink* link)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);
+
+    // Link is valid for the whole object's lifetime
+    return TRUE;
+}
+
+static gint webkitAccessibleHyperlinkGetNAnchors(AtkHyperlink* link)
+{
+    // FIXME Do NOT support more than one instance of an AtkObject
+    // implementing AtkHyperlinkImpl in every instance of AtkHyperLink
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, 0);
+
+    return 1;
+}
+
+static gboolean webkitAccessibleHyperlinkIsSelectedLink(AtkHyperlink* link)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(link);
+    returnValIfWebKitAccessibleIsInvalid(accessibleHyperlink->priv->hyperlinkImpl, FALSE);
+
+    // Not implemented: this function is deprecated in ATK now
+    notImplemented();
+    return FALSE;
+}
+
+static void webkitAccessibleHyperlinkGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* pspec)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(object);
+
+    switch (propId) {
+    case PROP_HYPERLINK_IMPL:
+        g_value_set_object(value, accessibleHyperlink->priv->hyperlinkImpl);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
+    }
+}
+
+static void webkitAccessibleHyperlinkSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* pspec)
+{
+    auto* accessibleHyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(object);
+
+    switch (propId) {
+    case PROP_HYPERLINK_IMPL:
+        accessibleHyperlink->priv->hyperlinkImpl = WEBKIT_ACCESSIBLE(g_value_get_object(value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
+    }
+}
+
+static void webkit_accessible_hyperlink_class_init(WebKitAccessibleHyperlinkClass* klass)
+{
+    GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
+    gobjectClass->set_property = webkitAccessibleHyperlinkSetProperty;
+    gobjectClass->get_property = webkitAccessibleHyperlinkGetProperty;
+
+    AtkHyperlinkClass* atkHyperlinkClass = ATK_HYPERLINK_CLASS(klass);
+    atkHyperlinkClass->get_uri = webkitAccessibleHyperlinkGetURI;
+    atkHyperlinkClass->get_object = webkitAccessibleHyperlinkGetObject;
+    atkHyperlinkClass->get_start_index = webkitAccessibleHyperlinkGetStartIndex;
+    atkHyperlinkClass->get_end_index = webkitAccessibleHyperlinkGetEndIndex;
+    atkHyperlinkClass->is_valid = webkitAccessibleHyperlinkIsValid;
+    atkHyperlinkClass->get_n_anchors = webkitAccessibleHyperlinkGetNAnchors;
+    atkHyperlinkClass->is_selected_link = webkitAccessibleHyperlinkIsSelectedLink;
+
+    g_object_class_install_property(gobjectClass, PROP_HYPERLINK_IMPL,
+        g_param_spec_object("hyperlink-impl",
+            "Hyperlink implementation",
+            "The associated WebKitAccessible instance.",
+            WEBKIT_TYPE_ACCESSIBLE,
+            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
+}
+
+WebKitAccessibleHyperlink* webkitAccessibleHyperlinkGetOrCreate(AtkHyperlinkImpl* hyperlinkImpl)
+{
+    g_return_val_if_fail(ATK_IS_HYPERLINK_IMPL(hyperlinkImpl), nullptr);
+    g_return_val_if_fail(WEBKIT_IS_ACCESSIBLE(hyperlinkImpl), nullptr);
+
+    if (auto* currentHyperLink = g_object_get_data(G_OBJECT(hyperlinkImpl), "webkit-accessible-hyperlink-object"))
+        return WEBKIT_ACCESSIBLE_HYPERLINK(g_object_ref(currentHyperLink));
+
+    auto* hyperlink = WEBKIT_ACCESSIBLE_HYPERLINK(g_object_new(WEBKIT_TYPE_ACCESSIBLE_HYPERLINK, "hyperlink-impl", hyperlinkImpl, nullptr));
+    g_object_set_data_full(G_OBJECT(hyperlinkImpl), "webkit-accessible-hyperlink-object", hyperlink, g_object_unref);
+    return hyperlink;
+}
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleHyperlink.h	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_ACCESSIBLE_HYPERLINK             (webkit_accessible_hyperlink_get_type())
+#define WEBKIT_ACCESSIBLE_HYPERLINK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_ACCESSIBLE_HYPERLINK, WebKitAccessibleHyperlink))
+#define WEBKIT_ACCESSIBLE_HYPERLINK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_ACCESSIBLE_HYPERLINK, WebKitAccessibleHyperlinkClass))
+#define WEBKIT_IS_ACCESSIBLE_HYPERLINK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_ACCESSIBLE_HYPERLINK))
+#define WEBKIT_IS_ACCESSIBLE_HYPERLINK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_ACCESSIBLE_HYPERLINK))
+#define WEBKIT_ACCESSIBLE_HYPERLINK_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_ACCESSIBLE_HYPERLINK, WebKitAccessibleHyperlinkClass))
+
+typedef struct _WebKitAccessibleHyperlink        WebKitAccessibleHyperlink;
+typedef struct _WebKitAccessibleHyperlinkClass   WebKitAccessibleHyperlinkClass;
+typedef struct _WebKitAccessibleHyperlinkPrivate WebKitAccessibleHyperlinkPrivate;
+
+struct _WebKitAccessibleHyperlink {
+    AtkHyperlink parent;
+
+    WebKitAccessibleHyperlinkPrivate *priv;
+};
+
+struct _WebKitAccessibleHyperlinkClass {
+    AtkHyperlinkClass parentClass;
+};
+
+GType webkit_accessible_hyperlink_get_type(void);
+
+WebKitAccessibleHyperlink* webkitAccessibleHyperlinkGetOrCreate(AtkHyperlinkImpl*);
+
+G_END_DECLS
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.cpp	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceAction.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "NotImplemented.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkAction* action)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(action))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(action));
+}
+
+static gboolean webkitAccessibleActionDoAction(AtkAction* action, gint index)
+{
+    g_return_val_if_fail(ATK_IS_ACTION(action), FALSE);
+    g_return_val_if_fail(!index, FALSE);
+
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(action), FALSE);
+
+    return core(action)->performDefaultAction();
+}
+
+static gint webkitAccessibleActionGetNActions(AtkAction* action)
+{
+    g_return_val_if_fail(ATK_IS_ACTION(action), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(action), 0);
+
+    return 1;
+}
+
+static const gchar* webkitAccessibleActionGetDescription(AtkAction* action, gint)
+{
+    g_return_val_if_fail(ATK_IS_ACTION(action), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(action), 0);
+
+    // TODO: Need a way to provide/localize action descriptions.
+    notImplemented();
+    return "";
+}
+
+static const gchar* webkitAccessibleActionGetKeybinding(AtkAction* action, gint)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(action);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    // FIXME: Construct a proper keybinding string.
+    return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedActionKeyBinding, core(action)->accessKey().utf8());
+}
+
+static const gchar* webkitAccessibleActionGetName(AtkAction* action, gint)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(action);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedActionName, core(action)->localizedActionVerb().utf8());
+}
+
+void webkitAccessibleActionInterfaceInit(AtkActionIface* iface)
+{
+    iface->do_action = webkitAccessibleActionDoAction;
+    iface->get_n_actions = webkitAccessibleActionGetNActions;
+    iface->get_description = webkitAccessibleActionGetDescription;
+    iface->get_keybinding = webkitAccessibleActionGetKeybinding;
+    iface->get_name = webkitAccessibleActionGetName;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceAction.h	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleActionInterfaceInit(AtkActionIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.cpp	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2012 Igalia S.L.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceComponent.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "FrameView.h"
+#include "IntRect.h"
+#include "RenderLayer.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static IntPoint atkToContents(const AccessibilityObject& coreObject, AtkCoordType coordType, gint x, gint y)
+{
+    auto* frameView = coreObject.documentFrameView();
+    if (!frameView)
+        return { x, y };
+
+    switch (coordType) {
+    case ATK_XY_SCREEN:
+        return frameView->screenToContents({ x, y });
+    case ATK_XY_WINDOW:
+        return frameView->windowToContents({ x, y });
+#if ATK_CHECK_VERSION(2, 30, 0)
+    case ATK_XY_PARENT:
+        RELEASE_ASSERT_NOT_REACHED();
+#endif
+    }
+
+    return { x, y };
+}
+
+static AtkObject* webkitAccessibleComponentRefAccessibleAtPoint(AtkComponent* component, gint x, gint y, AtkCoordType coordType)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(component);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessible);
+    auto* target = downcast<AccessibilityObject>(coreObject.accessibilityHitTest(atkToContents(coreObject, coordType, x, y)));
+    if (!target)
+        return nullptr;
+
+    if (auto* wrapper = target->wrapper())
+        return ATK_OBJECT(g_object_ref(wrapper));
+
+    return nullptr;
+}
+
+static void webkitAccessibleComponentGetExtents(AtkComponent* component, gint* x, gint* y, gint* width, gint* height, AtkCoordType coordType)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(component);
+    returnIfWebKitAccessibleIsInvalid(accessible);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessible);
+    contentsRelativeToAtkCoordinateType(&coreObject, coordType, snappedIntRect(coreObject.elementRect()), x, y, width, height);
+}
+
+static gboolean webkitAccessibleComponentGrabFocus(AtkComponent* component)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(component);
+    returnValIfWebKitAccessibleIsInvalid(accessible, FALSE);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessible);
+    coreObject.setFocused(true);
+    return coreObject.isFocused();
+}
+
+#if ATK_CHECK_VERSION(2, 30, 0)
+static gboolean webkitAccessibleComponentScrollTo(AtkComponent* component, AtkScrollType scrollType)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(component);
+    returnValIfWebKitAccessibleIsInvalid(accessible, FALSE);
+
+    ScrollAlignment alignX;
+    ScrollAlignment alignY;
+
+    switch (scrollType) {
+    case ATK_SCROLL_TOP_LEFT:
+        alignX = ScrollAlignment::alignLeftAlways;
+        alignY = ScrollAlignment::alignTopAlways;
+        break;
+    case ATK_SCROLL_BOTTOM_RIGHT:
+        alignX = ScrollAlignment::alignRightAlways;
+        alignY = ScrollAlignment::alignBottomAlways;
+        break;
+    case ATK_SCROLL_TOP_EDGE:
+    case ATK_SCROLL_BOTTOM_EDGE:
+        // Align to a particular edge is not supported, it's always the closest edge.
+        alignX = ScrollAlignment::alignCenterIfNeeded;
+        alignY = ScrollAlignment::alignToEdgeIfNeeded;
+        break;
+    case ATK_SCROLL_LEFT_EDGE:
+    case ATK_SCROLL_RIGHT_EDGE:
+        // Align to a particular edge is not supported, it's always the closest edge.
+        alignX = ScrollAlignment::alignToEdgeIfNeeded;
+        alignY = ScrollAlignment::alignCenterIfNeeded;
+        break;
+    case ATK_SCROLL_ANYWHERE:
+        alignX = ScrollAlignment::alignCenterIfNeeded;
+        alignY = ScrollAlignment::alignCenterIfNeeded;
+        break;
+    }
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessible);
+    coreObject.scrollToMakeVisible({ SelectionRevealMode::Reveal, alignX, alignY, ShouldAllowCrossOriginScrolling::Yes });
+
+    return TRUE;
+}
+
+static gboolean webkitAccessibleComponentScrollToPoint(AtkComponent* component, AtkCoordType coordType, gint x, gint y)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(component);
+    returnValIfWebKitAccessibleIsInvalid(accessible, FALSE);
+
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(accessible);
+
+    IntPoint point(x, y);
+    if (coordType == ATK_XY_SCREEN) {
+        if (auto* frameView = coreObject.documentFrameView())
+            point = frameView->contentsToWindow(frameView->screenToContents(point));
+    }
+
+    coreObject.scrollToGlobalPoint(point);
+
+    return TRUE;
+}
+#endif
+
+void webkitAccessibleComponentInterfaceInit(AtkComponentIface* iface)
+{
+    iface->ref_accessible_at_point = webkitAccessibleComponentRefAccessibleAtPoint;
+    iface->get_extents = webkitAccessibleComponentGetExtents;
+    iface->grab_focus = webkitAccessibleComponentGrabFocus;
+#if ATK_CHECK_VERSION(2, 30, 0)
+    iface->scroll_to = webkitAccessibleComponentScrollTo;
+    iface->scroll_to_point = webkitAccessibleComponentScrollToPoint;
+#endif
+}
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceComponent.h	2023-03-09 13:26:47.278643843 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleComponentInterfaceInit(AtkComponentIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2012 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceDocument.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "DocumentInlines.h"
+#include "DocumentType.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkDocument* document)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(document))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(document));
+}
+
+static const gchar* documentAttributeValue(AtkDocument* document, const gchar* attribute)
+{
+    Document* coreDocument = core(document)->document();
+    if (!coreDocument)
+        return 0;
+
+    String value;
+    AtkCachedProperty atkCachedProperty;
+
+    if (!g_ascii_strcasecmp(attribute, "DocType") && coreDocument->doctype()) {
+        value = coreDocument->doctype()->name();
+        atkCachedProperty = AtkCachedDocumentType;
+    } else if (!g_ascii_strcasecmp(attribute, "Encoding")) {
+        value = coreDocument->charset();
+        atkCachedProperty = AtkCachedDocumentEncoding;
+    } else if (!g_ascii_strcasecmp(attribute, "URI")) {
+        value = coreDocument->documentURI();
+        atkCachedProperty = AtkCachedDocumentURI;
+    }
+
+    if (!value.isEmpty())
+        return webkitAccessibleCacheAndReturnAtkProperty(WEBKIT_ACCESSIBLE(document), atkCachedProperty, value.utf8());
+
+    return 0;
+}
+
+static const gchar* webkitAccessibleDocumentGetAttributeValue(AtkDocument* document, const gchar* attribute)
+{
+    g_return_val_if_fail(ATK_IS_DOCUMENT(document), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(document), 0);
+
+    return documentAttributeValue(document, attribute);
+}
+
+static AtkAttributeSet* webkitAccessibleDocumentGetAttributes(AtkDocument* document)
+{
+    g_return_val_if_fail(ATK_IS_DOCUMENT(document), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(document), 0);
+
+    AtkAttributeSet* attributeSet = nullptr;
+    const gchar* attributes[] = { "DocType", "Encoding", "URI" };
+
+    for (unsigned i = 0; i < G_N_ELEMENTS(attributes); i++) {
+        const gchar* value = documentAttributeValue(document, attributes[i]);
+        if (value)
+            attributeSet = addToAtkAttributeSet(attributeSet, attributes[i], value);
+    }
+
+    return attributeSet;
+}
+
+static const gchar* webkitAccessibleDocumentGetLocale(AtkDocument* document)
+{
+    g_return_val_if_fail(ATK_IS_DOCUMENT(document), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(document), 0);
+
+    // The logic to resolve locale has been moved to
+    // AtkObject::get_object_locale() virtual method. However, to avoid breaking
+    // clients expecting the deprecated AtkDocumentIface::get_document_locale()
+    // to be overriden, method is kept and chained up to
+    // AtkObject::get_object_locale(). <https://bugs.webkit.org/show_bug.cgi?id=115647>
+    return atk_object_get_object_locale(ATK_OBJECT(document));
+}
+
+void webkitAccessibleDocumentInterfaceInit(AtkDocumentIface* iface)
+{
+    iface->get_document_attribute_value = webkitAccessibleDocumentGetAttributeValue;
+    iface->get_document_attributes = webkitAccessibleDocumentGetAttributes;
+    iface->get_document_locale = webkitAccessibleDocumentGetLocale;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceDocument.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleDocumentInterfaceInit(AtkDocumentIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2011, 2012 Igalia S.L.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceEditableText.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "Document.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "NotImplemented.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkEditableText* text)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(text))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(text));
+}
+
+static gboolean webkitAccessibleEditableTextSetRunAttributes(AtkEditableText* text, AtkAttributeSet*, gint, gint)
+{
+    g_return_val_if_fail(ATK_IS_EDITABLE_TEXT(text), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), FALSE);
+
+    notImplemented();
+    return FALSE;
+}
+
+static void webkitAccessibleEditableTextSetTextContents(AtkEditableText* text, const gchar* string)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    // FIXME: string nullcheck?
+    core(text)->setValue(String::fromUTF8(string));
+}
+
+static void webkitAccessibleEditableTextInsertText(AtkEditableText* text, const gchar* string, gint length, gint* position)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    if (!string)
+        return;
+
+    AccessibilityObject* coreObject = core(text);
+    // FIXME: Not implemented in WebCore
+    // coreObject->setSelectedTextRange(PlainTextRange(*position, 0));
+    // coreObject->setSelectedText(String::fromUTF8(string));
+
+    Document* document = coreObject->document();
+    if (!document || !document->frame())
+        return;
+
+    coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(*position, 0)));
+    coreObject->setFocused(true);
+    // FIXME: We should set position to the actual inserted text length, which may be less than that requested.
+    if (document->frame()->editor().insertTextWithoutSendingTextEvent(String::fromUTF8(string).substring(0, length), false, 0))
+        *position += length;
+}
+
+static void webkitAccessibleEditableTextCopyText(AtkEditableText* text, gint, gint)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    notImplemented();
+}
+
+static void webkitAccessibleEditableTextCutText(AtkEditableText* text, gint, gint)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    notImplemented();
+}
+
+static void webkitAccessibleEditableTextDeleteText(AtkEditableText* text, gint startPos, gint endPos)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    AccessibilityObject* coreObject = core(text);
+    // FIXME: Not implemented in WebCore
+    // coreObject->setSelectedTextRange(PlainTextRange(startPos, endPos - startPos));
+    // coreObject->setSelectedText(String());
+
+    Document* document = coreObject->document();
+    if (!document || !document->frame())
+        return;
+
+    coreObject->setSelectedVisiblePositionRange(coreObject->visiblePositionRangeForRange(PlainTextRange(startPos, endPos - startPos)));
+    coreObject->setFocused(true);
+    document->frame()->editor().performDelete();
+}
+
+static void webkitAccessibleEditableTextPasteText(AtkEditableText* text, gint)
+{
+    g_return_if_fail(ATK_IS_EDITABLE_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    notImplemented();
+}
+
+void webkitAccessibleEditableTextInterfaceInit(AtkEditableTextIface* iface)
+{
+    iface->set_run_attributes = webkitAccessibleEditableTextSetRunAttributes;
+    iface->set_text_contents = webkitAccessibleEditableTextSetTextContents;
+    iface->insert_text = webkitAccessibleEditableTextInsertText;
+    iface->copy_text = webkitAccessibleEditableTextCopyText;
+    iface->cut_text = webkitAccessibleEditableTextCutText;
+    iface->delete_text = webkitAccessibleEditableTextDeleteText;
+    iface->paste_text = webkitAccessibleEditableTextPasteText;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceEditableText.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleEditableTextInterfaceInit(AtkEditableTextIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceHyperlinkImpl.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "WebKitAccessibleHyperlink.h"
+
+static AtkHyperlink* webkitAccessibleHyperlinkImplGetHyperlink(AtkHyperlinkImpl* hyperlink)
+{
+    return ATK_HYPERLINK(webkitAccessibleHyperlinkGetOrCreate(hyperlink));
+}
+
+void webkitAccessibleHyperlinkImplInterfaceInit(AtkHyperlinkImplIface* iface)
+{
+    iface->get_hyperlink = webkitAccessibleHyperlinkImplGetHyperlink;
+}
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleHyperlinkImplInterfaceInit(AtkHyperlinkImplIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceHypertext.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkHypertext* hypertext)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(hypertext))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(hypertext));
+}
+
+static AtkHyperlink* webkitAccessibleHypertextGetLink(AtkHypertext* hypertext, gint index)
+{
+    g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), 0);
+
+    const AccessibilityObject::AccessibilityChildrenVector& children = core(hypertext)->children();
+    if (index < 0 || static_cast<unsigned>(index) >= children.size())
+        return 0;
+
+    gint currentLink = -1;
+    for (const auto& child : children) {
+        AXCoreObject* coreChild = child.get();
+        if (!coreChild->accessibilityIsIgnored()) {
+            auto* axObject = coreChild->wrapper();
+            if (!axObject || !ATK_IS_HYPERLINK_IMPL(axObject))
+                continue;
+
+            currentLink++;
+            if (index != currentLink)
+                continue;
+
+            return atk_hyperlink_impl_get_hyperlink(ATK_HYPERLINK_IMPL(axObject));
+        }
+    }
+
+    return 0;
+}
+
+static gint webkitAccessibleHypertextGetNLinks(AtkHypertext* hypertext)
+{
+    g_return_val_if_fail(ATK_HYPERTEXT(hypertext), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), 0);
+
+    const AccessibilityObject::AccessibilityChildrenVector& children = core(hypertext)->children();
+    gint linksFound = 0;
+    for (const auto& child : children) {
+        AXCoreObject* coreChild = child.get();
+        if (!coreChild->accessibilityIsIgnored()) {
+            auto* axObject = coreChild->wrapper();
+            if (axObject && ATK_IS_HYPERLINK_IMPL(axObject))
+                linksFound++;
+        }
+    }
+
+    return linksFound;
+}
+
+static gint webkitAccessibleHypertextGetLinkIndex(AtkHypertext* hypertext, gint charIndex)
+{
+    g_return_val_if_fail(ATK_HYPERTEXT(hypertext), -1);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(hypertext), -1);
+
+    size_t linksCount = webkitAccessibleHypertextGetNLinks(hypertext);
+    if (!linksCount)
+        return -1;
+
+    for (size_t i = 0; i < linksCount; i++) {
+        AtkHyperlink* hyperlink = ATK_HYPERLINK(webkitAccessibleHypertextGetLink(hypertext, i));
+        gint startIndex = atk_hyperlink_get_start_index(hyperlink);
+        gint endIndex = atk_hyperlink_get_end_index(hyperlink);
+
+        // Check if the char index in the link's offset range
+        if (startIndex <= charIndex && charIndex < endIndex)
+            return i;
+    }
+
+    // Not found if reached
+    return -1;
+}
+
+void webkitAccessibleHypertextInterfaceInit(AtkHypertextIface* iface)
+{
+    iface->get_link = webkitAccessibleHypertextGetLink;
+    iface->get_n_links = webkitAccessibleHypertextGetNLinks;
+    iface->get_link_index = webkitAccessibleHypertextGetLinkIndex;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceHypertext.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleHypertextInterfaceInit(AtkHypertextIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2012 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceImage.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "IntRect.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkImage* image)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(image))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(image));
+}
+
+static void webkitAccessibleImageGetImagePosition(AtkImage* image, gint* x, gint* y, AtkCoordType coordType)
+{
+    g_return_if_fail(ATK_IMAGE(image));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(image));
+
+    IntRect rect = snappedIntRect(core(image)->elementRect());
+    contentsRelativeToAtkCoordinateType(core(image), coordType, rect, x, y);
+}
+
+static const gchar* webkitAccessibleImageGetImageDescription(AtkImage* image)
+{
+    auto* accessible = WEBKIT_ACCESSIBLE(image);
+    returnValIfWebKitAccessibleIsInvalid(accessible, nullptr);
+
+    return webkitAccessibleCacheAndReturnAtkProperty(accessible, AtkCachedImageDescription, accessibilityDescription(core(image)).utf8());
+}
+
+static void webkitAccessibleImageGetImageSize(AtkImage* image, gint* width, gint* height)
+{
+    g_return_if_fail(ATK_IMAGE(image));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(image));
+
+    IntSize size = snappedIntRect(core(image)->elementRect()).size();
+
+    if (width)
+        *width = size.width();
+    if (height)
+        *height = size.height();
+}
+
+void webkitAccessibleImageInterfaceInit(AtkImageIface* iface)
+{
+    iface->get_image_position = webkitAccessibleImageGetImagePosition;
+    iface->get_image_description = webkitAccessibleImageGetImageDescription;
+    iface->get_image_size = webkitAccessibleImageGetImageSize;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceImage.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleImageInterfaceInit(AtkImageIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.cpp	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceSelection.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityListBox.h"
+#include "AccessibilityObject.h"
+#include "HTMLSelectElement.h"
+#include "RenderObject.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkSelection* selection)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(selection))
+        return nullptr;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(selection));
+}
+
+static AXCoreObject* listObjectForCoreSelection(AccessibilityObject* coreSelection)
+{
+    // Only list boxes and menu lists supported so far.
+    if (!coreSelection->isListBox() && !coreSelection->isMenuList())
+        return nullptr;
+
+    // For list boxes the list object is just itself.
+    if (coreSelection->isListBox())
+        return coreSelection;
+
+    // For menu lists we need to return the first accessible child,
+    // with role MenuListPopupRole, since that's the one holding the list
+    // of items with role MenuListOptionRole.
+    const AccessibilityObject::AccessibilityChildrenVector& children = coreSelection->children();
+    if (!children.size())
+        return nullptr;
+
+    AXCoreObject* listObject = children.at(0).get();
+    if (!listObject->isMenuListPopup())
+        return nullptr;
+
+    return listObject;
+}
+
+static AXCoreObject* optionFromList(AtkSelection* selection, gint index)
+{
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection || index < 0)
+        return nullptr;
+
+    // Need to select the proper list object depending on the type.
+    AXCoreObject* listObject = listObjectForCoreSelection(coreSelection);
+    if (!listObject)
+        return nullptr;
+
+    const AccessibilityObject::AccessibilityChildrenVector& options = listObject->children();
+    if (index < static_cast<gint>(options.size()))
+        return options.at(index).get();
+
+    return nullptr;
+}
+
+static AXCoreObject* optionFromSelection(AtkSelection* selection, gint index)
+{
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection || !coreSelection->isAccessibilityRenderObject() || index < 0)
+        return nullptr;
+
+    // This method provides the functionality expected by atk_selection_ref_selection().
+    // According to the ATK documentation for this method, the index is "a gint specifying
+    // the index in the selection set. (e.g. the ith selection as opposed to the ith child)."
+    // There is different API, namely atk_object_ref_accessible_child(), when the ith child
+    // from the set of all children is sought.
+    AccessibilityObject::AccessibilityChildrenVector options;
+    coreSelection->selectedChildren(options);
+    if (index < static_cast<gint>(options.size()))
+        return options.at(index).get();
+
+    return nullptr;
+}
+
+static gboolean webkitAccessibleSelectionAddSelection(AtkSelection* selection, gint index)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), FALSE);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection)
+        return FALSE;
+
+    AXCoreObject* option = optionFromList(selection, index);
+    if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) {
+        option->setSelected(true);
+        return option->isSelected();
+    }
+
+    return FALSE;
+}
+
+static gboolean webkitAccessibleSelectionClearSelection(AtkSelection* selection)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), FALSE);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection)
+        return FALSE;
+
+    AccessibilityObject::AccessibilityChildrenVector selectedItems;
+    if (is<AccessibilityListBox>(*coreSelection)) {
+        // Set the list of selected items to an empty list; then verify that it worked.
+        auto& listBox = downcast<AccessibilityListBox>(*coreSelection);
+        listBox.setSelectedChildren(selectedItems);
+        listBox.selectedChildren(selectedItems);
+        return selectedItems.isEmpty();
+    }
+    return FALSE;
+}
+
+static AtkObject* webkitAccessibleSelectionRefSelection(AtkSelection* selection, gint index)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), nullptr);
+
+    AXCoreObject* option = optionFromSelection(selection, index);
+    if (option) {
+        auto* child = option->wrapper();
+        g_object_ref(child);
+        return ATK_OBJECT(child);
+    }
+
+    return nullptr;
+}
+
+static gint webkitAccessibleSelectionGetSelectionCount(AtkSelection* selection)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), 0);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection || !coreSelection->isAccessibilityRenderObject())
+        return 0;
+
+    if (coreSelection->isMenuList()) {
+        RenderObject* renderer = coreSelection->renderer();
+        if (!renderer)
+            return 0;
+
+        int selectedIndex = downcast<HTMLSelectElement>(renderer->node())->selectedIndex();
+        return selectedIndex >= 0 && selectedIndex < static_cast<int>(downcast<HTMLSelectElement>(renderer->node())->listItems().size());
+    }
+
+    AccessibilityObject::AccessibilityChildrenVector selectedItems;
+    coreSelection->selectedChildren(selectedItems);
+    return static_cast<gint>(selectedItems.size());
+}
+
+static gboolean webkitAccessibleSelectionIsChildSelected(AtkSelection* selection, gint index)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), FALSE);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection)
+        return FALSE;
+
+    AXCoreObject* option = optionFromList(selection, index);
+    if (option && (coreSelection->isListBox() || coreSelection->isMenuList()))
+        return option->isSelected();
+
+    return FALSE;
+}
+
+static gboolean webkitAccessibleSelectionRemoveSelection(AtkSelection* selection, gint index)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), FALSE);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection)
+        return FALSE;
+
+    AXCoreObject* option = optionFromSelection(selection, index);
+    if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) {
+        option->setSelected(false);
+        return !option->isSelected();
+    }
+
+    return FALSE;
+}
+
+static gboolean webkitAccessibleSelectionSelectAllSelection(AtkSelection* selection)
+{
+    g_return_val_if_fail(ATK_SELECTION(selection), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(selection), FALSE);
+
+    AccessibilityObject* coreSelection = core(selection);
+    if (!coreSelection || !coreSelection->isMultiSelectable())
+        return FALSE;
+
+    if (is<AccessibilityListBox>(*coreSelection)) {
+        const AccessibilityObject::AccessibilityChildrenVector& children = coreSelection->children();
+        AccessibilityListBox& listBox = downcast<AccessibilityListBox>(*coreSelection);
+        listBox.setSelectedChildren(children);
+        AccessibilityObject::AccessibilityChildrenVector selectedItems;
+        listBox.selectedChildren(selectedItems);
+        return selectedItems.size() == children.size();
+    }
+
+    return FALSE;
+}
+
+void webkitAccessibleSelectionInterfaceInit(AtkSelectionIface* iface)
+{
+    iface->add_selection = webkitAccessibleSelectionAddSelection;
+    iface->clear_selection = webkitAccessibleSelectionClearSelection;
+    iface->ref_selection = webkitAccessibleSelectionRefSelection;
+    iface->get_selection_count = webkitAccessibleSelectionGetSelectionCount;
+    iface->is_child_selected = webkitAccessibleSelectionIsChildSelected;
+    iface->remove_selection = webkitAccessibleSelectionRemoveSelection;
+    iface->select_all_selection = webkitAccessibleSelectionSelectAllSelection;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceSelection.h	2023-03-09 13:26:47.282643864 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleSelectionInterfaceInit(AtkSelectionIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceTableCell.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "AccessibilityTable.h"
+#include "AccessibilityTableCell.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static GPtrArray* convertToGPtrArray(const AccessibilityObject::AccessibilityChildrenVector& children)
+{
+    GPtrArray* array = g_ptr_array_new();
+    for (const auto& child : children) {
+        if (auto* atkObject = child->wrapper())
+            g_ptr_array_add(array, atkObject);
+    }
+    return array;
+}
+
+static AccessibilityObject* core(AtkTableCell* cell)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(cell))
+        return nullptr;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(cell));
+}
+
+GPtrArray* webkitAccessibleTableCellGetColumnHeaderCells(AtkTableCell* cell)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), nullptr);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!is<AccessibilityTableCell>(axObject))
+        return nullptr;
+
+    auto columnHeaders = downcast<AccessibilityTableCell>(*axObject).columnHeaders();
+
+    return convertToGPtrArray(columnHeaders);
+}
+
+GPtrArray* webkitAccessibleTableCellGetRowHeaderCells(AtkTableCell* cell)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), nullptr);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!is<AccessibilityTableCell>(axObject))
+        return nullptr;
+
+    auto rowHeaders = downcast<AccessibilityTableCell>(*axObject).rowHeaders();
+
+    return convertToGPtrArray(rowHeaders);
+}
+
+gint webkitAccessibleTableCellGetColumnSpan(AtkTableCell* cell)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), 0);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!is<AccessibilityTableCell>(axObject))
+        return 0;
+
+    return axObject->columnIndexRange().second;
+}
+
+gint webkitAccessibleTableCellGetRowSpan(AtkTableCell* cell)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), 0);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!is<AccessibilityTableCell>(axObject))
+        return 0;
+
+    return axObject->rowIndexRange().second;
+}
+
+gboolean webkitAccessibleTableCellGetPosition(AtkTableCell* cell, gint* row, gint* column)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), false);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), false);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!is<AccessibilityTableCell>(axObject))
+        return false;
+
+    if (row) {
+        // aria-rowindex is 1-based.
+        int rowIndex = axObject->axRowIndex() - 1;
+        if (rowIndex <= -1)
+            rowIndex = axObject->rowIndexRange().first;
+        *row = rowIndex;
+    }
+    if (column) {
+        // aria-colindex is 1-based.
+        int columnIndex = axObject->axColumnIndex() - 1;
+        if (columnIndex <= -1)
+            columnIndex = axObject->columnIndexRange().first;
+        *column = columnIndex;
+    }
+
+    return true;
+}
+
+AtkObject* webkitAccessibleTableCellGetTable(AtkTableCell* cell)
+{
+    g_return_val_if_fail(ATK_TABLE_CELL(cell), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(cell), nullptr);
+
+    AccessibilityObject* axObject = core(cell);
+    if (!axObject || !axObject->isTableCell())
+        return nullptr;
+
+    auto* table = atk_object_get_parent(ATK_OBJECT(axObject->wrapper()));
+    if (!table || !ATK_IS_TABLE(table))
+        return nullptr;
+
+    return ATK_OBJECT(g_object_ref(table));
+}
+
+void webkitAccessibleTableCellInterfaceInit(AtkTableCellIface* iface)
+{
+    iface->get_column_header_cells = webkitAccessibleTableCellGetColumnHeaderCells;
+    iface->get_row_header_cells = webkitAccessibleTableCellGetRowHeaderCells;
+    iface->get_column_span = webkitAccessibleTableCellGetColumnSpan;
+    iface->get_row_span = webkitAccessibleTableCellGetRowSpan;
+    iface->get_position = webkitAccessibleTableCellGetPosition;
+    iface->get_table = webkitAccessibleTableCellGetTable;
+}
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTableCell.h	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleTableCellInterfaceInit(AtkTableCellIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceTable.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityListBox.h"
+#include "AccessibilityObject.h"
+#include "AccessibilityTable.h"
+#include "AccessibilityTableCell.h"
+#include "HTMLTableCaptionElement.h"
+#include "HTMLTableElement.h"
+#include "RenderElement.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleInterfaceText.h"
+#include "WebKitAccessibleUtil.h"
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkTable* table)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(table))
+        return nullptr;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(table));
+}
+
+static AXCoreObject* cell(AtkTable* table, guint row, guint column)
+{
+    auto* accTable = core(table);
+    return accTable ? accTable->cellForColumnAndRow(column, row) : nullptr;
+}
+
+static gint cellIndex(AXCoreObject* axCell, AccessibilityTable* axTable)
+{
+    // Calculate the cell's index as if we had a traditional Gtk+ table in
+    // which cells are all direct children of the table, arranged row-first.
+    auto allCells = axTable->cells();
+    AXCoreObject::AccessibilityChildrenVector::iterator position;
+    position = std::find(allCells.begin(), allCells.end(), axCell);
+    if (position == allCells.end())
+        return -1;
+    return position - allCells.begin();
+}
+
+static AccessibilityTableCell* cellAtIndex(AtkTable* table, gint index)
+{
+    AccessibilityObject* accTable = core(table);
+    if (is<AccessibilityTable>(*accTable)) {
+        auto allCells = downcast<AccessibilityTable>(*accTable).cells();
+        if (0 <= index && static_cast<unsigned>(index) < allCells.size())
+            return downcast<AccessibilityTableCell>(allCells[index].get());
+    }
+    return nullptr;
+}
+
+static AtkObject* webkitAccessibleTableRefAt(AtkTable* table, gint row, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    auto* axCell = cell(table, row, column);
+    if (!axCell)
+        return 0;
+
+    auto* cell = axCell->wrapper();
+    if (!cell)
+        return 0;
+
+    // This method transfers full ownership over the returned
+    // AtkObject, so an extra reference is needed here.
+    return ATK_OBJECT(g_object_ref(cell));
+}
+
+static gint webkitAccessibleTableGetIndexAt(AtkTable* table, gint row, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), -1);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1);
+
+    auto* axCell = cell(table, row, column);
+    AccessibilityTable* axTable = downcast<AccessibilityTable>(core(table));
+    return cellIndex(axCell, axTable);
+}
+
+static gint webkitAccessibleTableGetColumnAtIndex(AtkTable* table, gint index)
+{
+    g_return_val_if_fail(ATK_TABLE(table), -1);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1);
+
+    AccessibilityTableCell* axCell = cellAtIndex(table, index);
+    if (axCell) {
+        auto columnRange = axCell->columnIndexRange();
+        return columnRange.first;
+    }
+    return -1;
+}
+
+static gint webkitAccessibleTableGetRowAtIndex(AtkTable* table, gint index)
+{
+    g_return_val_if_fail(ATK_TABLE(table), -1);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), -1);
+
+    AccessibilityTableCell* axCell = cellAtIndex(table, index);
+    if (axCell) {
+        auto rowRange = axCell->rowIndexRange();
+        return rowRange.first;
+    }
+    return -1;
+}
+
+static gint webkitAccessibleTableGetNColumns(AtkTable* table)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AccessibilityObject* accTable = core(table);
+    if (!is<AccessibilityTable>(*accTable))
+        return 0;
+
+    if (int columnCount = downcast<AccessibilityTable>(*accTable).axColumnCount())
+        return columnCount;
+
+    return downcast<AccessibilityTable>(*accTable).columnCount();
+}
+
+static gint webkitAccessibleTableGetNRows(AtkTable* table)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AccessibilityObject* accTable = core(table);
+    if (!is<AccessibilityTable>(*accTable))
+        return 0;
+
+    if (int rowCount = downcast<AccessibilityTable>(*accTable).axRowCount())
+        return rowCount;
+
+    return downcast<AccessibilityTable>(*accTable).rowCount();
+}
+
+static gint webkitAccessibleTableGetColumnExtentAt(AtkTable* table, gint row, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    auto* axCell = cell(table, row, column);
+    if (axCell) {
+        auto columnRange = axCell->columnIndexRange();
+        return columnRange.second;
+    }
+    return 0;
+}
+
+static gint webkitAccessibleTableGetRowExtentAt(AtkTable* table, gint row, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    auto* axCell = cell(table, row, column);
+    if (axCell) {
+        auto rowRange = axCell->rowIndexRange();
+        return rowRange.second;
+    }
+    return 0;
+}
+
+static AtkObject* webkitAccessibleTableGetColumnHeader(AtkTable* table, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AccessibilityObject* accTable = core(table);
+    if (is<AccessibilityTable>(*accTable)) {
+        auto columnHeaders = downcast<AccessibilityTable>(*accTable).columnHeaders();
+
+        for (const auto& columnHeader : columnHeaders) {
+            auto columnRange = columnHeader->columnIndexRange();
+            if (columnRange.first <= static_cast<unsigned>(column) && static_cast<unsigned>(column) < columnRange.first + columnRange.second)
+                return ATK_OBJECT(columnHeader->wrapper());
+        }
+    }
+    return nullptr;
+}
+
+static AtkObject* webkitAccessibleTableGetRowHeader(AtkTable* table, gint row)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AccessibilityObject* accTable = core(table);
+    if (is<AccessibilityTable>(*accTable)) {
+        auto rowHeaders = downcast<AccessibilityTable>(*accTable).rowHeaders();
+
+        for (const auto& rowHeader : rowHeaders) {
+            auto rowRange = rowHeader->rowIndexRange();
+            if (rowRange.first <= static_cast<unsigned>(row) && static_cast<unsigned>(row) < rowRange.first + rowRange.second)
+                return ATK_OBJECT(rowHeader->wrapper());
+        }
+    }
+    return nullptr;
+}
+
+static AtkObject* webkitAccessibleTableGetCaption(AtkTable* table)
+{
+    g_return_val_if_fail(ATK_TABLE(table), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), nullptr);
+
+    AccessibilityObject* accTable = core(table);
+    if (accTable->isAccessibilityRenderObject()) {
+        Node* node = accTable->node();
+        if (is<HTMLTableElement>(node)) {
+            auto caption = downcast<HTMLTableElement>(*node).caption();
+            if (caption)
+                return ATK_OBJECT(AccessibilityObject::firstAccessibleObjectFromNode(caption->renderer()->element())->wrapper());
+        }
+    }
+    return nullptr;
+}
+
+static const gchar* webkitAccessibleTableGetColumnDescription(AtkTable* table, gint column)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AtkObject* columnHeader = atk_table_get_column_header(table, column);
+    if (columnHeader && ATK_IS_TEXT(columnHeader))
+        return atk_text_get_text(ATK_TEXT(columnHeader), 0, -1);
+
+    return 0;
+}
+
+static const gchar* webkitAccessibleTableGetRowDescription(AtkTable* table, gint row)
+{
+    g_return_val_if_fail(ATK_TABLE(table), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(table), 0);
+
+    AtkObject* rowHeader = atk_table_get_row_header(table, row);
+    if (rowHeader && ATK_IS_TEXT(rowHeader))
+        return atk_text_get_text(ATK_TEXT(rowHeader), 0, -1);
+
+    return 0;
+}
+
+void webkitAccessibleTableInterfaceInit(AtkTableIface* iface)
+{
+    iface->ref_at = webkitAccessibleTableRefAt;
+    iface->get_index_at = webkitAccessibleTableGetIndexAt;
+    iface->get_column_at_index = webkitAccessibleTableGetColumnAtIndex;
+    iface->get_row_at_index = webkitAccessibleTableGetRowAtIndex;
+    iface->get_n_columns = webkitAccessibleTableGetNColumns;
+    iface->get_n_rows = webkitAccessibleTableGetNRows;
+    iface->get_column_extent_at = webkitAccessibleTableGetColumnExtentAt;
+    iface->get_row_extent_at = webkitAccessibleTableGetRowExtentAt;
+    iface->get_column_header = webkitAccessibleTableGetColumnHeader;
+    iface->get_row_header = webkitAccessibleTableGetRowHeader;
+    iface->get_caption = webkitAccessibleTableGetCaption;
+    iface->get_column_description = webkitAccessibleTableGetColumnDescription;
+    iface->get_row_description = webkitAccessibleTableGetRowDescription;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceTable.h	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleTableInterfaceInit(AtkTableIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,1270 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceText.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "Document.h"
+#include "Editing.h"
+#include "FontCascade.h"
+#include "FrameView.h"
+#include "HTMLParserIdioms.h"
+#include "HostWindow.h"
+#include "NotImplemented.h"
+#include "Range.h"
+#include "RenderListItem.h"
+#include "RenderListMarker.h"
+#include "RenderText.h"
+#include "TextIterator.h"
+#include "VisibleUnits.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+#include <pal/text/TextEncoding.h>
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+// Text attribute to expose the ARIA 'aria-invalid' attribute. Initially initialized
+// to ATK_TEXT_ATTR_INVALID (which means 'invalid' text attribute'), will later on
+// hold a reference to the custom registered AtkTextAttribute that we will use.
+static AtkTextAttribute atkTextAttributeInvalid = ATK_TEXT_ATTR_INVALID;
+
+static AccessibilityObject* core(AtkText* text)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(text))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(text));
+}
+
+static int baselinePositionForRenderObject(RenderObject* renderObject)
+{
+    // FIXME: This implementation of baselinePosition originates from RenderObject.cpp and was
+    // removed in r70072. The implementation looks incorrect though, because this is not the
+    // baseline of the underlying RenderObject, but of the AccessibilityRenderObject.
+    const FontMetrics& fontMetrics = renderObject->firstLineStyle().metricsOfPrimaryFont();
+    return fontMetrics.ascent() + (renderObject->firstLineStyle().computedLineHeight() - fontMetrics.height()) / 2;
+}
+
+static AtkAttributeSet* getAttributeSetForAccessibilityObject(const AccessibilityObject* object)
+{
+    if (!object->isAccessibilityRenderObject())
+        return 0;
+
+    RenderObject* renderer = object->renderer();
+    auto* style = &renderer->style();
+
+    AtkAttributeSet* result = nullptr;
+    GUniquePtr<gchar> buffer(g_strdup_printf("%i", style->computedFontPixelSize()));
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_SIZE), buffer.get());
+
+    Color bgColor = style->visitedDependentColor(CSSPropertyBackgroundColor);
+    if (bgColor.isValid()) {
+        auto [r, g, b, a] = bgColor.toColorTypeLossy<SRGBA<uint8_t>>().resolved();
+        buffer.reset(g_strdup_printf("%i,%i,%i", r, g, b));
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_BG_COLOR), buffer.get());
+    }
+
+    Color fgColor = style->visitedDependentColor(CSSPropertyColor);
+    if (fgColor.isValid()) {
+        auto [r, g, b, a] = fgColor.toColorTypeLossy<SRGBA<uint8_t>>().resolved();
+        buffer.reset(g_strdup_printf("%i,%i,%i", r, g, b));
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FG_COLOR), buffer.get());
+    }
+
+    int baselinePosition;
+    bool includeRise = true;
+    switch (style->verticalAlign()) {
+    case VerticalAlign::Sub:
+        baselinePosition = -1 * baselinePositionForRenderObject(renderer);
+        break;
+    case VerticalAlign::Super:
+        baselinePosition = baselinePositionForRenderObject(renderer);
+        break;
+    case VerticalAlign::Baseline:
+        baselinePosition = 0;
+        break;
+    default:
+        includeRise = false;
+        break;
+    }
+
+    if (includeRise) {
+        buffer.reset(g_strdup_printf("%i", baselinePosition));
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_RISE), buffer.get());
+    }
+
+    if (!style->textIndent().isUndefined()) {
+        int indentation = valueForLength(style->textIndent(), object->size().width());
+        buffer.reset(g_strdup_printf("%i", indentation));
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INDENT), buffer.get());
+    }
+
+    String fontFamilyName = style->fontCascade().firstFamily();
+    if (fontFamilyName.left(8) == "-webkit-"_s)
+        fontFamilyName = fontFamilyName.substring(8);
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_FAMILY_NAME), fontFamilyName.utf8().data());
+
+    int fontWeight = static_cast<float>(style->fontCascade().weight());
+    if (fontWeight > 0) {
+        buffer.reset(g_strdup_printf("%i", fontWeight));
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_WEIGHT), buffer.get());
+    }
+
+    switch (style->textAlign()) {
+    case TextAlignMode::Start:
+    case TextAlignMode::End:
+        break;
+    case TextAlignMode::Left:
+    case TextAlignMode::WebKitLeft:
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "left");
+        break;
+    case TextAlignMode::Right:
+    case TextAlignMode::WebKitRight:
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "right");
+        break;
+    case TextAlignMode::Center:
+    case TextAlignMode::WebKitCenter:
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "center");
+        break;
+    case TextAlignMode::Justify:
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_JUSTIFICATION), "fill");
+    }
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_UNDERLINE), (style->textDecorationLine() & TextDecorationLine::Underline) ? "single" : "none");
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STYLE), style->fontCascade().italic() ? "italic" : "normal");
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_STRIKETHROUGH), (style->textDecorationLine() & TextDecorationLine::LineThrough) ? "true" : "false");
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_INVISIBLE), (style->visibility() == Visibility::Hidden) ? "true" : "false");
+
+    result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_EDITABLE), object->canSetValueAttribute() ? "true" : "false");
+
+    String language = object->language();
+    if (!language.isEmpty())
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(ATK_TEXT_ATTR_LANGUAGE), language.utf8().data());
+
+    String invalidStatus = object->invalidStatus();
+    if (invalidStatus != "false"_s) {
+        // Register the custom attribute for 'aria-invalid' if not done yet.
+        if (atkTextAttributeInvalid == ATK_TEXT_ATTR_INVALID)
+            atkTextAttributeInvalid = atk_text_attribute_register("invalid");
+
+        result = addToAtkAttributeSet(result, atk_text_attribute_get_name(atkTextAttributeInvalid), invalidStatus.utf8().data());
+    }
+
+    return result;
+}
+
+static gint compareAttribute(const AtkAttribute* a, const AtkAttribute* b)
+{
+    return g_strcmp0(a->name, b->name) || g_strcmp0(a->value, b->value);
+}
+
+// Returns an AtkAttributeSet with the elements of attributeSet1 which
+// are either not present or different in attributeSet2. Neither
+// attributeSet1 nor attributeSet2 should be used after calling this.
+static AtkAttributeSet* attributeSetDifference(AtkAttributeSet* attributeSet1, AtkAttributeSet* attributeSet2)
+{
+    if (!attributeSet2)
+        return attributeSet1;
+
+    AtkAttributeSet* currentSet = attributeSet1;
+    AtkAttributeSet* found;
+    AtkAttributeSet* toDelete = nullptr;
+
+    while (currentSet) {
+        found = g_slist_find_custom(attributeSet2, currentSet->data, (GCompareFunc)compareAttribute);
+        if (found) {
+            AtkAttributeSet* nextSet = currentSet->next;
+            toDelete = g_slist_prepend(toDelete, currentSet->data);
+            attributeSet1 = g_slist_delete_link(attributeSet1, currentSet);
+            currentSet = nextSet;
+        } else
+            currentSet = currentSet->next;
+    }
+
+    atk_attribute_set_free(attributeSet2);
+    atk_attribute_set_free(toDelete);
+    return attributeSet1;
+}
+
+static gchar* webkitAccessibleTextGetText(AtkText*, gint startOffset, gint endOffset);
+
+static guint accessibilityObjectLength(const AccessibilityObject* object)
+{
+    // Non render objects are not taken into account
+    if (!object->isAccessibilityRenderObject())
+        return 0;
+
+    // For those objects implementing the AtkText interface we use the
+    // well known API to always get the text in a consistent way
+    auto* atkObj = ATK_OBJECT(object->wrapper());
+    if (ATK_IS_TEXT(atkObj)) {
+        GUniquePtr<gchar> text(webkitAccessibleTextGetText(ATK_TEXT(atkObj), 0, -1));
+        return g_utf8_strlen(text.get(), -1);
+    }
+
+    // Even if we don't expose list markers to Assistive
+    // Technologies, we need to have a way to measure their length
+    // for those cases when it's needed to take it into account
+    // separately (as in getAccessibilityObjectForOffset)
+    if (auto renderer = object->renderer(); is<RenderListMarker>(renderer))
+        return downcast<RenderListMarker>(*renderer).textWithSuffix().length();
+
+    return 0;
+}
+
+static const AccessibilityObject* getAccessibilityObjectForOffset(const AccessibilityObject* object, guint offset, gint* startOffset, gint* endOffset)
+{
+    const AccessibilityObject* result;
+    guint length = accessibilityObjectLength(object);
+    if (length > offset) {
+        *startOffset = 0;
+        *endOffset = length;
+        result = object;
+    } else {
+        *startOffset = -1;
+        *endOffset = -1;
+        result = 0;
+    }
+
+    if (!object->firstChild())
+        return result;
+
+    AccessibilityObject* child = object->firstChild();
+    guint currentOffset = 0;
+    guint childPosition = 0;
+    while (child && currentOffset <= offset) {
+        guint childLength = accessibilityObjectLength(child);
+        currentOffset = childLength + childPosition;
+        if (currentOffset > offset) {
+            gint childStartOffset;
+            gint childEndOffset;
+            const AccessibilityObject* grandChild = getAccessibilityObjectForOffset(child, offset-childPosition,  &childStartOffset, &childEndOffset);
+            if (childStartOffset >= 0) {
+                *startOffset = childStartOffset + childPosition;
+                *endOffset = childEndOffset + childPosition;
+                result = grandChild;
+            }
+        } else {
+            childPosition += childLength;
+            child = child->nextSibling();
+        }
+    }
+    return result;
+}
+
+static AtkAttributeSet* getRunAttributesFromAccessibilityObject(const AccessibilityObject* element, gint offset, gint* startOffset, gint* endOffset)
+{
+    const AccessibilityObject* child = getAccessibilityObjectForOffset(element, offset, startOffset, endOffset);
+    if (!child) {
+        *startOffset = -1;
+        *endOffset = -1;
+        return 0;
+    }
+
+    AtkAttributeSet* defaultAttributes = getAttributeSetForAccessibilityObject(element);
+    AtkAttributeSet* childAttributes = getAttributeSetForAccessibilityObject(child);
+
+    return attributeSetDifference(childAttributes, defaultAttributes);
+}
+
+static IntRect textExtents(AtkText* text, gint startOffset, gint length, AtkCoordType coords)
+{
+    GUniquePtr<char> textContent(webkitAccessibleTextGetText(text, startOffset, -1));
+    gint textLength = g_utf8_strlen(textContent.get(), -1);
+
+    // The first case (endOffset of -1) should work, but seems broken for all Gtk+ apps.
+    gint rangeLength = length;
+    if (rangeLength < 0 || rangeLength > textLength)
+        rangeLength = textLength;
+    AccessibilityObject* coreObject = core(text);
+
+    IntRect extents = coreObject->doAXBoundsForRange(PlainTextRange(startOffset, rangeLength));
+    switch (coords) {
+    case ATK_XY_SCREEN:
+        if (Document* document = coreObject->document())
+            extents = document->view()->contentsToScreen(extents);
+        break;
+    case ATK_XY_WINDOW:
+        // No-op
+        break;
+#if ATK_CHECK_VERSION(2, 30, 0)
+    case ATK_XY_PARENT:
+        RELEASE_ASSERT_NOT_REACHED();
+#endif
+    }
+
+    return extents;
+}
+
+static int offsetAdjustmentForListItem(const AXCoreObject* object)
+{
+    // We need to adjust the offsets for the list item marker in
+    // Left-To-Right text, since we expose it together with the text.
+    RenderObject* renderer = object->renderer();
+    if (is<RenderListItem>(renderer) && renderer->style().direction() == TextDirection::LTR)
+        return downcast<RenderListItem>(*renderer).markerTextWithSuffix().length();
+
+    return 0;
+}
+
+static int webCoreOffsetToAtkOffset(const AXCoreObject* object, int offset)
+{
+    if (!object->isListItem())
+        return offset;
+
+    return offset + offsetAdjustmentForListItem(object);
+}
+
+static int atkOffsetToWebCoreOffset(AtkText* text, int offset)
+{
+    AccessibilityObject* coreObject = core(text);
+    if (!coreObject || !coreObject->isListItem())
+        return offset;
+
+    return offset - offsetAdjustmentForListItem(coreObject);
+}
+
+static Node* getNodeForAccessibilityObject(AccessibilityObject* coreObject)
+{
+    if (!coreObject->isNativeTextControl())
+        return coreObject->node();
+
+    // For text controls, we get the first visible position on it (which will
+    // belong to its inner element, unreachable from the DOM) and return its
+    // parent node, so we have a "bounding node" for the accessibility object.
+    VisiblePosition positionInTextControlInnerElement = coreObject->visiblePositionForIndex(0, true);
+    Node* innerMostNode = positionInTextControlInnerElement.deepEquivalent().anchorNode();
+    if (!innerMostNode)
+        return 0;
+
+    return innerMostNode->parentNode();
+}
+
+static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, VisibleSelection& selection, gint& startOffset, gint& endOffset)
+{
+    // Default values, unless the contrary is proved.
+    startOffset = 0;
+    endOffset = 0;
+
+    Node* node = getNodeForAccessibilityObject(coreObject);
+    if (!node)
+        return;
+
+    if (selection.isNone())
+        return;
+
+    // We need to limit our search to positions that fall inside the domain of the current object.
+    Position firstValidPosition = firstPositionInOrBeforeNode(node->firstDescendant());
+    Position lastValidPosition = lastPositionInOrAfterNode(node->lastDescendant());
+
+    // Find the proper range for the selection that falls inside the object.
+    auto nodeRangeStart = std::max(selection.start(), firstValidPosition);
+    auto nodeRangeEnd = std::min(selection.end(), lastValidPosition);
+
+    // Calculate position of the selected range inside the object.
+    Position parentFirstPosition = firstPositionInOrBeforeNode(node);
+    auto rangeInParent = *makeSimpleRange(parentFirstPosition, nodeRangeStart);
+
+    // Set values for start offsets and calculate initial range length.
+    // These values might be adjusted later to cover special cases.
+    startOffset = webCoreOffsetToAtkOffset(coreObject, characterCount(rangeInParent, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions));
+    auto nodeRange = *makeSimpleRange(nodeRangeStart, nodeRangeEnd);
+    int rangeLength = characterCount(nodeRange, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
+
+    // Special cases that are only relevant when working with *_END boundaries.
+    if (selection.affinity() == Affinity::Upstream) {
+        VisiblePosition visibleStart(nodeRangeStart, Affinity::Upstream);
+        VisiblePosition visibleEnd(nodeRangeEnd, Affinity::Upstream);
+
+        // We need to adjust offsets when finding wrapped lines so the position at the end
+        // of the line is properly taking into account when calculating the offsets.
+        if (isEndOfLine(visibleStart) && !lineBreakExistsAtVisiblePosition(visibleStart)) {
+            if (isStartOfLine(visibleStart.next()))
+                rangeLength++;
+
+            if (!isEndOfBlock(visibleStart))
+                startOffset = std::max(startOffset - 1, 0);
+        }
+
+        if (isEndOfLine(visibleEnd) && !lineBreakExistsAtVisiblePosition(visibleEnd) && !isEndOfBlock(visibleEnd))
+            rangeLength--;
+    }
+
+    endOffset = std::min(startOffset + rangeLength, static_cast<int>(accessibilityObjectLength(coreObject)));
+}
+
+static gchar* webkitAccessibleTextGetText(AtkText* text, gint startOffset, gint endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    AccessibilityObject* coreObject = core(text);
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    if (coreObject->roleValue() == AccessibilityRole::ColorWell) {
+        auto color = convertColor<SRGBA<float>>(coreObject->colorValue()).resolved();
+        return g_strdup_printf("rgb %7.5f %7.5f %7.5f 1", color.red, color.green, color.blue);
+    }
+#endif
+
+    String ret;
+    if (coreObject->isTextControl())
+        ret = coreObject->doAXStringForRange(PlainTextRange(0, endOffset));
+    else {
+        ret = coreObject->stringValue();
+        if (!ret)
+            ret = coreObject->textUnderElement(AccessibilityTextUnderElementMode(AccessibilityTextUnderElementMode::TextUnderElementModeIncludeAllChildren));
+    }
+
+    // Prefix a item number/bullet if needed
+    int actualEndOffset = endOffset == -1 ? ret.length() : endOffset;
+    if (coreObject->roleValue() == AccessibilityRole::ListItem) {
+        RenderObject* objRenderer = coreObject->renderer();
+        if (is<RenderListItem>(objRenderer)) {
+            String markerText = downcast<RenderListItem>(*objRenderer).markerTextWithSuffix().toString();
+            ret = objRenderer->style().direction() == TextDirection::LTR ? markerText + ret : ret + markerText;
+            if (endOffset == -1)
+                actualEndOffset = ret.length() + markerText.length();
+        }
+    }
+
+    ret = ret.substring(startOffset, actualEndOffset - startOffset);
+    return g_strdup(ret.utf8().data());
+}
+
+enum GetTextRelativePosition {
+    GetTextPositionAt,
+    GetTextPositionBefore,
+    GetTextPositionAfter
+};
+
+// Convenience function to be used in early returns.
+static char* emptyTextSelectionAtOffset(int offset, int* startOffset, int* endOffset)
+{
+    *startOffset = offset;
+    *endOffset = offset;
+    return g_strdup("");
+}
+
+static char* webkitAccessibleTextGetChar(AtkText* text, int offset, GetTextRelativePosition textPosition, int* startOffset, int* endOffset)
+{
+    int actualOffset = offset;
+    if (textPosition == GetTextPositionBefore)
+        actualOffset--;
+    else if (textPosition == GetTextPositionAfter)
+        actualOffset++;
+
+    GUniquePtr<char> textData(webkitAccessibleTextGetText(text, 0, -1));
+    int textLength = g_utf8_strlen(textData.get(), -1);
+
+    *startOffset = std::max(0, actualOffset);
+    *startOffset = std::min(*startOffset, textLength);
+
+    *endOffset = std::max(0, actualOffset + 1);
+    *endOffset = std::min(*endOffset, textLength);
+
+    if (*startOffset == *endOffset)
+        return g_strdup("");
+
+    return g_utf8_substring(textData.get(), *startOffset, *endOffset);
+}
+
+static VisiblePosition nextWordStartPosition(const VisiblePosition &position)
+{
+    VisiblePosition positionAfterCurrentWord = nextWordPosition(position);
+
+    // In order to skip spaces when moving right, we advance one word further
+    // and then move one word back. This will put us at the beginning of the
+    // word following.
+    VisiblePosition positionAfterSpacingAndFollowingWord = nextWordPosition(positionAfterCurrentWord);
+
+    if (positionAfterSpacingAndFollowingWord != positionAfterCurrentWord)
+        positionAfterCurrentWord = previousWordPosition(positionAfterSpacingAndFollowingWord);
+
+    bool movingBackwardsMovedPositionToStartOfCurrentWord = positionAfterCurrentWord == previousWordPosition(nextWordPosition(position));
+    if (movingBackwardsMovedPositionToStartOfCurrentWord)
+        positionAfterCurrentWord = positionAfterSpacingAndFollowingWord;
+
+    return positionAfterCurrentWord;
+}
+
+static VisiblePosition previousWordEndPosition(const VisiblePosition &position)
+{
+    // We move forward and then backward to position ourselves at the beginning
+    // of the current word for this boundary, making the most of the semantics
+    // of previousWordPosition() and nextWordPosition().
+    VisiblePosition positionAtStartOfCurrentWord = previousWordPosition(nextWordPosition(position));
+    VisiblePosition positionAtPreviousWord = previousWordPosition(position);
+
+    // Need to consider special cases (punctuation) when we are in the last word of a sentence.
+    if (isStartOfWord(position) && positionAtPreviousWord != position && positionAtPreviousWord == positionAtStartOfCurrentWord)
+        return nextWordPosition(positionAtStartOfCurrentWord);
+
+    // In order to skip spaces when moving left, we advance one word backwards
+    // and then move one word forward. This will put us at the beginning of
+    // the word following.
+    VisiblePosition positionBeforeSpacingAndPreceedingWord = previousWordPosition(positionAtStartOfCurrentWord);
+
+    if (positionBeforeSpacingAndPreceedingWord != positionAtStartOfCurrentWord)
+        positionAtStartOfCurrentWord = nextWordPosition(positionBeforeSpacingAndPreceedingWord);
+
+    bool movingForwardMovedPositionToEndOfCurrentWord = nextWordPosition(positionAtStartOfCurrentWord) == previousWordPosition(nextWordPosition(position));
+    if (movingForwardMovedPositionToEndOfCurrentWord)
+        positionAtStartOfCurrentWord = positionBeforeSpacingAndPreceedingWord;
+
+    return positionAtStartOfCurrentWord;
+}
+
+static VisibleSelection wordAtPositionForAtkBoundary(const AccessibilityObject* /*coreObject*/, const VisiblePosition& position, AtkTextBoundary boundaryType)
+{
+    VisiblePosition startPosition;
+    VisiblePosition endPosition;
+
+    switch (boundaryType) {
+    case ATK_TEXT_BOUNDARY_WORD_START:
+        // isStartOfWord() returns true both when at the beginning of a "real" word
+        // as when at the beginning of a whitespace range between two "real" words,
+        // since that whitespace is considered a "word" as well. And in case we are
+        // already at the beginning of a "real" word we do not need to look backwards.
+        if (isStartOfWord(position) && deprecatedIsEditingWhitespace(position.characterBefore()))
+            startPosition = position;
+        else
+            startPosition = previousWordPosition(position);
+        endPosition = nextWordStartPosition(startPosition);
+
+        // We need to make sure that we look for the word in the current line when
+        // we are at the beginning of a new line, and not look into the previous one
+        // at all, which might happen when lines belong to different nodes.
+        if (isStartOfLine(position) && isStartOfLine(endPosition)) {
+            startPosition = endPosition;
+            endPosition = nextWordStartPosition(startPosition);
+        }
+        break;
+
+    case ATK_TEXT_BOUNDARY_WORD_END:
+        startPosition = previousWordEndPosition(position);
+        endPosition = nextWordPosition(startPosition);
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    VisibleSelection selectedWord(startPosition, endPosition);
+
+    // We mark the selection as 'upstream' so we can use that information later,
+    // when finding the actual offsets in getSelectionOffsetsForObject().
+    if (boundaryType == ATK_TEXT_BOUNDARY_WORD_END)
+        selectedWord.setAffinity(Affinity::Upstream);
+
+    return selectedWord;
+}
+
+static int numberOfReplacedElementsBeforeOffset(AtkText* text, unsigned offset)
+{
+    GUniquePtr<char> textForObject(webkitAccessibleTextGetText(text, 0, offset));
+    String textBeforeOffset = String::fromUTF8(textForObject.get());
+
+    int count = 0;
+    size_t index = textBeforeOffset.find(objectReplacementCharacter, 0);
+    while (index < offset && index != notFound) {
+        index = textBeforeOffset.find(objectReplacementCharacter, index + 1);
+        count++;
+    }
+    return count;
+}
+
+static char* webkitAccessibleTextWordForBoundary(AtkText* text, int offset, AtkTextBoundary boundaryType, GetTextRelativePosition textPosition, int* startOffset, int* endOffset)
+{
+    AccessibilityObject* coreObject = core(text);
+    Document* document = coreObject->document();
+    if (!document)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    Node* node = getNodeForAccessibilityObject(coreObject);
+    if (!node)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    int actualOffset = atkOffsetToWebCoreOffset(text, offset);
+
+    // Besides of the usual conversion from ATK offsets to WebCore offsets,
+    // we need to consider the potential embedded objects that might have been
+    // inserted in the text exposed through AtkText when calculating the offset.
+    actualOffset -= numberOfReplacedElementsBeforeOffset(text, actualOffset);
+
+    VisiblePosition caretPosition = coreObject->visiblePositionForIndex(actualOffset);
+    VisibleSelection currentWord = wordAtPositionForAtkBoundary(coreObject, caretPosition, boundaryType);
+
+    // Take into account other relative positions, if needed, by
+    // calculating the new position that we would need to consider.
+    VisiblePosition newPosition = caretPosition;
+    switch (textPosition) {
+    case GetTextPositionAt:
+        break;
+
+    case GetTextPositionBefore:
+        // Early return if asking for the previous word while already at the beginning.
+        if (isFirstVisiblePositionInNode(currentWord.visibleStart(), node))
+            return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+        if (isStartOfLine(currentWord.end()))
+            newPosition = currentWord.visibleStart().previous();
+        else
+            newPosition = startOfWord(currentWord.start(), LeftWordIfOnBoundary);
+        break;
+
+    case GetTextPositionAfter:
+        // Early return if asking for the following word while already at the end.
+        if (isLastVisiblePositionInNode(currentWord.visibleEnd(), node))
+            return emptyTextSelectionAtOffset(accessibilityObjectLength(coreObject), startOffset, endOffset);
+
+        if (isEndOfLine(currentWord.end()))
+            newPosition = currentWord.visibleEnd().next();
+        else
+            newPosition = endOfWord(currentWord.end(), RightWordIfOnBoundary);
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // Determine the relevant word we are actually interested in
+    // and calculate the ATK offsets for it, then return everything.
+    VisibleSelection selectedWord = newPosition != caretPosition ? wordAtPositionForAtkBoundary(coreObject, newPosition, boundaryType) : currentWord;
+    getSelectionOffsetsForObject(coreObject, selectedWord, *startOffset, *endOffset);
+    return webkitAccessibleTextGetText(text, *startOffset, *endOffset);
+}
+
+static bool isSentenceBoundary(const VisiblePosition &pos)
+{
+    if (pos.isNull())
+        return false;
+
+    // It's definitely a sentence boundary if there's nothing before.
+    if (pos.previous().isNull())
+        return true;
+
+    // We go backwards and forward to make sure about this.
+    VisiblePosition startOfPreviousSentence = startOfSentence(pos);
+    return startOfPreviousSentence.isNotNull() && pos == endOfSentence(startOfPreviousSentence);
+}
+
+static bool isWhiteSpaceBetweenSentences(const VisiblePosition& position)
+{
+    if (position.isNull())
+        return false;
+
+    if (!deprecatedIsEditingWhitespace(position.characterAfter()))
+        return false;
+
+    auto start = startOfWord(position, RightWordIfOnBoundary);
+    auto end = endOfWord(start, RightWordIfOnBoundary);
+    if (!isSentenceBoundary(start) && !isSentenceBoundary(end))
+        return false;
+
+    auto range = makeSimpleRange(start, end);
+    return range && contains<ComposedTree>(*range, makeBoundaryPoint(position));
+}
+
+static VisibleSelection sentenceAtPositionForAtkBoundary(const AccessibilityObject*, const VisiblePosition& position, AtkTextBoundary boundaryType)
+{
+    VisiblePosition startPosition;
+    VisiblePosition endPosition;
+
+    bool isAtStartOfSentenceForEndBoundary = isWhiteSpaceBetweenSentences(position) || isSentenceBoundary(position);
+    if (boundaryType == ATK_TEXT_BOUNDARY_SENTENCE_START || !isAtStartOfSentenceForEndBoundary) {
+        startPosition = isSentenceBoundary(position) ? position : startOfSentence(position);
+        // startOfSentence might stop at a linebreak in the HTML source code,
+        // but we don't want to stop there yet, so keep going.
+        while (!isSentenceBoundary(startPosition) && isHTMLLineBreak(startPosition.characterBefore()))
+            startPosition = startOfSentence(startPosition);
+
+        endPosition = endOfSentence(startPosition);
+    }
+
+    if (boundaryType == ATK_TEXT_BOUNDARY_SENTENCE_END) {
+        if (isAtStartOfSentenceForEndBoundary) {
+            startPosition = position;
+            endPosition = endOfSentence(endOfWord(position, RightWordIfOnBoundary));
+        }
+
+        // startOfSentence returns a position after any white space previous to
+        // the sentence, so we might need to adjust that offset for this boundary.
+        if (deprecatedIsEditingWhitespace(startPosition.characterBefore()))
+            startPosition = startOfWord(startPosition, LeftWordIfOnBoundary);
+
+        // endOfSentence returns a position after any white space after the
+        // sentence, so we might need to adjust that offset for this boundary.
+        if (deprecatedIsEditingWhitespace(endPosition.characterBefore()))
+            endPosition = startOfWord(endPosition, LeftWordIfOnBoundary);
+
+        // Finally, do some additional adjustments that might be needed if
+        // positions are at the start or the end of a line.
+        if (isStartOfLine(startPosition) && !isStartOfBlock(startPosition))
+            startPosition = startPosition.previous();
+        if (isStartOfLine(endPosition) && !isStartOfBlock(endPosition))
+            endPosition = endPosition.previous();
+    }
+
+    VisibleSelection selectedSentence(startPosition, endPosition);
+
+    // We mark the selection as 'upstream' so we can use that information later,
+    // when finding the actual offsets in getSelectionOffsetsForObject().
+    if (boundaryType == ATK_TEXT_BOUNDARY_SENTENCE_END)
+        selectedSentence.setAffinity(Affinity::Upstream);
+
+    return selectedSentence;
+}
+
+static char* webkitAccessibleTextSentenceForBoundary(AtkText* text, int offset, AtkTextBoundary boundaryType, GetTextRelativePosition textPosition, int* startOffset, int* endOffset)
+{
+    AccessibilityObject* coreObject = core(text);
+    Document* document = coreObject->document();
+    if (!document)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    Node* node = getNodeForAccessibilityObject(coreObject);
+    if (!node)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    int actualOffset = atkOffsetToWebCoreOffset(text, offset);
+
+    // Besides of the usual conversion from ATK offsets to WebCore offsets,
+    // we need to consider the potential embedded objects that might have been
+    // inserted in the text exposed through AtkText when calculating the offset.
+    actualOffset -= numberOfReplacedElementsBeforeOffset(text, actualOffset);
+
+    VisiblePosition caretPosition = coreObject->visiblePositionForIndex(actualOffset);
+    VisibleSelection currentSentence = sentenceAtPositionForAtkBoundary(coreObject, caretPosition, boundaryType);
+
+    // Take into account other relative positions, if needed, by
+    // calculating the new position that we would need to consider.
+    VisiblePosition newPosition = caretPosition;
+    switch (textPosition) {
+    case GetTextPositionAt:
+        break;
+
+    case GetTextPositionBefore:
+        // Early return if asking for the previous sentence while already at the beginning.
+        if (isFirstVisiblePositionInNode(currentSentence.visibleStart(), node))
+            return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+        newPosition = currentSentence.visibleStart().previous();
+        break;
+
+    case GetTextPositionAfter:
+        // Early return if asking for the following word while already at the end.
+        if (isLastVisiblePositionInNode(currentSentence.visibleEnd(), node))
+            return emptyTextSelectionAtOffset(accessibilityObjectLength(coreObject), startOffset, endOffset);
+        newPosition = currentSentence.visibleEnd().next();
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // Determine the relevant sentence we are actually interested in
+    // and calculate the ATK offsets for it, then return everything.
+    VisibleSelection selectedSentence = newPosition != caretPosition ? sentenceAtPositionForAtkBoundary(coreObject, newPosition, boundaryType) : currentSentence;
+    getSelectionOffsetsForObject(coreObject, selectedSentence, *startOffset, *endOffset);
+    return webkitAccessibleTextGetText(text, *startOffset, *endOffset);
+}
+
+static VisibleSelection lineAtPositionForAtkBoundary(const AccessibilityObject* coreObject, const VisiblePosition& position, AtkTextBoundary boundaryType)
+{
+    UNUSED_PARAM(coreObject);
+    VisiblePosition startPosition;
+    VisiblePosition endPosition;
+
+    switch (boundaryType) {
+    case ATK_TEXT_BOUNDARY_LINE_START:
+        startPosition = isStartOfLine(position) ? position : logicalStartOfLine(position);
+        endPosition = logicalEndOfLine(position);
+
+        // In addition to checking that we are not at the end of a block, we need
+        // to check that endPosition has not UPSTREAM affinity, since that would
+        // cause trouble inside of text controls (we would be advancing too much).
+        if (!isEndOfBlock(endPosition) && endPosition.affinity() != Affinity::Upstream)
+            endPosition = endPosition.next();
+        break;
+
+    case ATK_TEXT_BOUNDARY_LINE_END:
+        startPosition = isEndOfLine(position) ? position : logicalStartOfLine(position);
+        if (!isStartOfBlock(startPosition))
+            startPosition = startPosition.previous();
+        endPosition = logicalEndOfLine(position);
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    VisibleSelection selectedLine(startPosition, endPosition);
+
+    // We mark the selection as 'upstream' so we can use that information later,
+    // when finding the actual offsets in getSelectionOffsetsForObject().
+    if (boundaryType == ATK_TEXT_BOUNDARY_LINE_END)
+        selectedLine.setAffinity(Affinity::Upstream);
+
+    return selectedLine;
+}
+
+static char* webkitAccessibleTextLineForBoundary(AtkText* text, int offset, AtkTextBoundary boundaryType, GetTextRelativePosition textPosition, int* startOffset, int* endOffset)
+{
+    AccessibilityObject* coreObject = core(text);
+    Document* document = coreObject->document();
+    if (!document)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    Node* node = getNodeForAccessibilityObject(coreObject);
+    if (!node)
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    int actualOffset = atkOffsetToWebCoreOffset(text, offset);
+
+    // Besides the usual conversion from ATK offsets to WebCore offsets,
+    // we need to consider the potential embedded objects that might have been
+    // inserted in the text exposed through AtkText when calculating the offset.
+    actualOffset -= numberOfReplacedElementsBeforeOffset(text, actualOffset);
+
+    VisiblePosition caretPosition = coreObject->visiblePositionForIndex(actualOffset);
+    VisibleSelection currentLine = lineAtPositionForAtkBoundary(coreObject, caretPosition, boundaryType);
+
+    // Take into account other relative positions, if needed, by
+    // calculating the new position that we would need to consider.
+    VisiblePosition newPosition = caretPosition;
+    switch (textPosition) {
+    case GetTextPositionAt:
+        // No need to do additional work if we are using the "at" position, we just
+        // explicitly list this case option to catch invalid values in the default case.
+        break;
+
+    case GetTextPositionBefore:
+        // Early return if asking for the previous line while already at the beginning.
+        if (isFirstVisiblePositionInNode(currentLine.visibleStart(), node))
+            return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+        newPosition = currentLine.visibleStart().previous();
+        break;
+
+    case GetTextPositionAfter:
+        // Early return if asking for the following word while already at the end.
+        if (isLastVisiblePositionInNode(currentLine.visibleEnd(), node))
+            return emptyTextSelectionAtOffset(accessibilityObjectLength(coreObject), startOffset, endOffset);
+        newPosition = currentLine.visibleEnd().next();
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // Determine the relevant line we are actually interested in
+    // and calculate the ATK offsets for it, then return everything.
+    VisibleSelection selectedLine = newPosition != caretPosition ? lineAtPositionForAtkBoundary(coreObject, newPosition, boundaryType) : currentLine;
+    getSelectionOffsetsForObject(coreObject, selectedLine, *startOffset, *endOffset);
+
+    // We might need to adjust the start or end offset to include the list item marker,
+    // if present, when printing the first or the last full line for a list item.
+    RenderObject* renderer = coreObject->renderer();
+    if (renderer->isListItem()) {
+        // For Left-to-Right, the list item marker is at the beginning of the exposed text.
+        if (renderer->style().direction() == TextDirection::LTR && isFirstVisiblePositionInNode(selectedLine.visibleStart(), node))
+            *startOffset = 0;
+
+        // For Right-to-Left, the list item marker is at the end of the exposed text.
+        if (renderer->style().direction() == TextDirection::RTL && isLastVisiblePositionInNode(selectedLine.visibleEnd(), node))
+            *endOffset = accessibilityObjectLength(coreObject);
+    }
+
+    return webkitAccessibleTextGetText(text, *startOffset, *endOffset);
+}
+
+static gchar* webkitAccessibleTextGetTextForOffset(AtkText* text, gint offset, AtkTextBoundary boundaryType, GetTextRelativePosition textPosition, gint* startOffset, gint* endOffset)
+{
+    AccessibilityObject* coreObject = core(text);
+    if (!coreObject || !coreObject->isAccessibilityRenderObject())
+        return emptyTextSelectionAtOffset(0, startOffset, endOffset);
+
+    switch (boundaryType) {
+    case ATK_TEXT_BOUNDARY_CHAR:
+        return webkitAccessibleTextGetChar(text, offset, textPosition, startOffset, endOffset);
+
+    case ATK_TEXT_BOUNDARY_WORD_START:
+    case ATK_TEXT_BOUNDARY_WORD_END:
+        return webkitAccessibleTextWordForBoundary(text, offset, boundaryType, textPosition, startOffset, endOffset);
+
+    case ATK_TEXT_BOUNDARY_LINE_START:
+    case ATK_TEXT_BOUNDARY_LINE_END:
+        return webkitAccessibleTextLineForBoundary(text, offset, boundaryType, textPosition, startOffset, endOffset);
+
+    case ATK_TEXT_BOUNDARY_SENTENCE_START:
+    case ATK_TEXT_BOUNDARY_SENTENCE_END:
+        return webkitAccessibleTextSentenceForBoundary(text, offset, boundaryType, textPosition, startOffset, endOffset);
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    // This should never be reached.
+    return 0;
+}
+
+static gchar* webkitAccessibleTextGetTextAfterOffset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    return webkitAccessibleTextGetTextForOffset(text, offset, boundaryType, GetTextPositionAfter, startOffset, endOffset);
+}
+
+static gchar* webkitAccessibleTextGetTextAtOffset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    return webkitAccessibleTextGetTextForOffset(text, offset, boundaryType, GetTextPositionAt, startOffset, endOffset);
+}
+
+static gchar* webkitAccessibleTextGetTextBeforeOffset(AtkText* text, gint offset, AtkTextBoundary boundaryType, gint* startOffset, gint* endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    return webkitAccessibleTextGetTextForOffset(text, offset, boundaryType, GetTextPositionBefore, startOffset, endOffset);
+}
+
+static gunichar webkitAccessibleTextGetCharacterAtOffset(AtkText* text, gint)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    notImplemented();
+    return 0;
+}
+
+static gint webkitAccessibleTextGetCaretOffset(AtkText* text)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    // coreObject is the unignored object whose offset the caller is requesting.
+    // focusedObject is the object with the caret. It is likely ignored -- unless it's a link.
+    AXCoreObject* coreObject = core(text);
+    if (!coreObject->isAccessibilityRenderObject())
+        return 0;
+
+    // We need to make sure we pass a valid object as reference.
+    if (coreObject->accessibilityIsIgnored())
+        coreObject = coreObject->parentObjectUnignored();
+    if (!coreObject)
+        return 0;
+
+    int offset;
+    if (!objectFocusedAndCaretOffsetUnignored(coreObject, offset))
+        return 0;
+
+    return webCoreOffsetToAtkOffset(coreObject, offset);
+}
+
+static AtkAttributeSet* webkitAccessibleTextGetRunAttributes(AtkText* text, gint offset, gint* startOffset, gint* endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    AccessibilityObject* coreObject = core(text);
+    AtkAttributeSet* result;
+
+    if (!coreObject) {
+        *startOffset = 0;
+        *endOffset = atk_text_get_character_count(text);
+        return 0;
+    }
+
+    if (offset == -1)
+        offset = atk_text_get_caret_offset(text);
+
+    result = getRunAttributesFromAccessibilityObject(coreObject, offset, startOffset, endOffset);
+
+    if (*startOffset < 0) {
+        *startOffset = offset;
+        *endOffset = offset;
+    }
+
+    return result;
+}
+
+static AtkAttributeSet* webkitAccessibleTextGetDefaultAttributes(AtkText* text)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    AccessibilityObject* coreObject = core(text);
+    if (!coreObject || !coreObject->isAccessibilityRenderObject())
+        return 0;
+
+    return getAttributeSetForAccessibilityObject(coreObject);
+}
+
+static void webkitAccessibleTextGetCharacterExtents(AtkText* text, gint offset, gint* x, gint* y, gint* width, gint* height, AtkCoordType coords)
+{
+    g_return_if_fail(ATK_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    IntRect extents = textExtents(text, offset, 1, coords);
+    *x = extents.x();
+    *y = extents.y();
+    *width = extents.width();
+    *height = extents.height();
+}
+
+static void webkitAccessibleTextGetRangeExtents(AtkText* text, gint startOffset, gint endOffset, AtkCoordType coords, AtkTextRectangle* rect)
+{
+    g_return_if_fail(ATK_TEXT(text));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text));
+
+    IntRect extents = textExtents(text, startOffset, endOffset - startOffset, coords);
+    rect->x = extents.x();
+    rect->y = extents.y();
+    rect->width = extents.width();
+    rect->height = extents.height();
+}
+
+static gint webkitAccessibleTextGetCharacterCount(AtkText* text)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    return accessibilityObjectLength(core(text));
+}
+
+static gint webkitAccessibleTextGetOffsetAtPoint(AtkText* text, gint x, gint y, AtkCoordType)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    // FIXME: Use the AtkCoordType
+    // TODO: Is it correct to ignore range.length?
+    IntPoint pos(x, y);
+    PlainTextRange range = core(text)->doAXRangeForPosition(pos);
+    return range.start;
+}
+
+static gint webkitAccessibleTextGetNSelections(AtkText* text)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    AccessibilityObject* coreObject = core(text);
+    VisibleSelection selection = coreObject->selection();
+
+    // Only range selections are needed for the purpose of this method
+    if (!selection.isRange())
+        return 0;
+
+    // We don't support multiple selections for now, so there's only
+    // two possibilities
+    // Also, we don't want to do anything if the selection does not
+    // belong to the currently selected object. We have to check since
+    // there's no way to get the selection for a given object, only
+    // the global one (the API is a bit confusing)
+    return selectionBelongsToObject(coreObject, selection) ? 1 : 0;
+}
+
+static gchar* webkitAccessibleTextGetSelection(AtkText* text, gint selectionNum, gint* startOffset, gint* endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), 0);
+
+    // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
+    if (selectionNum)
+        return 0;
+
+    // Get the offsets of the selection for the selected object
+    AccessibilityObject* coreObject = core(text);
+    VisibleSelection selection = coreObject->selection();
+    getSelectionOffsetsForObject(coreObject, selection, *startOffset, *endOffset);
+
+    // Return 0 instead of "", as that's the expected result for
+    // this AtkText method when there's no selection
+    if (*startOffset == *endOffset)
+        return 0;
+
+    return webkitAccessibleTextGetText(text, *startOffset, *endOffset);
+}
+
+static gboolean webkitAccessibleTextAddSelection(AtkText* text, gint, gint)
+{
+    g_return_val_if_fail(ATK_TEXT(text), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), FALSE);
+
+    notImplemented();
+    return FALSE;
+}
+
+static gboolean webkitAccessibleTextSetSelection(AtkText* text, gint selectionNum, gint startOffset, gint endOffset)
+{
+    g_return_val_if_fail(ATK_TEXT(text), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), FALSE);
+
+    // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
+    if (selectionNum)
+        return FALSE;
+
+    AccessibilityObject* coreObject = core(text);
+    if (!coreObject->isAccessibilityRenderObject())
+        return FALSE;
+
+    // Consider -1 and out-of-bound values and correct them to length
+    gint textCount = webkitAccessibleTextGetCharacterCount(text);
+    if (startOffset < 0 || startOffset > textCount)
+        startOffset = textCount;
+    if (endOffset < 0 || endOffset > textCount)
+        endOffset = textCount;
+
+    // We need to adjust the offsets for the list item marker.
+    int offsetAdjustment = offsetAdjustmentForListItem(coreObject);
+    if (offsetAdjustment) {
+        if (startOffset < offsetAdjustment || endOffset < offsetAdjustment)
+            return FALSE;
+
+        startOffset = atkOffsetToWebCoreOffset(text, startOffset);
+        endOffset = atkOffsetToWebCoreOffset(text, endOffset);
+    }
+
+    PlainTextRange textRange(startOffset, endOffset - startOffset);
+    VisiblePositionRange range = coreObject->visiblePositionRangeForRange(textRange);
+    if (range.isNull())
+        return FALSE;
+
+    coreObject->setSelectedVisiblePositionRange(range);
+    return TRUE;
+}
+
+static gboolean webkitAccessibleTextRemoveSelection(AtkText* text, gint selectionNum)
+{
+    g_return_val_if_fail(ATK_TEXT(text), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(text), FALSE);
+
+    // WebCore does not support multiple selection, so anything but 0 does not make sense for now.
+    if (selectionNum)
+        return FALSE;
+
+    // Do nothing if current selection doesn't belong to the object
+    if (!webkitAccessibleTextGetNSelections(text))
+        return FALSE;
+
+    // Set a new 0-sized selection to the caret position, in order
+    // to simulate selection removal (GAIL style)
+    gint caretOffset = webkitAccessibleTextGetCaretOffset(text);
+    return webkitAccessibleTextSetSelection(text, selectionNum, caretOffset, caretOffset);
+}
+
+static gboolean webkitAccessibleTextSetCaretOffset(AtkText* text, gint offset)
+{
+    // Internally, setting the caret offset is equivalent to set a zero-length
+    // selection, so delegate in that implementation and void duplicated code.
+    return webkitAccessibleTextSetSelection(text, 0, offset, offset);
+}
+
+static gchar* webkitAccessibleTextGetStringAtOffset(AtkText* text, gint offset, AtkTextGranularity granularity, gint* startOffset, gint* endOffset)
+{
+    // This new API has been designed to simplify the AtkText interface and it has been
+    // designed to keep exactly the same behaviour the atk_text_get_text_at_text() for
+    // ATK_TEXT_BOUNDARY_*_START boundaries, so for now we just need to translate the
+    // granularity to the right old boundary and reuse the code for the old API.
+    // However, this should be simplified later on (and a lot of code removed) once
+    // WebKitGTK depends on ATK >= 2.9.4 *and* can safely assume that a version of
+    // AT-SPI2 new enough not to include the old APIs is being used. But until then,
+    // we will have to live with both the old and new APIs implemented here.
+    // FIXME: WebKit nowadays depends on much newer ATK and we can safely assume AT-SPI2
+    // isn't ancient. But whoever wrote this code didn't use ATK_CHECK_VERSION() guards,
+    // so it's unclear what is supposed to be changed here.
+    AtkTextBoundary boundaryType = ATK_TEXT_BOUNDARY_CHAR;
+    switch (granularity) {
+    case ATK_TEXT_GRANULARITY_CHAR:
+        break;
+
+    case ATK_TEXT_GRANULARITY_WORD:
+        boundaryType = ATK_TEXT_BOUNDARY_WORD_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_SENTENCE:
+        boundaryType = ATK_TEXT_BOUNDARY_SENTENCE_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_LINE:
+        boundaryType = ATK_TEXT_BOUNDARY_LINE_START;
+        break;
+
+    case ATK_TEXT_GRANULARITY_PARAGRAPH:
+        // FIXME: This has not been a need with the old AtkText API, which means ATs won't
+        // need it yet for some time, so we can skip it for now.
+        notImplemented();
+        return g_strdup("");
+
+    default:
+        ASSERT_NOT_REACHED();
+    }
+
+    return webkitAccessibleTextGetTextForOffset(text, offset, boundaryType, GetTextPositionAt, startOffset, endOffset);
+}
+
+void webkitAccessibleTextInterfaceInit(AtkTextIface* iface)
+{
+    iface->get_text = webkitAccessibleTextGetText;
+    iface->get_text_after_offset = webkitAccessibleTextGetTextAfterOffset;
+    iface->get_text_at_offset = webkitAccessibleTextGetTextAtOffset;
+    iface->get_text_before_offset = webkitAccessibleTextGetTextBeforeOffset;
+    iface->get_character_at_offset = webkitAccessibleTextGetCharacterAtOffset;
+    iface->get_caret_offset = webkitAccessibleTextGetCaretOffset;
+    iface->get_run_attributes = webkitAccessibleTextGetRunAttributes;
+    iface->get_default_attributes = webkitAccessibleTextGetDefaultAttributes;
+    iface->get_character_extents = webkitAccessibleTextGetCharacterExtents;
+    iface->get_range_extents = webkitAccessibleTextGetRangeExtents;
+    iface->get_character_count = webkitAccessibleTextGetCharacterCount;
+    iface->get_offset_at_point = webkitAccessibleTextGetOffsetAtPoint;
+    iface->get_n_selections = webkitAccessibleTextGetNSelections;
+    iface->get_selection = webkitAccessibleTextGetSelection;
+    iface->add_selection = webkitAccessibleTextAddSelection;
+    iface->remove_selection = webkitAccessibleTextRemoveSelection;
+    iface->set_selection = webkitAccessibleTextSetSelection;
+    iface->set_caret_offset = webkitAccessibleTextSetCaretOffset;
+    iface->get_string_at_offset = webkitAccessibleTextGetStringAtOffset;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceText.h	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleTextInterfaceInit(AtkTextIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleInterfaceValue.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AccessibilityObject.h"
+#include "HTMLNames.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+static AccessibilityObject* core(AtkValue* value)
+{
+    if (!WEBKIT_IS_ACCESSIBLE(value))
+        return 0;
+
+    return &webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(value));
+}
+
+static bool webkitAccessibleSetNewValue(AtkValue* coreValue, const gdouble newValue)
+{
+    AccessibilityObject* coreObject = core(coreValue);
+    if (!coreObject->canSetValueAttribute())
+        return FALSE;
+
+    // Check value against range limits
+    double value;
+    value = std::max(static_cast<double>(coreObject->minValueForRange()), newValue);
+    value = std::min(static_cast<double>(coreObject->maxValueForRange()), newValue);
+
+    coreObject->setValue(String::numberToStringFixedPrecision(value));
+    return TRUE;
+}
+
+static float webkitAccessibleGetIncrementValue(AccessibilityObject* coreObject)
+{
+    if (!coreObject->getAttribute(HTMLNames::stepAttr).isEmpty())
+        return coreObject->stepValueForRange();
+
+    // If 'step' attribute is not defined, WebCore assumes a 5% of the
+    // range between minimum and maximum values. Implicit value of step should be one or larger.
+    float step = (coreObject->maxValueForRange() - coreObject->minValueForRange()) * 0.05;
+    return step < 1 ? 1 : step;
+}
+
+static void webkitAccessibleGetValueAndText(AtkValue* value, gdouble* currentValue, gchar** alternativeText)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    AccessibilityObject* coreObject = core(value);
+    if (!coreObject)
+        return;
+
+    if (currentValue)
+        *currentValue = coreObject->valueForRange();
+    if (alternativeText)
+        *alternativeText = g_strdup_printf("%s", coreObject->valueDescription().utf8().data());
+}
+
+static double webkitAccessibleGetIncrement(AtkValue* value)
+{
+    g_return_val_if_fail(ATK_VALUE(value), 0);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value), 0);
+
+    AccessibilityObject* coreObject = core(value);
+    if (!coreObject)
+        return 0;
+
+    return webkitAccessibleGetIncrementValue(coreObject);
+}
+
+static void webkitAccessibleSetValue(AtkValue* value, const gdouble newValue)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    webkitAccessibleSetNewValue(value, newValue);
+}
+
+static AtkRange* webkitAccessibleGetRange(AtkValue* value)
+{
+    g_return_val_if_fail(ATK_VALUE(value), nullptr);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value), nullptr);
+
+    AccessibilityObject* coreObject = core(value);
+    if (!coreObject)
+        return nullptr;
+
+    gdouble minValue = coreObject->minValueForRange();
+    gdouble maxValue = coreObject->maxValueForRange();
+    gchar* valueDescription = g_strdup_printf("%s", coreObject->valueDescription().utf8().data());
+    return atk_range_new(minValue, maxValue, valueDescription);
+}
+
+static void webkitAccessibleValueGetCurrentValue(AtkValue* value, GValue* gValue)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    memset(gValue,  0, sizeof(GValue));
+    g_value_init(gValue, G_TYPE_FLOAT);
+    g_value_set_float(gValue, core(value)->valueForRange());
+}
+
+static void webkitAccessibleValueGetMaximumValue(AtkValue* value, GValue* gValue)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    memset(gValue,  0, sizeof(GValue));
+    g_value_init(gValue, G_TYPE_FLOAT);
+    g_value_set_float(gValue, core(value)->maxValueForRange());
+}
+
+static void webkitAccessibleValueGetMinimumValue(AtkValue* value, GValue* gValue)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    memset(gValue,  0, sizeof(GValue));
+    g_value_init(gValue, G_TYPE_FLOAT);
+    g_value_set_float(gValue, core(value)->minValueForRange());
+}
+
+static gboolean webkitAccessibleValueSetCurrentValue(AtkValue* value, const GValue* gValue)
+{
+    g_return_val_if_fail(ATK_VALUE(value), FALSE);
+    returnValIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value), FALSE);
+
+    double newValue;
+    if (G_VALUE_HOLDS_DOUBLE(gValue))
+        newValue = g_value_get_double(gValue);
+    else if (G_VALUE_HOLDS_FLOAT(gValue))
+        newValue = g_value_get_float(gValue);
+    else if (G_VALUE_HOLDS_INT64(gValue))
+        newValue = g_value_get_int64(gValue);
+    else if (G_VALUE_HOLDS_INT(gValue))
+        newValue = g_value_get_int(gValue);
+    else if (G_VALUE_HOLDS_LONG(gValue))
+        newValue = g_value_get_long(gValue);
+    else if (G_VALUE_HOLDS_ULONG(gValue))
+        newValue = g_value_get_ulong(gValue);
+    else if (G_VALUE_HOLDS_UINT64(gValue))
+        newValue = g_value_get_uint64(gValue);
+    else if (G_VALUE_HOLDS_UINT(gValue))
+        newValue = g_value_get_uint(gValue);
+    else
+        return FALSE;
+
+    return webkitAccessibleSetNewValue(value, newValue);
+}
+
+static void webkitAccessibleValueGetMinimumIncrement(AtkValue* value, GValue* gValue)
+{
+    g_return_if_fail(ATK_VALUE(value));
+    returnIfWebKitAccessibleIsInvalid(WEBKIT_ACCESSIBLE(value));
+
+    memset(gValue,  0, sizeof(GValue));
+    g_value_init(gValue, G_TYPE_FLOAT);
+
+    AccessibilityObject* coreObject = core(value);
+    g_value_set_float(gValue, webkitAccessibleGetIncrementValue(coreObject));
+}
+
+void webkitAccessibleValueInterfaceInit(AtkValueIface* iface)
+{
+    iface->get_value_and_text = webkitAccessibleGetValueAndText;
+    iface->get_increment = webkitAccessibleGetIncrement;
+    iface->set_value = webkitAccessibleSetValue;
+    iface->get_range = webkitAccessibleGetRange;
+    iface->get_current_value = webkitAccessibleValueGetCurrentValue;
+    iface->get_maximum_value = webkitAccessibleValueGetMaximumValue;
+    iface->get_minimum_value = webkitAccessibleValueGetMinimumValue;
+    iface->set_current_value = webkitAccessibleValueSetCurrentValue;
+    iface->get_minimum_increment = webkitAccessibleValueGetMinimumIncrement;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleInterfaceValue.h	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+
+void webkitAccessibleValueInterfaceInit(AtkValueIface*);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2012 Igalia S.L.
+ *
+ * Portions from Mozilla a11y, copyright as follows:
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAccessibleUtil.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AXObjectCache.h"
+#include "AccessibilityObject.h"
+#include "FrameView.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "Range.h"
+#include "RenderObject.h"
+#include "TextIterator.h"
+#include "VisibleSelection.h"
+
+#include <wtf/text/AtomString.h>
+#include <wtf/text/CString.h>
+
+using namespace WebCore;
+
+AtkAttributeSet* addToAtkAttributeSet(AtkAttributeSet* attributeSet, const char* name, const char* value)
+{
+    AtkAttribute* attribute = static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
+    attribute->name = g_strdup(name);
+    attribute->value = g_strdup(value);
+    attributeSet = g_slist_prepend(attributeSet, attribute);
+    return attributeSet;
+}
+
+void contentsRelativeToAtkCoordinateType(AccessibilityObject* coreObject, AtkCoordType coordType, IntRect rect, gint* x, gint* y, gint* width, gint* height)
+{
+    FrameView* frameView = coreObject->documentFrameView();
+
+    if (frameView) {
+        switch (coordType) {
+        case ATK_XY_WINDOW:
+            rect = frameView->contentsToWindow(rect);
+            break;
+        case ATK_XY_SCREEN:
+            rect = frameView->contentsToScreen(rect);
+            break;
+#if ATK_CHECK_VERSION(2, 30, 0)
+        case ATK_XY_PARENT:
+            RELEASE_ASSERT_NOT_REACHED();
+#endif
+        }
+    }
+
+    if (x)
+        *x = rect.x();
+    if (y)
+        *y = rect.y();
+    if (width)
+        *width = rect.width();
+    if (height)
+        *height = rect.height();
+}
+
+// FIXME: Different kinds of elements are putting the title tag to use
+// in different AX fields. This might not be 100% correct but we will
+// keep it now in order to achieve consistency with previous behavior.
+static bool titleTagShouldBeUsedInDescriptionField(AccessibilityObject* coreObject)
+{
+    return (coreObject->isLink() && !coreObject->isImageMapLink()) || coreObject->isImage();
+}
+
+// This should be the "visible" text that's actually on the screen if possible.
+// If there's alternative text, that can override the title.
+String accessibilityTitle(AccessibilityObject* coreObject)
+{
+    Vector<AccessibilityText> textOrder;
+    coreObject->accessibilityText(textOrder);
+
+    for (const AccessibilityText& text : textOrder) {
+        // Once we encounter visible text, or the text from our children that should be used foremost.
+        if (text.textSource == AccessibilityTextSource::Visible || text.textSource == AccessibilityTextSource::Children)
+            return text.text;
+
+        // If there's an element that labels this object and it's not exposed, then we should use
+        // that text as our title.
+        if (text.textSource == AccessibilityTextSource::LabelByElement && !coreObject->titleUIElement())
+            return text.text;
+
+        // Elements of role AccessibilityRole::Toolbar will return its title as AccessibilityTextSource::Alternative.
+        if (coreObject->roleValue() == AccessibilityRole::Toolbar && text.textSource == AccessibilityTextSource::Alternative)
+            return text.text;
+
+        // FIXME: The title tag is used in certain cases for the title. This usage should
+        // probably be in the description field since it's not "visible".
+        if (text.textSource == AccessibilityTextSource::TitleTag && !titleTagShouldBeUsedInDescriptionField(coreObject))
+            return text.text;
+    }
+
+    return String();
+}
+
+String accessibilityDescription(AccessibilityObject* coreObject)
+{
+    Vector<AccessibilityText> textOrder;
+    coreObject->accessibilityText(textOrder);
+
+    bool visibleTextAvailable = false;
+    for (const AccessibilityText& text : textOrder) {
+        if (text.textSource == AccessibilityTextSource::Alternative)
+            return text.text;
+
+        switch (text.textSource) {
+        case AccessibilityTextSource::Visible:
+        case AccessibilityTextSource::Children:
+        case AccessibilityTextSource::LabelByElement:
+            visibleTextAvailable = true;
+        default:
+            break;
+        }
+
+        if (text.textSource == AccessibilityTextSource::TitleTag && !visibleTextAvailable)
+            return text.text;
+    }
+
+    return String();
+}
+
+bool selectionBelongsToObject(AccessibilityObject* coreObject, VisibleSelection& selection)
+{
+    if (!coreObject || !coreObject->isAccessibilityRenderObject())
+        return false;
+
+    auto range = selection.firstRange();
+    return range && intersects<ComposedTree>(*range, *coreObject->node());
+}
+
+AXCoreObject* objectFocusedAndCaretOffsetUnignored(AXCoreObject* referenceObject, int& offset)
+{
+    // Indication that something bogus has transpired.
+    offset = -1;
+
+    Document* document = referenceObject->document();
+    if (!document)
+        return nullptr;
+
+    Node* focusedNode = referenceObject->selection().end().containerNode();
+    if (!focusedNode)
+        return nullptr;
+
+    RenderObject* focusedRenderer = focusedNode->renderer();
+    if (!focusedRenderer)
+        return nullptr;
+
+    AccessibilityObject* focusedObject = document->axObjectCache()->getOrCreate(focusedRenderer);
+    if (!focusedObject)
+        return nullptr;
+
+    // Look for the actual (not ignoring accessibility) selected object.
+    AXCoreObject* firstUnignoredParent = focusedObject;
+    if (firstUnignoredParent->accessibilityIsIgnored())
+        firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
+    if (!firstUnignoredParent)
+        return nullptr;
+
+    // Don't ignore links if the offset is being requested for a link
+    // or if the link is a block.
+    if (!referenceObject->isLink() && firstUnignoredParent->isLink()
+        && !(firstUnignoredParent->renderer() && !firstUnignoredParent->renderer()->isInline()))
+        firstUnignoredParent = firstUnignoredParent->parentObjectUnignored();
+    if (!firstUnignoredParent)
+        return nullptr;
+
+    // The reference object must either coincide with the focused
+    // object being considered, or be a descendant of it.
+    if (referenceObject->isDescendantOfObject(firstUnignoredParent))
+        referenceObject = firstUnignoredParent;
+
+    Node* startNode = nullptr;
+    if (firstUnignoredParent != referenceObject || firstUnignoredParent->isTextControl()) {
+        // We need to use the first child's node of the reference
+        // object as the start point to calculate the caret offset
+        // because we want it to be relative to the object of
+        // reference, not just to the focused object (which could have
+        // previous siblings which should be taken into account too).
+        AXCoreObject* axFirstChild = reinterpret_cast<AccessibilityObject *>(referenceObject)->firstChild();
+        if (axFirstChild)
+            startNode = axFirstChild->node();
+    }
+    // Getting the Position of a PseudoElement now triggers an assertion.
+    // This can occur when clicking on empty space in a render block.
+    if (!startNode || startNode->isPseudoElement())
+        startNode = firstUnignoredParent->node();
+
+    // Check if the node for the first parent object not ignoring
+    // accessibility is null again before using it. This might happen
+    // with certain kind of accessibility objects, such as the root
+    // one (the scroller containing the webArea object).
+    if (!startNode)
+        return nullptr;
+
+    VisiblePosition startPosition = VisiblePosition(positionBeforeNode(startNode));
+    VisiblePosition endPosition = firstUnignoredParent->selection().visibleEnd();
+
+    if (startPosition == endPosition)
+        offset = 0;
+    else if (!isStartOfLine(endPosition)) {
+        auto range = makeSimpleRange(startPosition, endPosition.previous());
+        offset = (range ? characterCount(*range, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions) : 0) + 1;
+    } else {
+        auto range = makeSimpleRange(startPosition, endPosition);
+        offset = range ? characterCount(*range, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions) : 0;
+    }
+
+    return firstUnignoredParent;
+}
+
+#endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atk/WebKitAccessibleUtil.h	2023-03-09 13:26:47.286643885 -0600
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2009 Jan Alonzo
+ * Copyright (C) 2009, 2010, 2012 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include <atk/atk.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class AXCoreObject;
+class AccessibilityObject;
+class IntRect;
+class VisibleSelection;
+}
+
+// An existing accessibility object is considered to be invalid whether it's already
+// detached or if it's not but just updating the layout will detach it anyway.
+#define returnIfWebKitAccessibleIsInvalid(webkitAccessible) G_STMT_START { \
+    if (!webkitAccessible || webkitAccessibleIsDetached(webkitAccessible)) \
+        return; \
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(webkitAccessible); \
+    if (!coreObject.document())                                         \
+        return;                                                         \
+    coreObject.updateBackingStore();                                    \
+    if (webkitAccessibleIsDetached(webkitAccessible))                   \
+        return;                                                         \
+    ; } G_STMT_END
+
+#define returnValIfWebKitAccessibleIsInvalid(webkitAccessible, val) G_STMT_START { \
+    if (!webkitAccessible || webkitAccessibleIsDetached(webkitAccessible)) \
+        return (val);                                                   \
+    auto& coreObject = webkitAccessibleGetAccessibilityObject(webkitAccessible); \
+    if (!coreObject.document())                                         \
+        return (val);                                                   \
+    coreObject.updateBackingStore();                                    \
+    if (webkitAccessibleIsDetached(webkitAccessible))                   \
+        return (val);                                                   \
+    ; } G_STMT_END
+
+AtkAttributeSet* addToAtkAttributeSet(AtkAttributeSet*, const char* name, const char* value);
+
+void contentsRelativeToAtkCoordinateType(WebCore::AccessibilityObject*, AtkCoordType, WebCore::IntRect, gint* x, gint* y, gint* width = nullptr, gint* height = nullptr);
+
+String accessibilityTitle(WebCore::AccessibilityObject*);
+
+String accessibilityDescription(WebCore::AccessibilityObject*);
+
+bool selectionBelongsToObject(WebCore::AccessibilityObject*, WebCore::VisibleSelection&);
+
+WebCore::AXCoreObject* objectFocusedAndCaretOffsetUnignored(WebCore::AXCoreObject*, int& offset);
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp	2023-02-20 03:22:15.289729400 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp	2023-03-09 13:26:47.286643885 -0600
@@ -967,7 +967,7 @@ HashMap<String, String> AccessibilityObj
 
     // According to the W3C Core Accessibility API Mappings 1.1, section 5.4.1 General Rules:
     // "User agents must expose the WAI-ARIA role string if the API supports a mechanism to do so."
-    // In the case of ATSPI, the mechanism to do so is an object attribute pair (xml-roles:"string").
+    // In the case of ATK, the mechanism to do so is an object attribute pair (xml-roles:"string").
     // We cannot use the computedRoleString for this purpose because it is not limited to elements
     // with ARIA roles, and it might not contain the actual ARIA role value (e.g. DPub ARIA).
     String roleString = static_cast<AccessibilityObject*>(m_coreObject)->getAttribute(HTMLNames::roleAttr);
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AXObjectCache.h webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AXObjectCache.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/accessibility/AXObjectCache.h	2023-02-20 03:22:15.225729000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/accessibility/AXObjectCache.h	2023-03-09 13:26:47.290643907 -0600
@@ -39,6 +39,10 @@
 #include <wtf/ListHashSet.h>
 #include <wtf/WeakHashSet.h>
 
+#if USE(ATK)
+#include <wtf/glib/GRefPtr.h>
+#endif
+
 namespace WTF {
 class TextStream;
 }
@@ -613,6 +617,10 @@ private:
     bool m_relationsNeedUpdate { true };
     HashSet<AXID> m_relationTargets;
 
+#if USE(ATK)
+    ListHashSet<RefPtr<AccessibilityObject>> m_deferredAttachedWrapperObjectList;
+    ListHashSet<GRefPtr<AccessibilityObjectWrapper>> m_deferredDetachedWrapperList;
+#endif
 #if USE(ATSPI)
     ListHashSet<RefPtr<AXCoreObject>> m_deferredParentChangedList;
 #endif
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/editing/atk/FrameSelectionAtk.cpp webkitgtk-2.39.91.atk/Source/WebCore/editing/atk/FrameSelectionAtk.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/editing/atk/FrameSelectionAtk.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/editing/atk/FrameSelectionAtk.cpp	2023-03-09 13:26:47.290643907 -0600
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2009 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FrameSelection.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATK)
+
+#include "AXObjectCache.h"
+#include "DocumentInlines.h"
+#include "Frame.h"
+#include "RenderListItem.h"
+#include "WebKitAccessible.h"
+#include "WebKitAccessibleUtil.h"
+#include <glib.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static void emitTextSelectionChange(AXCoreObject* object, VisibleSelection selection, int offset)
+{
+    auto* axObject = object->wrapper();
+    if (!axObject || !ATK_IS_TEXT(axObject))
+        return;
+
+    // We need to adjust the offset for the list item marker in Left-To-Right text because
+    // the list item marker is exposed through the text of the accessible list item rather
+    // than through a separate accessible object.
+    RenderObject* renderer = object->renderer();
+    if (is<RenderListItem>(renderer) && renderer->style().direction() == TextDirection::LTR)
+        offset += downcast<RenderListItem>(*renderer).markerTextWithSuffix().length();
+
+    g_signal_emit_by_name(axObject, "text-caret-moved", offset);
+    if (selection.isRange())
+        g_signal_emit_by_name(axObject, "text-selection-changed");
+}
+
+static void maybeEmitTextFocusChange(RefPtr<AXCoreObject>&& object)
+{
+    // This static variable is needed to keep track of the old object
+    // as per previous calls to this function, in order to properly
+    // decide whether to emit some signals or not.
+    static NeverDestroyed<RefPtr<AXCoreObject>> oldObject;
+
+    // Ensure the oldObject belongs to the same document that the
+    // current object so further comparisons make sense. Otherwise,
+    // just reset oldObject to 0 so it won't be taken into account in
+    // the immediately following call to this function.
+    if (object && oldObject.get() && oldObject.get()->document() != object->document())
+        oldObject.get() = nullptr;
+
+    auto* axObject = object ? object->wrapper() : nullptr;
+    auto* oldAxObject = oldObject.get() ? oldObject.get()->wrapper() : nullptr;
+
+    if (axObject != oldAxObject) {
+        if (oldAxObject && ATK_IS_TEXT(oldAxObject)) {
+            g_signal_emit_by_name(oldAxObject, "focus-event", FALSE);
+            atk_object_notify_state_change(ATK_OBJECT(oldAxObject), ATK_STATE_FOCUSED, FALSE);
+        }
+        if (axObject && ATK_IS_TEXT(axObject)) {
+            g_signal_emit_by_name(axObject, "focus-event", TRUE);
+            atk_object_notify_state_change(ATK_OBJECT(axObject), ATK_STATE_FOCUSED, TRUE);
+        }
+    }
+
+    // Update pointer to last focused object.
+    oldObject.get() = WTFMove(object);
+}
+
+
+void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&)
+{
+    if (!AXObjectCache::accessibilityEnabled())
+        return;
+
+    if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull())
+        return;
+
+    Node* focusedNode = m_selection.end().containerNode();
+    if (!focusedNode)
+        return;
+
+    AXObjectCache* cache = m_document->existingAXObjectCache();
+    if (!cache)
+        return;
+
+    AccessibilityObject* accessibilityObject = cache->getOrCreate(focusedNode->renderer());
+    if (!accessibilityObject)
+        return;
+
+    int offset;
+    RefPtr<AXCoreObject> object = objectFocusedAndCaretOffsetUnignored(accessibilityObject, offset);
+    if (!object)
+        return;
+
+    emitTextSelectionChange(object.get(), m_selection, offset);
+    maybeEmitTextFocusChange(WTFMove(object));
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATK)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/editing/FrameSelection.h webkitgtk-2.39.91.atk/Source/WebCore/editing/FrameSelection.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/editing/FrameSelection.h	2023-02-20 03:22:16.373733500 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/editing/FrameSelection.h	2023-03-09 13:26:47.290643907 -0600
@@ -383,7 +383,7 @@ inline void FrameSelection::clearTypingS
     m_typingStyle = nullptr;
 }
 
-#if !(ENABLE(ACCESSIBILITY) && (PLATFORM(COCOA) || USE(ATSPI)))
+#if !(ENABLE(ACCESSIBILITY) && (PLATFORM(COCOA) || USE(ATK) || USE(ATSPI)))
 
 inline void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent&)
 {
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/page/Settings.yaml webkitgtk-2.39.91.atk/Source/WebCore/page/Settings.yaml
--- webkitgtk-2.39.91.glib244/Source/WebCore/page/Settings.yaml	2023-02-20 03:22:17.725739000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/page/Settings.yaml	2023-03-09 13:26:47.290643907 -0600
@@ -264,6 +264,7 @@ LangAttributeAwareFormControlUIEnabled:
   type: bool
   defaultValue:
     WebCore:
+      USE(ATSPI): true
       default: false
 
 LocalStorageDatabasePath:
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/PlatformDisplay.cpp webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/PlatformDisplay.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/PlatformDisplay.cpp	2023-03-08 03:00:32.710698800 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/PlatformDisplay.cpp	2023-03-09 13:26:47.290643907 -0600
@@ -80,7 +80,7 @@
 #include <wtf/NeverDestroyed.h>
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
 #include <wtf/glib/GUniquePtr.h>
 #endif
 
@@ -342,7 +342,7 @@ cmsHPROFILE PlatformDisplay::colorProfil
 }
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
 const String& PlatformDisplay::accessibilityBusAddress() const
 {
     if (m_accessibilityBusAddress)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/PlatformDisplay.h webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/PlatformDisplay.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/PlatformDisplay.h	2023-03-08 03:00:32.710698800 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/PlatformDisplay.h	2023-03-09 13:26:47.290643907 -0600
@@ -104,7 +104,7 @@ public:
     virtual cmsHPROFILE colorProfile() const;
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
     const String& accessibilityBusAddress() const;
 #endif
 
@@ -136,7 +136,7 @@ protected:
     mutable LCMSProfilePtr m_iccProfile;
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
     virtual String platformAccessibilityBusAddress() const { return { }; }
 
     mutable std::optional<String> m_accessibilityBusAddress;
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.cpp webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.cpp
--- webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.cpp	2023-02-20 03:22:19.013744000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.cpp	2023-03-09 13:26:47.290643907 -0600
@@ -271,7 +271,7 @@ cmsHPROFILE PlatformDisplayX11::colorPro
 }
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
 String PlatformDisplayX11::platformAccessibilityBusAddress() const
 {
     Atom atspiBusAtom = XInternAtom(m_display, "AT_SPI_BUS", False);
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.h webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.h
--- webkitgtk-2.39.91.glib244/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.h	2023-02-20 03:22:19.017744000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/platform/graphics/x11/PlatformDisplayX11.h	2023-03-09 13:26:47.290643907 -0600
@@ -71,7 +71,7 @@ private:
     cmsHPROFILE colorProfile() const override;
 #endif
 
-#if USE(ATSPI)
+#if USE(ATSPI) || USE(ATK)
     String platformAccessibilityBusAddress() const override;
 #endif
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/PlatformGTK.cmake webkitgtk-2.39.91.atk/Source/WebCore/PlatformGTK.cmake
--- webkitgtk-2.39.91.glib244/Source/WebCore/PlatformGTK.cmake	2023-02-20 03:22:15.125728600 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/PlatformGTK.cmake	2023-03-09 13:26:47.290643907 -0600
@@ -14,8 +14,10 @@ list(APPEND WebCore_UNIFIED_SOURCE_LIST_
 )
 
 list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES
+    "${WEBCORE_DIR}/accessibility/atk"
     "${WEBCORE_DIR}/accessibility/atspi"
     "${WEBCORE_DIR}/crypto/openssl"
+    "${WEBCORE_DIR}/editing/atk"
     "${WEBCORE_DIR}/page/gtk"
     "${WEBCORE_DIR}/platform/audio/glib"
     "${WEBCORE_DIR}/platform/generic"
@@ -68,6 +70,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HE
 set(CSS_VALUE_PLATFORM_DEFINES "HAVE_OS_DARK_MODE_SUPPORT=1")
 
 list(APPEND WebCore_LIBRARIES
+    ${ATK_LIBRARIES}
     ${ENCHANT_LIBRARIES}
     ${GLIB_GIO_LIBRARIES}
     ${GLIB_GMODULE_LIBRARIES}
@@ -86,6 +89,7 @@ list(APPEND WebCore_LIBRARIES
 )
 
 list(APPEND WebCore_SYSTEM_INCLUDE_DIRECTORIES
+    ${ATK_INCLUDE_DIRS}
     ${ENCHANT_INCLUDE_DIRS}
     ${GIO_UNIX_INCLUDE_DIRS}
     ${GLIB_INCLUDE_DIRS}
diff -urpN webkitgtk-2.39.91.glib244/Source/WebCore/SourcesGTK.txt webkitgtk-2.39.91.atk/Source/WebCore/SourcesGTK.txt
--- webkitgtk-2.39.91.glib244/Source/WebCore/SourcesGTK.txt	2023-03-09 11:32:30.594447910 -0600
+++ webkitgtk-2.39.91.atk/Source/WebCore/SourcesGTK.txt	2023-03-09 13:26:47.290643907 -0600
@@ -21,6 +21,24 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 // THE POSSIBILITY OF SUCH DAMAGE.
 
+accessibility/atk/AXObjectCacheAtk.cpp
+accessibility/atk/AccessibilityObjectAtk.cpp
+accessibility/atk/WebKitAccessible.cpp
+accessibility/atk/WebKitAccessibleHyperlink.cpp
+accessibility/atk/WebKitAccessibleInterfaceAction.cpp @no-unify
+accessibility/atk/WebKitAccessibleInterfaceComponent.cpp
+accessibility/atk/WebKitAccessibleInterfaceDocument.cpp
+accessibility/atk/WebKitAccessibleInterfaceEditableText.cpp
+accessibility/atk/WebKitAccessibleInterfaceHyperlinkImpl.cpp
+accessibility/atk/WebKitAccessibleInterfaceHypertext.cpp
+accessibility/atk/WebKitAccessibleInterfaceImage.cpp
+accessibility/atk/WebKitAccessibleInterfaceSelection.cpp
+accessibility/atk/WebKitAccessibleInterfaceTable.cpp
+accessibility/atk/WebKitAccessibleInterfaceTableCell.cpp
+accessibility/atk/WebKitAccessibleInterfaceText.cpp
+accessibility/atk/WebKitAccessibleInterfaceValue.cpp
+accessibility/atk/WebKitAccessibleUtil.cpp
+
 accessibility/atspi/AccessibilityAtspi.cpp
 accessibility/atspi/AccessibilityObjectAtspi.cpp
 accessibility/atspi/AccessibilityObjectActionAtspi.cpp
@@ -38,6 +56,8 @@ accessibility/atspi/AccessibilityObjectV
 accessibility/atspi/AccessibilityRootAtspi.cpp
 accessibility/atspi/AXObjectCacheAtspi.cpp
 
+editing/atk/FrameSelectionAtk.cpp
+
 editing/atspi/FrameSelectionAtspi.cpp
 
 editing/gtk/EditorGtk.cpp
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/PlatformGTK.cmake webkitgtk-2.39.91.atk/Source/WebKit/PlatformGTK.cmake
--- webkitgtk-2.39.91.glib244/Source/WebKit/PlatformGTK.cmake	2023-03-09 13:26:06.422428155 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/PlatformGTK.cmake	2023-03-09 13:26:47.290643907 -0600
@@ -287,10 +287,12 @@ list(APPEND WebKit_INCLUDE_DIRECTORIES
     "${WEBKIT_DIR}/WebProcess/WebCoreSupport/gtk"
     "${WEBKIT_DIR}/WebProcess/WebCoreSupport/soup"
     "${WEBKIT_DIR}/WebProcess/WebPage/CoordinatedGraphics"
+    "${WEBKIT_DIR}/WebProcess/WebPage/atk"
     "${WEBKIT_DIR}/WebProcess/WebPage/gtk"
 )
 
 list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES
+    ${ATK_INCLUDE_DIRS}
     ${ENCHANT_INCLUDE_DIRS}
     ${GIO_UNIX_INCLUDE_DIRS}
     ${GLIB_INCLUDE_DIRS}
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/SourcesGTK.txt webkitgtk-2.39.91.atk/Source/WebKit/SourcesGTK.txt
--- webkitgtk-2.39.91.glib244/Source/WebKit/SourcesGTK.txt	2023-03-09 11:32:30.594447910 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/SourcesGTK.txt	2023-03-09 13:26:47.290643907 -0600
@@ -324,6 +324,8 @@ WebProcess/WebPage/CoordinatedGraphics/C
 WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp
 WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp
 
+WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp
+
 WebProcess/WebPage/glib/WebPageGLib.cpp
 
 WebProcess/WebPage/gtk/AcceleratedSurfaceX11.cpp @no-unify
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.cpp webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.cpp
--- webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.cpp	2023-02-20 03:22:21.497753900 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.cpp	2023-03-09 13:26:47.290643907 -0600
@@ -20,7 +20,7 @@
 #include "config.h"
 #include "WebKitWebViewAccessible.h"
 
-#if ENABLE(ACCESSIBILITY) && !USE(GTK4)
+#if ENABLE(ACCESSIBILITY)
 
 #include <wtf/glib/WTFGType.h>
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.h webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.h
--- webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.h	2023-02-20 03:22:21.497753900 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/glib/WebKitWebViewAccessible.h	2023-03-09 13:26:47.290643907 -0600
@@ -19,7 +19,7 @@
 
 #pragma once
 
-#if ENABLE(ACCESSIBILITY) && !USE(GTK4)
+#if ENABLE(ACCESSIBILITY)
 
 #include <atk/atk.h>
 
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
--- webkitgtk-2.39.91.glib244/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp	2023-03-09 11:32:30.602447951 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp	2023-03-09 13:26:47.294643927 -0600
@@ -285,9 +285,7 @@ struct _WebKitWebViewBasePrivate {
     CString tooltipText;
     IntRect tooltipArea;
     WebHitTestResultData::IsScrollbar mouseIsOverScrollbar;
-#if !USE(GTK4)
     GRefPtr<AtkObject> accessible;
-#endif
     GtkWidget* dialog { nullptr };
     GtkWidget* inspectorView { nullptr };
     AttachmentSide inspectorAttachmentSide { AttachmentSide::Bottom };
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp
--- webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp	2023-03-09 13:26:47.294643927 -0600
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2012, 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebKitWebPageAccessibilityObject.h"
+
+#if ENABLE(ACCESSIBILITY)
+
+#include "WebPage.h"
+#include <WebCore/AXObjectCache.h>
+#include <WebCore/AccessibilityScrollView.h>
+#include <WebCore/Document.h>
+#include <WebCore/Frame.h>
+#include <WebCore/Page.h>
+#include <WebCore/ScrollView.h>
+#include <wtf/glib/WTFGType.h>
+
+using namespace WebKit;
+using namespace WebCore;
+
+struct _WebKitWebPageAccessibilityObjectPrivate {
+    WebPage* page;
+};
+
+WEBKIT_DEFINE_TYPE(WebKitWebPageAccessibilityObject, webkit_web_page_accessibility_object, ATK_TYPE_PLUG)
+
+static void coreRootObjectWrapperDetachedCallback(AtkObject* wrapper, const char*, gboolean value, AtkObject* atkObject)
+{
+    if (!value)
+        return;
+
+    g_signal_emit_by_name(atkObject, "children-changed::remove", 0, wrapper);
+}
+
+static AccessibilityObjectWrapper* rootWebAreaWrapper(AXCoreObject& rootObject)
+{
+    if (!rootObject.isScrollView())
+        return nullptr;
+
+    if (auto* webAreaObject = downcast<AccessibilityObject>(rootObject).webAreaObject())
+        return webAreaObject->wrapper();
+
+    return nullptr;
+}
+
+static AtkObject* accessibilityRootObjectWrapper(AtkObject* atkObject)
+{
+    if (!AXObjectCache::accessibilityEnabled())
+        AXObjectCache::enableAccessibility();
+
+    auto* accessible = WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT(atkObject);
+    if (!accessible->priv->page)
+        return nullptr;
+
+    Page* corePage = accessible->priv->page->corePage();
+    if (!corePage)
+        return nullptr;
+
+    Frame& coreFrame = corePage->mainFrame();
+    if (!coreFrame.document())
+        return nullptr;
+
+    AXObjectCache* cache = coreFrame.document()->axObjectCache();
+    if (!cache)
+        return nullptr;
+
+    AXCoreObject* coreRootObject = cache->rootObject();
+    if (!coreRootObject)
+        return nullptr;
+
+    auto* wrapper = ATK_OBJECT(coreRootObject->wrapper());
+    if (!wrapper)
+        return nullptr;
+
+    if (atk_object_peek_parent(wrapper) != ATK_OBJECT(accessible)) {
+        atk_object_set_parent(wrapper, ATK_OBJECT(accessible));
+        g_signal_emit_by_name(accessible, "children-changed::add", 0, wrapper);
+
+        if (auto* webAreaWrapper = rootWebAreaWrapper(*coreRootObject)) {
+            g_signal_connect_object(webAreaWrapper, "state-change::defunct",
+                G_CALLBACK(coreRootObjectWrapperDetachedCallback), accessible, static_cast<GConnectFlags>(0));
+        }
+    }
+
+    return wrapper;
+}
+
+static void webkitWebPageAccessibilityObjectInitialize(AtkObject* atkObject, gpointer data)
+{
+    if (ATK_OBJECT_CLASS(webkit_web_page_accessibility_object_parent_class)->initialize)
+        ATK_OBJECT_CLASS(webkit_web_page_accessibility_object_parent_class)->initialize(atkObject, data);
+
+    WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT(atkObject)->priv->page = reinterpret_cast<WebPage*>(data);
+    atk_object_set_role(atkObject, ATK_ROLE_FILLER);
+}
+
+static gint webkitWebPageAccessibilityObjectGetIndexInParent(AtkObject*)
+{
+    // An AtkPlug is the only child an AtkSocket can have.
+    return 0;
+}
+
+static gint webkitWebPageAccessibilityObjectGetNChildren(AtkObject* atkObject)
+{
+    return accessibilityRootObjectWrapper(atkObject) ? 1 : 0;
+}
+
+static AtkObject* webkitWebPageAccessibilityObjectRefChild(AtkObject* atkObject, gint index)
+{
+    // It's supposed to have either one child or zero.
+    if (index && index != 1)
+        return nullptr;
+
+    if (auto* rootObjectWrapper = accessibilityRootObjectWrapper(atkObject))
+        return ATK_OBJECT(g_object_ref(rootObjectWrapper));
+
+    return nullptr;
+}
+
+static AtkStateSet* webkitWebPageAccessibilityObjectRefStateSet(AtkObject* atkObject)
+{
+    if (auto* rootObjectWrapper = accessibilityRootObjectWrapper(atkObject))
+        return atk_object_ref_state_set(rootObjectWrapper);
+
+    return atk_state_set_new();
+}
+
+static void webkit_web_page_accessibility_object_class_init(WebKitWebPageAccessibilityObjectClass* klass)
+{
+    AtkObjectClass* atkObjectClass = ATK_OBJECT_CLASS(klass);
+    // No need to implement get_parent() here since this is a subclass
+    // of AtkPlug and all the logic related to that function will be
+    // implemented by the ATK bridge.
+    atkObjectClass->initialize = webkitWebPageAccessibilityObjectInitialize;
+    atkObjectClass->get_index_in_parent = webkitWebPageAccessibilityObjectGetIndexInParent;
+    atkObjectClass->get_n_children = webkitWebPageAccessibilityObjectGetNChildren;
+    atkObjectClass->ref_child = webkitWebPageAccessibilityObjectRefChild;
+    atkObjectClass->ref_state_set = webkitWebPageAccessibilityObjectRefStateSet;
+}
+
+AtkObject* webkitWebPageAccessibilityObjectNew(WebPage* page)
+{
+    AtkObject* object = ATK_OBJECT(g_object_new(WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT, nullptr));
+    atk_object_initialize(object, page);
+    return object;
+}
+
+#endif // ENABLE(ACCESSIBILITY)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h
--- webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h	1969-12-31 18:00:00.000000000 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h	2023-03-09 13:26:47.294643927 -0600
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012, 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ACCESSIBILITY)
+
+#include <atk/atk.h>
+
+namespace WebKit {
+class WebPage;
+}
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT              (webkit_web_page_accessibility_object_get_type())
+#define WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT, WebKitWebPageAccessibilityObject))
+#define WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT, WebKitWebPageAccessibilityObjectClass))
+#define WEBKIT_IS_WEB_PAGE_ACCESSIBILITY_OBJECT(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT))
+#define WEBKIT_IS_WEB_PAGE_ACCESSIBILITY_OBJECT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT))
+#define WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), WEBKIT_TYPE_WEB_PAGE_ACCESSIBILITY_OBJECT, WebKitWebPageAccessibilityObjectClass))
+
+typedef struct _WebKitWebPageAccessibilityObject WebKitWebPageAccessibilityObject;
+typedef struct _WebKitWebPageAccessibilityObjectClass WebKitWebPageAccessibilityObjectClass;
+typedef struct _WebKitWebPageAccessibilityObjectPrivate WebKitWebPageAccessibilityObjectPrivate;
+
+struct _WebKitWebPageAccessibilityObject {
+    AtkPlug parent;
+
+    WebKitWebPageAccessibilityObjectPrivate* priv;
+};
+
+struct _WebKitWebPageAccessibilityObjectClass {
+    AtkPlugClass parentClass;
+};
+
+GType webkit_web_page_accessibility_object_get_type();
+
+AtkObject* webkitWebPageAccessibilityObjectNew(WebKit::WebPage*);
+
+G_END_DECLS
+
+#endif // ENABLE(ACCESSIBILITY)
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp
--- webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp	2023-03-08 00:53:12.550624400 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp	2023-03-09 13:29:01.763353832 -0600
@@ -29,6 +29,7 @@
 #include "EditorState.h"
 #include "InputMethodState.h"
 #include "UserMessage.h"
+#include "WebKitWebPageAccessibilityObject.h"
 #include "WebKitUserMessage.h"
 #include "WebKitWebPagePrivate.h"
 #include "WebPageProxyMessages.h"
@@ -55,11 +56,35 @@ using namespace WebCore;
 
 void WebPage::platformInitialize(const WebPageCreationParameters&)
 {
-#if USE(ATSPI)
+#if ENABLE(ACCESSIBILITY)
     // Create the accessible object (the plug) that will serve as the
     // entry point to the Web process, and send a message to the UI
     // process to connect the two worlds through the accessibility
     // object there specifically placed for that purpose (the socket).
+#if USE(ATK)
+    auto isValidPlugID = [](const char* plugID) -> bool {
+        if (!plugID || plugID[0] != ':')
+            return false;
+
+        auto* p = g_strrstr(plugID, ":");
+        if (!p)
+            return false;
+
+        if (!g_variant_is_object_path(p + 1))
+            return false;
+
+        GUniquePtr<char> name(g_strndup(plugID, p - plugID));
+        if (!g_dbus_is_unique_name(name.get()))
+            return false;
+
+        return true;
+    };
+
+    m_accessibilityObject = adoptGRef(webkitWebPageAccessibilityObjectNew(this));
+    GUniquePtr<gchar> plugID(atk_plug_get_id(ATK_PLUG(m_accessibilityObject.get())));
+    if (isValidPlugID(plugID.get()))
+        send(Messages::WebPageProxy::BindAccessibilityTree(String::fromLatin1(plugID.get())));
+#elif USE(ATSPI)
 #if PLATFORM(GTK) && USE(GTK4)
     // FIXME: we need a way to connect DOM and app a11y tree in GTK4.
 #else
@@ -72,6 +97,7 @@ void WebPage::platformInitialize(const W
     }
 #endif
 #endif
+#endif
 }
 
 void WebPage::platformDetach()
diff -urpN webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/WebPage.h webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/WebPage.h
--- webkitgtk-2.39.91.glib244/Source/WebKit/WebProcess/WebPage/WebPage.h	2023-03-08 00:53:12.550624400 -0600
+++ webkitgtk-2.39.91.atk/Source/WebKit/WebProcess/WebPage/WebPage.h	2023-03-09 13:26:47.294643927 -0600
@@ -112,9 +112,14 @@
 #include <wtf/WeakHashSet.h>
 #include <wtf/text/WTFString.h>
 
-#if USE(ATSPI)
+#if ENABLE(ACCESSIBILITY)
+#if USE(ATK)
+typedef struct _AtkObject AtkObject;
+#include <wtf/glib/GRefPtr.h>
+#elif USE(ATSPI)
 #include <WebCore/AccessibilityRootAtspi.h>
 #endif
+#endif
 
 #if PLATFORM(GTK)
 #include "ArgumentCodersGtk.h"
@@ -2176,9 +2181,13 @@ private:
     RetainPtr<NSDictionary> m_dataDetectionContext;
 #endif
 
-#if USE(ATSPI)
+#if ENABLE(ACCESSIBILITY)
+#if USE(ATK)
+    GRefPtr<AtkObject> m_accessibilityObject;
+#elif USE(ATSPI)
     RefPtr<WebCore::AccessibilityRootAtspi> m_accessibilityRootObject;
 #endif
+#endif
 
 #if USE(GRAPHICS_LAYER_TEXTURE_MAPPER) || USE(GRAPHICS_LAYER_WC)
     uint64_t m_nativeWindowHandle { 0 };
openSUSE Build Service is sponsored by