Title: [284367] trunk
Revision
284367
Author
[email protected]
Date
2021-10-18 05:43:12 -0700 (Mon, 18 Oct 2021)

Log Message

[GTK][a11y] Add implementation of component interface when building with ATSPI
https://bugs.webkit.org/show_bug.cgi?id=230257

Reviewed by Adrian Perez de Castro.

Source/WebCore:

* SourcesGTK.txt:
* accessibility/atspi/AccessibilityAtspiEnums.h:
* accessibility/atspi/AccessibilityObjectAtspi.cpp:
(WebCore::AccessibilityObjectAtspi::interfacesForObject):
(WebCore::AccessibilityObjectAtspi::path):
(WebCore::AccessibilityObjectAtspi::buildInterfaces const):
* accessibility/atspi/AccessibilityObjectComponentAtspi.cpp: Added.
(WebCore::AccessibilityObjectAtspi::hitTest const):
(WebCore::AccessibilityObjectAtspi::elementRect const):
(WebCore::AccessibilityObjectAtspi::focus const):
(WebCore::AccessibilityObjectAtspi::opacity const):
(WebCore::AccessibilityObjectAtspi::scrollToMakeVisible const):
(WebCore::AccessibilityObjectAtspi::scrollToPoint const):
* accessibility/atspi/AccessibilityRootAtspi.cpp:
(WebCore::AccessibilityRootAtspi::registerObject):
(WebCore::AccessibilityRootAtspi::serialize const):
(WebCore::AccessibilityRootAtspi::frameRect const):
* accessibility/atspi/AccessibilityRootAtspi.h:
* accessibility/atspi/xml/Component.xml:

Tools:

Add unit tests for component interface.

* TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
(testComponentHitTest):
(testComponentScrollTo):
(beforeAll):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (284366 => 284367)


--- trunk/Source/WebCore/ChangeLog	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/ChangeLog	2021-10-18 12:43:12 UTC (rev 284367)
@@ -1,3 +1,30 @@
+2021-10-18  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][a11y] Add implementation of component interface when building with ATSPI
+        https://bugs.webkit.org/show_bug.cgi?id=230257
+
+        Reviewed by Adrian Perez de Castro.
+
+        * SourcesGTK.txt:
+        * accessibility/atspi/AccessibilityAtspiEnums.h:
+        * accessibility/atspi/AccessibilityObjectAtspi.cpp:
+        (WebCore::AccessibilityObjectAtspi::interfacesForObject):
+        (WebCore::AccessibilityObjectAtspi::path):
+        (WebCore::AccessibilityObjectAtspi::buildInterfaces const):
+        * accessibility/atspi/AccessibilityObjectComponentAtspi.cpp: Added.
+        (WebCore::AccessibilityObjectAtspi::hitTest const):
+        (WebCore::AccessibilityObjectAtspi::elementRect const):
+        (WebCore::AccessibilityObjectAtspi::focus const):
+        (WebCore::AccessibilityObjectAtspi::opacity const):
+        (WebCore::AccessibilityObjectAtspi::scrollToMakeVisible const):
+        (WebCore::AccessibilityObjectAtspi::scrollToPoint const):
+        * accessibility/atspi/AccessibilityRootAtspi.cpp:
+        (WebCore::AccessibilityRootAtspi::registerObject):
+        (WebCore::AccessibilityRootAtspi::serialize const):
+        (WebCore::AccessibilityRootAtspi::frameRect const):
+        * accessibility/atspi/AccessibilityRootAtspi.h:
+        * accessibility/atspi/xml/Component.xml:
+
 2021-10-18  Tim Nguyen  <[email protected]>
 
         Fix mouse selection on modal <dialog> text nodes

Modified: trunk/Source/WebCore/SourcesGTK.txt (284366 => 284367)


--- trunk/Source/WebCore/SourcesGTK.txt	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/SourcesGTK.txt	2021-10-18 12:43:12 UTC (rev 284367)
@@ -41,6 +41,7 @@
 
 accessibility/atspi/AccessibilityAtspi.cpp
 accessibility/atspi/AccessibilityObjectAtspi.cpp
+accessibility/atspi/AccessibilityObjectComponentAtspi.cpp
 accessibility/atspi/AccessibilityRootAtspi.cpp
 accessibility/atspi/AXObjectCacheAtspi.cpp
 

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspiEnums.h (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspiEnums.h	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspiEnums.h	2021-10-18 12:43:12 UTC (rev 284367)
@@ -231,6 +231,33 @@
     LastDefinedRelation,
 };
 
+enum CoordinateType {
+    ScreenCoordinates,
+    WindowCoordinates,
+    ParentCoordinates,
+};
+
+enum ComponentLayer {
+    InvalidLayer,
+    BackgroundLayer,
+    CanvasLayer,
+    WidgetLayer,
+    MdiLayer,
+    PopupLayer,
+    OverlayLayer,
+    WindowLayer,
+};
+
+enum ScrollType {
+    TopLeft,
+    BottomRight,
+    TopEdge,
+    BottomEdge,
+    LeftEdge,
+    RightEdge,
+    Anywhere
+};
+
 } // namespace Atspi
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp	2021-10-18 12:43:12 UTC (rev 284367)
@@ -41,7 +41,7 @@
 
 OptionSet<AccessibilityObjectAtspi::Interface> AccessibilityObjectAtspi::interfacesForObject(AXCoreObject& coreObject)
 {
-    OptionSet<Interface> interfaces = { Interface::Accessible };
+    OptionSet<Interface> interfaces = { Interface::Accessible, Interface::Component };
 
     return interfaces;
 }
@@ -425,6 +425,8 @@
         Vector<std::pair<GDBusInterfaceInfo*, GDBusInterfaceVTable*>> interfaces;
         if (m_interfaces.contains(Interface::Accessible))
             interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_accessible_interface), &s_accessibleFunctions });
+        if (m_interfaces.contains(Interface::Component))
+            interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_component_interface), &s_componentFunctions });
         m_path = atspiRoot->atspi().registerObject(*this, WTFMove(interfaces));
     }
 
@@ -1036,6 +1038,8 @@
     RELEASE_ASSERT(!isMainThread());
     if (m_interfaces.contains(Interface::Accessible))
         g_variant_builder_add(builder, "s", webkit_accessible_interface.name);
+    if (m_interfaces.contains(Interface::Component))
+        g_variant_builder_add(builder, "s", webkit_component_interface.name);
 }
 
 void AccessibilityObjectAtspi::serialize(GVariantBuilder* builder) const

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h	2021-10-18 12:43:12 UTC (rev 284367)
@@ -22,6 +22,7 @@
 #if ENABLE(ACCESSIBILITY) && USE(ATSPI)
 #include "AccessibilityAtspi.h"
 #include "AccessibilityObjectInterface.h"
+#include "IntRect.h"
 #include <wtf/Atomics.h>
 #include <wtf/Lock.h>
 #include <wtf/OptionSet.h>
@@ -42,7 +43,8 @@
     ~AccessibilityObjectAtspi() = default;
 
     enum class Interface : uint8_t {
-        Accessible = 1 << 0
+        Accessible = 1 << 0,
+        Component = 1 << 1
     };
     const OptionSet<Interface>& interfaces() const { return m_interfaces; }
 
@@ -75,6 +77,11 @@
     HashMap<String, String> attributes() const;
     HashMap<uint32_t, Vector<RefPtr<AccessibilityObjectAtspi>>> relationMap() const;
 
+    AccessibilityObjectAtspi* hitTest(const IntPoint&, uint32_t) const;
+    IntRect elementRect(uint32_t) const;
+    void scrollToMakeVisible(uint32_t) const;
+    void scrollToPoint(const IntPoint&, uint32_t) const;
+
 private:
     explicit AccessibilityObjectAtspi(AXCoreObject*);
 
@@ -89,9 +96,13 @@
     void buildRelationSet(GVariantBuilder*) const;
     void buildInterfaces(GVariantBuilder*) const;
 
+    bool focus() const;
+    float opacity() const;
+
     static OptionSet<Interface> interfacesForObject(AXCoreObject&);
 
     static GDBusInterfaceVTable s_accessibleFunctions;
+    static GDBusInterfaceVTable s_componentFunctions;
 
     AXCoreObject* m_axObject { nullptr };
     AXCoreObject* m_coreObject { nullptr };

Added: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectComponentAtspi.cpp (0 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectComponentAtspi.cpp	                        (rev 0)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectComponentAtspi.cpp	2021-10-18 12:43:12 UTC (rev 284367)
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 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 "AccessibilityObjectAtspi.h"
+
+#if ENABLE(ACCESSIBILITY) && USE(ATSPI)
+#include "AXIsolatedObject.h"
+#include "AccessibilityAtspiEnums.h"
+#include "AccessibilityObjectInterface.h"
+#include "Document.h"
+#include "FrameView.h"
+#include "RenderLayer.h"
+
+namespace WebCore {
+
+GDBusInterfaceVTable AccessibilityObjectAtspi::s_componentFunctions = {
+    // method_call
+    [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData) {
+        RELEASE_ASSERT(!isMainThread());
+        auto atspiObject = Ref { *static_cast<AccessibilityObjectAtspi*>(userData) };
+        atspiObject->updateBackingStore();
+
+        if (!g_strcmp0(methodName, "Contains")) {
+            int x, y;
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(iiu)", &x, &y, &coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", !!atspiObject->hitTest({ x, y }, coordinateType)));
+        } else if (!g_strcmp0(methodName, "GetAccessibleAtPoint")) {
+            int x, y;
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(iiu)", &x, &y, &coordinateType);
+            auto* wrapper = atspiObject->hitTest({ x, y }, coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(@(so))", wrapper ? wrapper->reference() : atspiObject->root()->atspi().nullReference()));
+        } else if (!g_strcmp0(methodName, "GetExtents")) {
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(u)", &coordinateType);
+            auto rect = atspiObject->elementRect(coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("((iiii))", rect.x(), rect.y(), rect.width(), rect.height()));
+        } else if (!g_strcmp0(methodName, "GetPosition")) {
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(u)", &coordinateType);
+            auto rect = atspiObject->elementRect(coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(ii)", rect.x(), rect.y()));
+        } else if (!g_strcmp0(methodName, "GetSize")) {
+            auto rect = atspiObject->elementRect(Atspi::CoordinateType::ParentCoordinates);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(ii)", rect.width(), rect.height()));
+        } else if (!g_strcmp0(methodName, "GetLayer"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", Atspi::ComponentLayer::WidgetLayer));
+        else if (!g_strcmp0(methodName, "GetMDIZOrder"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(n)", 0));
+        else if (!g_strcmp0(methodName, "GrabFocus"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", atspiObject->focus()));
+        else if (!g_strcmp0(methodName, "GetAlpha"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(d)", atspiObject->opacity()));
+        else if (!g_strcmp0(methodName, "ScrollTo")) {
+            uint32_t scrollType;
+            g_variant_get(parameters, "(u)", &scrollType);
+            atspiObject->scrollToMakeVisible(scrollType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", TRUE));
+        } else if (!g_strcmp0(methodName, "ScrollToPoint")) {
+            int x, y;
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(uii)", &coordinateType, &x, &y);
+            atspiObject->scrollToPoint({ x, y }, coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", TRUE));
+        } else if (!g_strcmp0(methodName, "SetExtents") || !g_strcmp0(methodName, "SetPosition") || !g_strcmp0(methodName, "SetSize"))
+            g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+    },
+    // get_property
+    nullptr,
+    // set_property,
+    nullptr,
+    // padding
+    nullptr
+};
+
+AccessibilityObjectAtspi* AccessibilityObjectAtspi::hitTest(const IntPoint& point, uint32_t coordinateType) const
+{
+    return Accessibility::retrieveValueFromMainThread<AccessibilityObjectAtspi*>([this, &point, coordinateType]() -> AccessibilityObjectAtspi* {
+        if (m_coreObject)
+            m_coreObject->updateBackingStore();
+
+        if (!m_coreObject)
+            return nullptr;
+
+        IntPoint convertedPoint = point;
+        if (auto* frameView = m_coreObject->documentFrameView()) {
+            switch (coordinateType) {
+            case Atspi::CoordinateType::ScreenCoordinates:
+                convertedPoint = frameView->screenToContents(point);
+                break;
+            case Atspi::CoordinateType::WindowCoordinates:
+                convertedPoint = frameView->windowToContents(point);
+                break;
+            case Atspi::CoordinateType::ParentCoordinates:
+                break;
+            }
+        }
+
+        m_coreObject->updateChildrenIfNecessary();
+        if (auto* coreObject = m_coreObject->accessibilityHitTest(convertedPoint))
+            return coreObject->wrapper();
+
+        return nullptr;
+    });
+}
+
+IntRect AccessibilityObjectAtspi::elementRect(uint32_t coordinateType) const
+{
+    return Accessibility::retrieveValueFromMainThread<IntRect>([this, coordinateType]() -> IntRect {
+        if (m_coreObject)
+            m_coreObject->updateBackingStore();
+
+        if (!m_coreObject)
+            return { };
+
+        auto rect = snappedIntRect(m_coreObject->elementRect());
+        auto* frameView = m_coreObject->documentFrameView();
+        if (!frameView)
+            return rect;
+
+        switch (coordinateType) {
+        case Atspi::CoordinateType::ScreenCoordinates:
+            return frameView->contentsToScreen(rect);
+        case Atspi::CoordinateType::WindowCoordinates:
+            return frameView->contentsToWindow(rect);
+        case Atspi::CoordinateType::ParentCoordinates:
+            return rect;
+        }
+
+        RELEASE_ASSERT_NOT_REACHED();
+    });
+}
+
+bool AccessibilityObjectAtspi::focus() const
+{
+    if (!m_axObject)
+        return false;
+
+    m_axObject->setFocused(true);
+    m_axObject->updateBackingStore();
+    return m_axObject->isFocused();
+}
+
+float AccessibilityObjectAtspi::opacity() const
+{
+    return Accessibility::retrieveValueFromMainThread<float>([this]() -> float {
+        if (m_coreObject)
+            m_coreObject->updateBackingStore();
+
+        if (!m_coreObject)
+            return 1;
+
+        if (auto* renderer = m_coreObject->renderer())
+            return renderer->style().opacity();
+
+        return 1;
+    });
+}
+
+void AccessibilityObjectAtspi::scrollToMakeVisible(uint32_t scrollType) const
+{
+    Accessibility::performFunctionOnMainThread([this, scrollType] {
+        if (m_coreObject)
+            m_coreObject->updateBackingStore();
+
+        if (!m_coreObject)
+            return;
+
+        ScrollAlignment alignX;
+        ScrollAlignment alignY;
+        switch (scrollType) {
+        case Atspi::ScrollType::TopLeft:
+            alignX = ScrollAlignment::alignLeftAlways;
+            alignY = ScrollAlignment::alignTopAlways;
+            break;
+        case Atspi::ScrollType::BottomRight:
+            alignX = ScrollAlignment::alignRightAlways;
+            alignY = ScrollAlignment::alignBottomAlways;
+            break;
+        case Atspi::ScrollType::TopEdge:
+        case Atspi::ScrollType::BottomEdge:
+            // Align to a particular edge is not supported, it's always the closest edge.
+            alignX = ScrollAlignment::alignCenterIfNeeded;
+            alignY = ScrollAlignment::alignToEdgeIfNeeded;
+            break;
+        case Atspi::ScrollType::LeftEdge:
+        case Atspi::ScrollType::RightEdge:
+            // Align to a particular edge is not supported, it's always the closest edge.
+            alignX = ScrollAlignment::alignToEdgeIfNeeded;
+            alignY = ScrollAlignment::alignCenterIfNeeded;
+            break;
+        case Atspi::ScrollType::Anywhere:
+            alignX = ScrollAlignment::alignCenterIfNeeded;
+            alignY = ScrollAlignment::alignCenterIfNeeded;
+            break;
+        }
+
+        m_coreObject->scrollToMakeVisible({ SelectionRevealMode::Reveal, alignX, alignY, ShouldAllowCrossOriginScrolling::Yes });
+    });
+}
+
+void AccessibilityObjectAtspi::scrollToPoint(const IntPoint& point, uint32_t coordinateType) const
+{
+    Accessibility::performFunctionOnMainThread([this, point, coordinateType] {
+        if (m_coreObject)
+            m_coreObject->updateBackingStore();
+
+        if (!m_coreObject)
+            return;
+
+        IntPoint convertedPoint(point);
+        if (coordinateType == Atspi::CoordinateType::ScreenCoordinates) {
+            if (auto* frameView = m_coreObject->documentFrameView())
+                convertedPoint = frameView->contentsToWindow(frameView->screenToContents(point));
+        }
+        m_coreObject->scrollToGlobalPoint(convertedPoint);
+    });
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(ACCESSIBILITY) && USE(ATSPI)

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.cpp (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.cpp	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.cpp	2021-10-18 12:43:12 UTC (rev 284367)
@@ -118,6 +118,7 @@
             GVariantBuilder builder = G_VARIANT_BUILDER_INIT(G_VARIANT_TYPE("as"));
 
             g_variant_builder_add(&builder, "s", webkit_accessible_interface.name);
+            g_variant_builder_add(&builder, "s", webkit_component_interface.name);
             g_dbus_method_invocation_return_value(invocation, g_variant_new("(as)", &builder));
         }
     },
@@ -156,6 +157,7 @@
     RELEASE_ASSERT(isMainThread());
     Vector<std::pair<GDBusInterfaceInfo*, GDBusInterfaceVTable*>> interfaces;
     interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_accessible_interface), &s_accessibleFunctions });
+    interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_component_interface), &s_componentFunctions });
     m_atspi.registerRoot(*this, WTFMove(interfaces), WTFMove(completionHandler));
 }
 
@@ -236,6 +238,7 @@
 
     GVariantBuilder interfaces = G_VARIANT_BUILDER_INIT(G_VARIANT_TYPE("as"));
     g_variant_builder_add(&interfaces, "s", webkit_accessible_interface.name);
+    g_variant_builder_add(&interfaces, "s", webkit_component_interface.name);
     g_variant_builder_add(builder, "@as", g_variant_new("as", &interfaces));
 
     g_variant_builder_add(builder, "s", "");
@@ -251,6 +254,72 @@
     g_variant_builder_add(builder, "@au", g_variant_builder_end(&states));
 }
 
+GDBusInterfaceVTable AccessibilityRootAtspi::s_componentFunctions = {
+    // method_call
+    [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData) {
+        RELEASE_ASSERT(!isMainThread());
+        auto& rootObject = *static_cast<AccessibilityRootAtspi*>(userData);
+        if (!g_strcmp0(methodName, "Contains"))
+            g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+        else if (!g_strcmp0(methodName, "GetAccessibleAtPoint"))
+            g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+        else if (!g_strcmp0(methodName, "GetExtents")) {
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(u)", &coordinateType);
+            auto rect = rootObject.frameRect(coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("((iiii))", rect.x(), rect.y(), rect.width(), rect.height()));
+        } else if (!g_strcmp0(methodName, "GetPosition")) {
+            uint32_t coordinateType;
+            g_variant_get(parameters, "(u)", &coordinateType);
+            auto rect = rootObject.frameRect(coordinateType);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("((ii))", rect.x(), rect.y()));
+        } else if (!g_strcmp0(methodName, "GetSize")) {
+            auto rect = rootObject.frameRect(Atspi::CoordinateType::ParentCoordinates);
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("((ii))", rect.width(), rect.height()));
+        } else if (!g_strcmp0(methodName, "GetLayer"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", Atspi::ComponentLayer::WidgetLayer));
+        else if (!g_strcmp0(methodName, "GetMDIZOrder"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(n)", 0));
+        else if (!g_strcmp0(methodName, "GrabFocus"))
+            g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+        else if (!g_strcmp0(methodName, "GetAlpha"))
+            g_dbus_method_invocation_return_value(invocation, g_variant_new("(d)", 1.0));
+        else if ((!g_strcmp0(methodName, "SetExtents")) || !g_strcmp0(methodName, "SetPosition") || !g_strcmp0(methodName, "SetSize") || !g_strcmp0(methodName, "ScrollTo") || !g_strcmp0(methodName, "ScrollToPoint"))
+            g_dbus_method_invocation_return_error_literal(invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "");
+    },
+    // get_property
+    nullptr,
+    // set_property,
+    nullptr,
+    // padding
+    nullptr
+};
+
+IntRect AccessibilityRootAtspi::frameRect(uint32_t coordinateType) const
+{
+    RELEASE_ASSERT(!isMainThread());
+    return Accessibility::retrieveValueFromMainThread<IntRect>([this, coordinateType]() -> IntRect {
+        if (!m_page)
+            return { };
+
+        auto* frameView = m_page->mainFrame().view();
+        if (!frameView)
+            return { };
+
+        auto frameRect = frameView->frameRect();
+        switch (coordinateType) {
+        case Atspi::CoordinateType::ScreenCoordinates:
+            return frameView->contentsToScreen(frameRect);
+        case Atspi::CoordinateType::WindowCoordinates:
+            return frameView->contentsToWindow(frameRect);
+        case Atspi::CoordinateType::ParentCoordinates:
+            return frameRect;
+        }
+
+        RELEASE_ASSERT_NOT_REACHED();
+    });
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(ACCESSIBILITY) && USE(ATSPI)

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.h (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.h	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityRootAtspi.h	2021-10-18 12:43:12 UTC (rev 284367)
@@ -21,6 +21,7 @@
 
 #if ENABLE(ACCESSIBILITY) && USE(ATSPI)
 #include "AccessibilityAtspi.h"
+#include "IntRect.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/WeakPtr.h>
@@ -54,7 +55,10 @@
 private:
     AccessibilityRootAtspi(Page&, AccessibilityAtspi&);
 
+    IntRect frameRect(uint32_t) const;
+
     static GDBusInterfaceVTable s_accessibleFunctions;
+    static GDBusInterfaceVTable s_componentFunctions;
 
     AccessibilityAtspi& m_atspi;
     WeakPtr<Page> m_page;

Modified: trunk/Source/WebCore/accessibility/atspi/xml/Component.xml (284366 => 284367)


--- trunk/Source/WebCore/accessibility/atspi/xml/Component.xml	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Source/WebCore/accessibility/atspi/xml/Component.xml	2021-10-18 12:43:12 UTC (rev 284367)
@@ -74,6 +74,7 @@
 
   <method name="ScrollTo">
     <arg direction="in" name="type" type="u"/>
+    <arg direction="out" type="b"/>
   </method>
 
   <method name="ScrollToPoint">
@@ -80,6 +81,7 @@
     <arg direction="in" name="type" type="u"/>
     <arg direction="in" name="x" type="i"/>
     <arg direction="in" name="y" type="i"/>
+    <arg direction="out" type="b"/>
   </method>
 
 </interface>

Modified: trunk/Tools/ChangeLog (284366 => 284367)


--- trunk/Tools/ChangeLog	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Tools/ChangeLog	2021-10-18 12:43:12 UTC (rev 284367)
@@ -1,3 +1,17 @@
+2021-10-18  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][a11y] Add implementation of component interface when building with ATSPI
+        https://bugs.webkit.org/show_bug.cgi?id=230257
+
+        Reviewed by Adrian Perez de Castro.
+
+        Add unit tests for component interface.
+
+        * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
+        (testComponentHitTest):
+        (testComponentScrollTo):
+        (beforeAll):
+
 2021-10-18  Yusuke Suzuki  <[email protected]>
 
         Remove AVOID_NATIVE_INT128_T

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp (284366 => 284367)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp	2021-10-18 12:26:37 UTC (rev 284366)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp	2021-10-18 12:43:12 UTC (rev 284367)
@@ -713,6 +713,96 @@
     events = { };
 }
 
+static void testComponentHitTest(AccessibilityTest* test, gconstpointer)
+{
+    test->showInWindow();
+    GUniquePtr<char> baseDir(g_strdup_printf("file://%s/", Test::getResourcesDir().data()));
+    test->loadHtml(
+        "<html>"
+        "  <body>"
+        "    <img style='position:absolute; left:1; top:1' src='' width=5 height=5></img>"
+        "  </body>"
+        "</html>",
+        baseDir.get());
+    test->waitUntilLoadFinished();
+
+    auto testApp = test->findTestApplication();
+    g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get()));
+
+    auto documentWeb = test->findDocumentWeb(testApp.get());
+    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
+    g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1);
+
+    auto img = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
+    g_assert_true(ATSPI_IS_COMPONENT(img.get()));
+    GUniquePtr<AtspiRect> rect(atspi_component_get_extents(ATSPI_COMPONENT(img.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_nonnull(rect.get());
+    g_assert_cmpuint(rect->x, ==, 1);
+    g_assert_cmpuint(rect->y, ==, 1);
+    g_assert_cmpuint(rect->width, ==, 5);
+    g_assert_cmpuint(rect->height, ==, 5);
+    GUniquePtr<AtspiPoint> point(atspi_component_get_position(ATSPI_COMPONENT(img.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_nonnull(point.get());
+    g_assert_cmpuint(rect->x, ==, point->x);
+    g_assert_cmpuint(rect->y, ==, point->y);
+    GUniquePtr<AtspiPoint> size(atspi_component_get_size(ATSPI_COMPONENT(img.get()), nullptr));
+    g_assert_nonnull(size.get());
+    g_assert_cmpuint(size->x, ==, rect->width);
+    g_assert_cmpuint(size->y, ==, rect->height);
+    g_assert_true(atspi_component_contains(ATSPI_COMPONENT(img.get()), rect->x, rect->y, ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_false(atspi_component_contains(ATSPI_COMPONENT(img.get()), rect->x + rect->width, rect->y + rect->height, ATSPI_COORD_TYPE_WINDOW, nullptr));
+    auto accessible = adoptGRef(atspi_component_get_accessible_at_point(ATSPI_COMPONENT(documentWeb.get()), rect->x, rect->y, ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_true(accessible.get() == img.get());
+    accessible = adoptGRef(atspi_component_get_accessible_at_point(ATSPI_COMPONENT(documentWeb.get()), rect->x + rect->width, rect->y + rect->height, ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_true(accessible.get() == documentWeb.get());
+}
+
+static void testComponentScrollTo(AccessibilityTest* test, gconstpointer)
+{
+    test->showInWindow(640, 480);
+    GUniquePtr<char> baseDir(g_strdup_printf("file://%s/", Test::getResourcesDir().data()));
+    test->loadHtml(
+        "<html>"
+        "  <body>"
+        "    <p>Top</p>"
+        "    <img src='' width=200 height=600></img>"
+        "    <p>Bottom</p>"
+        "  </body>"
+        "</html>",
+        baseDir.get());
+    test->waitUntilLoadFinished();
+
+    auto testApp = test->findTestApplication();
+    g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get()));
+
+    auto documentWeb = test->findDocumentWeb(testApp.get());
+    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
+    g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 3);
+
+    auto top = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
+    g_assert_true(ATSPI_IS_COMPONENT(top.get()));
+    GUniquePtr<AtspiPoint> topPositionBeforeScrolling(atspi_component_get_position(ATSPI_COMPONENT(top.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_cmpint(topPositionBeforeScrolling->y, >, 0);
+    g_assert_cmpint(topPositionBeforeScrolling->y, <, 480);
+
+    auto bottom = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 2, nullptr));
+    g_assert_true(ATSPI_IS_COMPONENT(bottom.get()));
+    GUniquePtr<AtspiPoint> bottomPositionBeforeScrolling(atspi_component_get_position(ATSPI_COMPONENT(bottom.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_cmpint(bottomPositionBeforeScrolling->y, >, 480);
+
+    atspi_component_scroll_to(ATSPI_COMPONENT(bottom.get()), ATSPI_SCROLL_ANYWHERE, nullptr);
+
+    GUniquePtr<AtspiPoint> topPositionAfterScrolling(atspi_component_get_position(ATSPI_COMPONENT(top.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_cmpint(topPositionAfterScrolling->y, <, 0);
+    GUniquePtr<AtspiPoint> bottomPositionAfterScrolling(atspi_component_get_position(ATSPI_COMPONENT(bottom.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_cmpint(bottomPositionAfterScrolling->y, <, 480);
+
+    atspi_component_scroll_to_point(ATSPI_COMPONENT(top.get()), ATSPI_COORD_TYPE_WINDOW, topPositionBeforeScrolling->x, topPositionBeforeScrolling->y, nullptr);
+    topPositionAfterScrolling.reset(atspi_component_get_position(ATSPI_COMPONENT(top.get()), ATSPI_COORD_TYPE_WINDOW, nullptr));
+    g_assert_cmpint(topPositionBeforeScrolling->x, ==, topPositionAfterScrolling->x);
+    g_assert_cmpint(topPositionBeforeScrolling->y, ==, topPositionAfterScrolling->y);
+}
+
 void beforeAll()
 {
     AccessibilityTest::add("WebKitAccessibility", "accessible/basic-hierarchy", testAccessibleBasicHierarchy);
@@ -721,6 +811,8 @@
     AccessibilityTest::add("WebKitAccessibility", "accessible/attributes", testAccessibleAttributes);
     AccessibilityTest::add("WebKitAccessibility", "accessible/state", testAccessibleState);
     AccessibilityTest::add("WebKitAccessibility", "accessible/state-changed", testAccessibleStateChanged);
+    AccessibilityTest::add("WebKitAccessibility", "component/hit-test", testComponentHitTest);
+    AccessibilityTest::add("WebKitAccessibility", "component/scroll-to", testComponentScrollTo);
 }
 
 void afterAll()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to