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 };