Changeset 244212 in webkit


Ignore:
Timestamp:
Apr 12, 2019 1:46:57 AM (5 years ago)
Author:
Carlos Garcia Campos
Message:

[GTK] REGRESSION(r243860): Many tests failing
https://bugs.webkit.org/show_bug.cgi?id=196791

Reviewed by Joanmarie Diggs.

Source/WebKit:

Calling updateAccessibilityTree() on document loaded was causing a re-layout because of the backing store update
that confused all those tests. We shouldn't need to update the accessibility tree on document load, it should
happen automatically when root object is attached/detached. This patch emits children-changed::add when the root
object wrapper is attached and children-changed::remove when the root object is detached. That way ATs are
notified of the changes in the accessibility tree.

  • WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:

(WebKit::WebFrameLoaderClient::dispatchDidFinishDocumentLoad): Remove call to WebPage::updateAccessibilityTree().

  • WebProcess/WebPage/WebPage.h: Remove updateAccessibilityTree().
  • WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp:

(coreRootObjectWrapperDetachedCallback): Emit children-changed::remove.
(rootWebAreaWrapper): Helper to get the root WebArea wrapper.
(accessibilityRootObjectWrapper): Set the parent here when root object is created and emit children-changed::add.
(webkitWebPageAccessibilityObjectRefChild): Dot no set the parent here, it's now set when the root object is created.

  • WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h: Remove webkitWebPageAccessibilityObjectRefresh().
  • WebProcess/WebPage/gtk/WebPageGtk.cpp:

Tools:

Rework the accessibility unit test to use DBus for the communication with the server. This way we can load
multiple documents and check that accessibility hierarchy is updated after a navigation.

  • TestWebKitAPI/Tests/WebKitGtk/AccessibilityTestServer.cpp:

(loadChangedCallback):

  • TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:

(AccessibilityTest::AccessibilityTest):
(AccessibilityTest::~AccessibilityTest):
(AccessibilityTest::loadHTMLAndWaitUntilFinished):
(AccessibilityTest::findTestServerApplication):
(AccessibilityTest::findDocumentWeb):
(AccessibilityTest::findRootObject):
(AccessibilityTest::waitUntilChildrenRemoved):
(AccessibilityTest::ensureProxy):
(testAtspiBasicHierarchy):
(beforeAll):
(afterAll):

LayoutTests:

Remove expectations for tests that pass now.

  • platform/gtk/TestExpectations:
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r244210 r244212  
     12019-04-11  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] REGRESSION(r243860): Many tests failing
     4        https://bugs.webkit.org/show_bug.cgi?id=196791
     5
     6        Reviewed by Joanmarie Diggs.
     7
     8        Remove expectations for tests that pass now.
     9
     10        * platform/gtk/TestExpectations:
     11
    1122019-04-11  Megan Gardner  <megan_gardner@apple.com>
    213
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r244187 r244212  
    18941894webkit.org/b/181030 wasm/iframe-postmessage.html [ Pass Failure ]
    18951895webkit.org/b/179948 [ Release ] fast/hidpi/filters-reference.html [ Pass ImageOnlyFailure ]
    1896 webkit.org/b/196791 webkit.org/b/181031 fast/frames/crash-when-iframe-is-remove-in-eventhandler.html [ Pass Crash Failure ]
     1896webkit.org/b/181031 fast/frames/crash-when-iframe-is-remove-in-eventhandler.html [ Pass Crash ]
    18971897
    18981898webkit.org/b/181528 http/tests/cache/memory-cache-pruning.html [ Pass Crash ]
     
    38183818webkit.org/b/196541 editing/pasteboard/paste-content-with-overflow-auto-parent-across-origin.html [ Failure ]
    38193819
    3820 webkit.org/b/196791 tables/mozilla/dom/deleteCol1.html [ Failure ]
    3821 webkit.org/b/196791 tables/mozilla/dom/deleteCol2.html [ Failure ]
    3822 webkit.org/b/196791 tables/mozilla/dom/deleteCol3.html [ Failure ]
    3823 webkit.org/b/196791 tables/mozilla/dom/deleteColGroup1.html [ Failure ]
    3824 webkit.org/b/196791 tables/mozilla/dom/deleteColGroup2.html [ Failure ]
    3825 webkit.org/b/196791 tables/mozilla/dom/insertColGroups1.html [ Failure ]
    3826 webkit.org/b/196791 tables/mozilla/dom/insertColGroups2.html [ Failure ]
    3827 webkit.org/b/196791 tables/mozilla/dom/insertCols1.html [ Failure ]
    3828 webkit.org/b/196791 tables/mozilla/dom/insertCols2.html [ Failure ]
    3829 webkit.org/b/196791 tables/mozilla/dom/insertCols3.html [ Failure ]
    3830 webkit.org/b/196791 tables/mozilla/dom/insertCols4.html [ Failure ]
    3831 webkit.org/b/196791 tables/mozilla/dom/insertCols5.html [ Failure ]
    3832 webkit.org/b/196791 svg/hixie/text/003.html [ Failure ]
    3833 webkit.org/b/196791 svg/custom/linking-uri-01-b.svg [ Failure ]
    3834 webkit.org/b/196791 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-width-1000px.html [ Failure ]
    3835 webkit.org/b/196791 fast/text/international/bidi-listbox-atsui.html [ Failure ]
    3836 webkit.org/b/196791 fast/text/international/bidi-innertext.html [ Failure ]
    3837 webkit.org/b/196791 fast/text/international/bidi-L2-run-reordering.html [ Failure ]
    3838 webkit.org/b/196791 fast/scrolling/scroll-animator-select-list-events.html [ Failure ]
    3839 webkit.org/b/196791 fast/scrolling/scroll-animator-overlay-scrollbars-hovered.html [ Failure ]
    3840 webkit.org/b/196791 fast/scrolling/scroll-animator-overlay-scrollbars-clicked.html [ Failure ]
    3841 webkit.org/b/196791 fast/scrolling/scroll-animator-basic-events.html [ Failure ]
    3842 webkit.org/b/196791 fast/frames/inline-object-inside-frameset.html [ Failure ]
    3843 webkit.org/b/196791 fast/forms/visual-hebrew-text-field.html [ Failure ]
    3844 webkit.org/b/196791 fast/forms/select-visual-hebrew.html [ Failure ]
    3845 webkit.org/b/196791 fast/forms/form-submission-crash-3.html [ Failure ]
    3846 webkit.org/b/196791 compositing/backing/backing-store-attachment-empty-keyframe.html [ Failure ]
    3847 webkit.org/b/196791 fast/images/animated-gif-no-layout.html [ Failure ]
    3848 webkit.org/b/196791 http/tests/incremental/stylesheet-body-incremental-rendering.html [ Failure ]
    3849 webkit.org/b/196791 http/tests/webfont/font-loading-system-fallback-visibility-FontRanges.html [ Failure ]
    3850 webkit.org/b/196791 mathml/scripts-removeChild.html [ Failure ]
    3851 webkit.org/b/196791 mathml/presentation/attributes-accent-accentunder-dynamic.html [ Failure ]
    3852 webkit.org/b/196791 mathml/presentation/menclose-notation-attribute-add.html [ Failure ]
    3853 webkit.org/b/196791 mathml/presentation/menclose-notation-attribute-change-value.html [ Failure ]
    3854 webkit.org/b/196791 mathml/presentation/menclose-notation-attribute-remove.html [ Failure ]
    3855 webkit.org/b/196791 mathml/presentation/mo-form-dynamic.html [ Failure ]
    3856 webkit.org/b/196791 mathml/presentation/mpadded-dynamic.html [ Failure ]
    3857 webkit.org/b/196791 mathml/presentation/stretchy-minsize-maxsize-dynamic.html [ Failure ]
    3858 webkit.org/b/196791 svg/custom/textPath-change-id-pattern.svg [ Failure ]
    3859 webkit.org/b/196791 svg/custom/textPath-change-id.svg [ Failure ]
    3860 webkit.org/b/196791 svg/custom/textPath-insert-path-pattern.svg [ Failure ]
    3861 webkit.org/b/196791 svg/custom/textPath-insert-path.svg [ Failure ]
    3862 
    38633820#////////////////////////////////////////////////////////////////////////////////////////
    38643821# End of non-crashing, non-flaky tests failing
  • trunk/Source/WebKit/ChangeLog

    r244205 r244212  
     12019-04-11  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] REGRESSION(r243860): Many tests failing
     4        https://bugs.webkit.org/show_bug.cgi?id=196791
     5
     6        Reviewed by Joanmarie Diggs.
     7
     8        Calling updateAccessibilityTree() on document loaded was causing a re-layout because of the backing store update
     9        that confused all those tests. We shouldn't need to update the accessibility tree on document load, it should
     10        happen automatically when root object is attached/detached. This patch emits children-changed::add when the root
     11        object wrapper is attached and children-changed::remove when the root object is detached. That way ATs are
     12        notified of the changes in the accessibility tree.
     13
     14        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
     15        (WebKit::WebFrameLoaderClient::dispatchDidFinishDocumentLoad): Remove call to WebPage::updateAccessibilityTree().
     16        * WebProcess/WebPage/WebPage.h: Remove updateAccessibilityTree().
     17        * WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp:
     18        (coreRootObjectWrapperDetachedCallback): Emit children-changed::remove.
     19        (rootWebAreaWrapper): Helper to get the root WebArea wrapper.
     20        (accessibilityRootObjectWrapper): Set the parent here when root object is created and emit children-changed::add.
     21        (webkitWebPageAccessibilityObjectRefChild): Dot no set the parent here, it's now set when the root object is created.
     22        * WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h: Remove webkitWebPageAccessibilityObjectRefresh().
     23        * WebProcess/WebPage/gtk/WebPageGtk.cpp:
     24
    1252019-04-11  Megan Gardner  <megan_gardner@apple.com>
    226
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp

    r244161 r244212  
    600600    // Notify the UIProcess.
    601601    webPage->send(Messages::WebPageProxy::DidFinishDocumentLoadForFrame(m_frame->frameID(), navigationID, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
    602 
    603 #if HAVE(ACCESSIBILITY) && PLATFORM(GTK)
    604     // Ensure the accessibility hierarchy is updated.
    605     webPage->updateAccessibilityTree();
    606 #endif
    607602}
    608603
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r244202 r244212  
    806806#endif
    807807
    808 #if HAVE(ACCESSIBILITY) && PLATFORM(GTK)
    809     void updateAccessibilityTree();
    810 #endif
    811 
    812808    void setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length, bool suppressUnderline);
    813809    bool hasCompositionForTesting();
  • trunk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.cpp

    r243928 r244212  
    3131#include "WebPage.h"
    3232#include <WebCore/AXObjectCache.h>
     33#include <WebCore/AccessibilityScrollView.h>
    3334#include <WebCore/Document.h>
    3435#include <WebCore/Frame.h>
     
    4445
    4546WEBKIT_DEFINE_TYPE(WebKitWebPageAccessibilityObject, webkit_web_page_accessibility_object, ATK_TYPE_PLUG)
     47
     48static void coreRootObjectWrapperDetachedCallback(AtkObject* wrapper, const char*, gboolean value, AtkObject* atkObject)
     49{
     50    if (!value)
     51        return;
     52
     53    g_signal_emit_by_name(atkObject, "children-changed::remove", 0, wrapper);
     54}
     55
     56static AccessibilityObjectWrapper* rootWebAreaWrapper(AccessibilityObject& rootObject)
     57{
     58    if (!rootObject.isAccessibilityScrollView())
     59        return nullptr;
     60
     61    if (auto* webAreaObject = downcast<AccessibilityScrollView>(rootObject).webAreaObject())
     62        return webAreaObject->wrapper();
     63
     64    return nullptr;
     65}
    4666
    4767static AtkObject* accessibilityRootObjectWrapper(AtkObject* atkObject)
     
    7090        return nullptr;
    7191
    72     return ATK_OBJECT(coreRootObject->wrapper());
     92    auto* wrapper = ATK_OBJECT(coreRootObject->wrapper());
     93    if (!wrapper)
     94        return nullptr;
     95
     96    if (atk_object_peek_parent(wrapper) != ATK_OBJECT(accessible)) {
     97        atk_object_set_parent(wrapper, ATK_OBJECT(accessible));
     98        g_signal_emit_by_name(accessible, "children-changed::add", 0, wrapper);
     99
     100        if (auto* webAreaWrapper = rootWebAreaWrapper(*coreRootObject)) {
     101            g_signal_connect_object(webAreaWrapper, "state-change::defunct",
     102                G_CALLBACK(coreRootObjectWrapperDetachedCallback), accessible, static_cast<GConnectFlags>(0));
     103        }
     104    }
     105
     106    return wrapper;
    73107}
    74108
     
    99133        return nullptr;
    100134
    101     AtkObject* rootObject = accessibilityRootObjectWrapper(atkObject);
    102     if (!rootObject)
    103         return nullptr;
     135    if (auto* rootObjectWrapper = accessibilityRootObjectWrapper(atkObject))
     136        return ATK_OBJECT(g_object_ref(rootObjectWrapper));
    104137
    105     atk_object_set_parent(rootObject, atkObject);
    106     g_object_ref(rootObject);
    107 
    108     return rootObject;
     138    return nullptr;
    109139}
    110140
     
    128158}
    129159
    130 void webkitWebPageAccessibilityObjectRefresh(WebKitWebPageAccessibilityObject* accessible)
    131 {
    132     // We just need to ensure that there's a connection in the ATK
    133     // world between this accessibility object and the AtkObject of
    134     // the accessibility object for the root of the DOM tree.
    135     if (auto* rootObject = accessibilityRootObjectWrapper(ATK_OBJECT(accessible)))
    136         atk_object_set_parent(rootObject, ATK_OBJECT(accessible));
    137 }
    138 
    139160#endif // HAVE(ACCESSIBILITY)
  • trunk/Source/WebKit/WebProcess/WebPage/atk/WebKitWebPageAccessibilityObject.h

    r243863 r244212  
    6161AtkObject* webkitWebPageAccessibilityObjectNew(WebKit::WebPage*);
    6262
    63 void webkitWebPageAccessibilityObjectRefresh(WebKitWebPageAccessibilityObject*);
    64 
    6563G_END_DECLS
    6664
  • trunk/Source/WebKit/WebProcess/WebPage/gtk/WebPageGtk.cpp

    r243863 r244212  
    112112}
    113113
    114 #if HAVE(ACCESSIBILITY)
    115 void WebPage::updateAccessibilityTree()
    116 {
    117     if (!m_accessibilityObject)
    118         return;
    119 
    120     webkitWebPageAccessibilityObjectRefresh(WEBKIT_WEB_PAGE_ACCESSIBILITY_OBJECT(m_accessibilityObject.get()));
    121 }
    122 #endif
    123 
    124114bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
    125115{
  • trunk/Tools/ChangeLog

    r244207 r244212  
     12019-04-11  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] REGRESSION(r243860): Many tests failing
     4        https://bugs.webkit.org/show_bug.cgi?id=196791
     5
     6        Reviewed by Joanmarie Diggs.
     7
     8        Rework the accessibility unit test to use DBus for the communication with the server. This way we can load
     9        multiple documents and check that accessibility hierarchy is updated after a navigation.
     10
     11        * TestWebKitAPI/Tests/WebKitGtk/AccessibilityTestServer.cpp:
     12        (loadChangedCallback):
     13        * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
     14        (AccessibilityTest::AccessibilityTest):
     15        (AccessibilityTest::~AccessibilityTest):
     16        (AccessibilityTest::loadHTMLAndWaitUntilFinished):
     17        (AccessibilityTest::findTestServerApplication):
     18        (AccessibilityTest::findDocumentWeb):
     19        (AccessibilityTest::findRootObject):
     20        (AccessibilityTest::waitUntilChildrenRemoved):
     21        (AccessibilityTest::ensureProxy):
     22        (testAtspiBasicHierarchy):
     23        (beforeAll):
     24        (afterAll):
     25
    1262019-04-11  Aakash Jain  <aakash_jain@apple.com>
    227
  • trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/AccessibilityTestServer.cpp

    r161366 r244212  
    11/*
    2  * Copyright (C) 2012 Igalia S.L.
     2 * Copyright (C) 2012, 2019 Igalia S.L.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    2323#include <webkit2/webkit2.h>
    2424
    25 static void loadChangedCallback(WebKitWebView*, WebKitLoadEvent loadEvent, gpointer)
     25static const char introspectionXML[] =
     26    "<node>"
     27    " <interface name='org.webkit.gtk.AccessibilityTest'>"
     28    "  <method name='LoadHTML'>"
     29    "   <arg type='s' name='html' direction='in'/>"
     30    "   <arg type='s' name='baseURI' direction='in'/>"
     31    "  </method>"
     32    " </interface>"
     33    "</node>";
     34
     35static void loadChangedCallback(WebKitWebView* webView, WebKitLoadEvent loadEvent, GDBusMethodInvocation* invocation)
    2636{
    27     // Send a message to the parent process when we're ready.
    28     if (loadEvent == WEBKIT_LOAD_FINISHED)
    29         g_print("OK");
     37    if (loadEvent != WEBKIT_LOAD_FINISHED)
     38        return;
     39
     40    g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(loadChangedCallback), invocation);
     41    g_dbus_method_invocation_return_value(invocation, nullptr);
    3042}
     43
     44static const GDBusInterfaceVTable interfaceVirtualTable = {
     45    // methodCall
     46    [](GDBusConnection* connection, const char* sender, const char* objectPath, const char* interfaceName, const char* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData) {
     47        if (g_strcmp0(interfaceName, "org.webkit.gtk.AccessibilityTest"))
     48            return;
     49
     50        auto* webView = WEBKIT_WEB_VIEW(userData);
     51
     52        if (!g_strcmp0(methodName, "LoadHTML")) {
     53            const char* html;
     54            const char* baseURI;
     55            g_variant_get(parameters, "(&s&s)", &html, &baseURI);
     56            g_signal_connect(webView, "load-changed", G_CALLBACK(loadChangedCallback), invocation);
     57            webkit_web_view_load_html(webView, html, baseURI && *baseURI ? baseURI : nullptr);
     58        }
     59    },
     60    nullptr,
     61    nullptr,
     62    { 0, }
     63};
    3164
    3265int main(int argc, char** argv)
     
    3770    gtk_init(&argc, &argv);
    3871
    39     WebKitWebView* webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
    40     webkit_web_view_load_html(webView,
    41         "<html>"
    42         "  <body>"
    43         "   <h1>This is a test</h1>"
    44         "   <p>This is a paragraph with some plain text.</p>"
    45         "   <p>This paragraph contains <a href=\"http://www.webkitgtk.org\">a link</a> in the middle.</p>"
    46         "  </body>"
    47         "</html>",
    48         0);
     72    GtkWidget* webView = webkit_web_view_new();
    4973
    5074    GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     75    g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), nullptr);
    5176    gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(webView));
    5277    gtk_widget_show_all(window);
    5378
    54     g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), 0);
    55     g_signal_connect(webView, "load-changed", G_CALLBACK(loadChangedCallback), 0);
     79    g_bus_own_name(G_BUS_TYPE_SESSION, "org.webkit.gtk.AccessibilityTest", G_BUS_NAME_OWNER_FLAGS_NONE,
     80        [](GDBusConnection* connection, const char* name, gpointer userData) {
     81            static GDBusNodeInfo *introspectionData = nullptr;
     82            if (!introspectionData)
     83                introspectionData = g_dbus_node_info_new_for_xml(introspectionXML, nullptr);
     84
     85            g_dbus_connection_register_object(connection, "/org/webkit/gtk/AccessibilityTest", introspectionData->interfaces[0],
     86                &interfaceVirtualTable, userData, nullptr, nullptr);
     87        }, nullptr, nullptr, webView, nullptr);
    5688
    5789    gtk_main();
  • trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp

    r239772 r244212  
    11/*
    2  * Copyright (C) 2012 Igalia S.L.
     2 * Copyright (C) 2012, 2019 Igalia S.L.
    33 *
    44 * This library is free software; you can redistribute it and/or
     
    2121
    2222#include "TestMain.h"
    23 #include "WebViewTest.h"
     23#include "WebKitTestBus.h"
    2424
    2525// The libatspi headers don't use G_BEGIN_DECLS
     
    2828}
    2929
    30 #include <errno.h>
    31 #include <fcntl.h>
    32 #include <glib.h>
    33 #include <signal.h>
    34 #include <unistd.h>
    35 #include <wtf/glib/GRefPtr.h>
    36 #include <wtf/glib/GUniquePtr.h>
    37 
    38 // Name of the test server application creating the webView object.
    39 static const char* kTestServerAppName = "AccessibilityTestServer";
    40 
    41 // Max seconds to wait for the test server before inspecting it.
    42 static const int kMaxWaitForChild = 5;
    43 
    44 // The PID for the test server running, so we can kill it if needed.
    45 static GPid kChildProcessPid = 0;
    46 
    47 // Whether the child has replied and it's ready.
    48 static bool kChildIsReady = false;
    49 
    50 static void stopTestServer()
     30static WebKitTestBus* bus;
     31
     32class AccessibilityTest : public Test {
     33public:
     34    MAKE_GLIB_TEST_FIXTURE(AccessibilityTest);
     35
     36    AccessibilityTest()
     37    {
     38        GUniquePtr<char> testServerPath(g_build_filename(WEBKIT_EXEC_PATH, "TestWebKitAPI", "WebKit2Gtk", "AccessibilityTestServer", nullptr));
     39        char* args[2];
     40        args[0] = testServerPath.get();
     41        args[1] = nullptr;
     42
     43        g_assert_true(g_spawn_async(nullptr, args, nullptr, G_SPAWN_DEFAULT, nullptr, nullptr, &m_childProcessID, nullptr));
     44    }
     45
     46    ~AccessibilityTest()
     47    {
     48        if (m_childProcessID) {
     49            g_spawn_close_pid(m_childProcessID);
     50            kill(m_childProcessID, SIGTERM);
     51        }
     52    }
     53
     54    void loadHTMLAndWaitUntilFinished(const char* html, const char* baseURI)
     55    {
     56        ensureProxy();
     57
     58        GUniqueOutPtr<GError> error;
     59        GRefPtr<GVariant> result = adoptGRef(g_dbus_proxy_call_sync(m_proxy.get(), "LoadHTML",
     60            g_variant_new("(ss)", html, baseURI ? baseURI : ""), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &error.outPtr()));
     61        g_assert_no_error(error.get());
     62    }
     63
     64    GRefPtr<AtspiAccessible> findTestServerApplication()
     65    {
     66        // Only one desktop is supported by ATSPI at the moment.
     67        GRefPtr<AtspiAccessible> desktop = adoptGRef(atspi_get_desktop(0));
     68
     69        int childCount = atspi_accessible_get_child_count(desktop.get(), nullptr);
     70        for (int i = 0; i < childCount; ++i) {
     71            GRefPtr<AtspiAccessible> current = adoptGRef(atspi_accessible_get_child_at_index(desktop.get(), i, nullptr));
     72            if (!g_strcmp0(atspi_accessible_get_name(current.get(), nullptr), "AccessibilityTestServer"))
     73                return current;
     74        }
     75
     76        return 0;
     77    }
     78
     79    GRefPtr<AtspiAccessible> findDocumentWeb(AtspiAccessible* accessible)
     80    {
     81        int childCount = atspi_accessible_get_child_count(accessible, nullptr);
     82        for (int i = 0; i < childCount; ++i) {
     83            GRefPtr<AtspiAccessible> child = adoptGRef(atspi_accessible_get_child_at_index(accessible, i, nullptr));
     84            if (atspi_accessible_get_role(child.get(), nullptr) == ATSPI_ROLE_DOCUMENT_WEB)
     85                return child;
     86
     87            if (auto documentWeb = findDocumentWeb(child.get()))
     88                return documentWeb;
     89        }
     90        return nullptr;
     91    }
     92
     93    GRefPtr<AtspiAccessible> findRootObject(AtspiAccessible* application)
     94    {
     95        // Find the document web, its parent is the scroll view (WebCore root object) and its parent is
     96        // the GtkPlug (WebProcess root element).
     97        auto documentWeb = findDocumentWeb(application);
     98        if (!documentWeb)
     99            return nullptr;
     100
     101        auto parent = adoptGRef(atspi_accessible_get_parent(documentWeb.get(), nullptr));
     102        return parent ? adoptGRef(atspi_accessible_get_parent(parent.get(), nullptr)) : nullptr;
     103    }
     104
     105    void waitUntilChildrenRemoved(AtspiAccessible* accessible)
     106    {
     107        m_eventSource = accessible;
     108        GRefPtr<AtspiEventListener> listener = adoptGRef(atspi_event_listener_new(
     109            [](AtspiEvent* event, gpointer userData) {
     110                auto* test = static_cast<AccessibilityTest*>(userData);
     111                if (event->source == test->m_eventSource)
     112                    g_main_loop_quit(test->m_mainLoop.get());
     113        }, this, nullptr));
     114        atspi_event_listener_register(listener.get(), "object:children-changed:remove", nullptr);
     115        g_main_loop_run(m_mainLoop.get());
     116        m_eventSource = nullptr;
     117    }
     118
     119private:
     120    void ensureProxy()
     121    {
     122        if (m_proxy)
     123            return;
     124
     125        m_mainLoop = adoptGRef(g_main_loop_new(nullptr, FALSE));
     126        m_proxy = adoptGRef(bus->createProxy("org.webkit.gtk.AccessibilityTest", "/org/webkit/gtk/AccessibilityTest", "org.webkit.gtk.AccessibilityTest", m_mainLoop.get()));
     127    }
     128
     129    GPid m_childProcessID { 0 };
     130    GRefPtr<GDBusProxy> m_proxy;
     131    GRefPtr<GMainLoop> m_mainLoop;
     132    AtspiAccessible* m_eventSource { nullptr };
     133};
     134
     135static void testAtspiBasicHierarchy(AccessibilityTest* test, gconstpointer)
    51136{
    52     // Do nothing if there's no server running.
    53     if (!kChildProcessPid)
    54         return;
    55 
    56     g_spawn_close_pid(kChildProcessPid);
    57     kill(kChildProcessPid, SIGTERM);
    58     kChildProcessPid = 0;
    59 }
    60 
    61 static void sigAbortHandler(int sigNum)
    62 {
    63     // Just stop the test server if SIGABRT was received.
    64     stopTestServer();
    65 }
    66 
    67 static gpointer testServerMonitorThreadFunc(gpointer)
    68 {
    69     // Wait for the specified timeout to happen.
    70     g_usleep(kMaxWaitForChild * G_USEC_PER_SEC);
    71 
    72     // Kill the child process if not ready yet.
    73     if (!kChildIsReady)
    74         stopTestServer();
    75 
    76     g_thread_exit(0);
    77     return 0;
    78 }
    79 
    80 static void startTestServerMonitor()
    81 {
    82     kChildIsReady = false;
    83     g_thread_new("TestServerMonitor", testServerMonitorThreadFunc, 0);
    84 }
    85 
    86 static void startTestServer()
    87 {
    88     // Prepare argv[] for spawning the server process.
    89     GUniquePtr<char> testServerPath(g_build_filename(WEBKIT_EXEC_PATH, "TestWebKitAPI", "WebKit2Gtk", kTestServerAppName, nullptr));
    90 
    91     char* testServerArgv[2];
    92     testServerArgv[0] = testServerPath.get();
    93     testServerArgv[1] = 0;
    94 
    95     // Spawn the server, getting its stdout file descriptor to set a
    96     // communication channel, so we know when it's ready.
    97     int childStdout = 0;
    98     if (!g_spawn_async_with_pipes(0, testServerArgv, 0, static_cast<GSpawnFlags>(0), 0, 0, &kChildProcessPid, 0, &childStdout, 0, 0)) {
    99         close(childStdout);
    100         return;
    101     }
    102 
    103     // Start monitoring the test server (in a separate thread) to
    104     // ensure we don't block on the child process more than a timeout.
    105     startTestServerMonitor();
    106 
    107     char msg[2];
    108     GIOChannel* ioChannel = g_io_channel_unix_new(childStdout);
    109     if (g_io_channel_read_chars(ioChannel, msg, 2, 0, 0) == G_IO_STATUS_NORMAL) {
    110         // Check whether the server sent a message saying it's ready
    111         // and store the result globally, so the monitor can see it.
    112         kChildIsReady = msg[0] == 'O' && msg[1] == 'K';
    113     }
    114     g_io_channel_unref(ioChannel);
    115     close(childStdout);
    116 
    117     // The timeout was reached and the server is not ready yet, so
    118     // stop it inmediately, and let the unit tests fail.
    119     if (!kChildIsReady)
    120         stopTestServer();
    121 }
    122 
    123 static void checkAtspiAccessible(AtspiAccessible* accessible, const char* targetName, AtspiRole targetRole)
    124 {
    125     g_assert_true(ATSPI_IS_ACCESSIBLE(accessible));
    126 
    127     GUniquePtr<char> name(atspi_accessible_get_name(accessible, 0));
    128     g_assert_cmpstr(targetName, ==, name.get());
    129     g_assert_cmpint(targetRole, ==, atspi_accessible_get_role(accessible, 0));
    130 }
    131 
    132 static GRefPtr<AtspiAccessible> findTestServerApplication()
    133 {
    134     // Only one desktop is supported by ATSPI at the moment.
    135     GRefPtr<AtspiAccessible> desktop = adoptGRef(atspi_get_desktop(0));
    136 
    137     // Look for the server application in the list of apps.
    138     GRefPtr<AtspiAccessible> current;
    139     int childCount = atspi_accessible_get_child_count(desktop.get(), 0);
    140     for (int i = 0; i < childCount; i++) {
    141         current = adoptGRef(atspi_accessible_get_child_at_index(desktop.get(), i, 0));
    142         if (!g_strcmp0(atspi_accessible_get_name(current.get(), 0), kTestServerAppName))
    143             return current;
    144     }
    145 
    146     return 0;
    147 }
    148 
    149 static void testAtspiBasicHierarchy(WebViewTest* test, gconstpointer)
    150 {
    151     // The test server's accessibility object (UI Process).
    152     GRefPtr<AtspiAccessible> testServerApp = findTestServerApplication();
     137    test->loadHTMLAndWaitUntilFinished(
     138        "<html>"
     139        "  <body>"
     140        "   <h1>This is a test</h1>"
     141        "   <p>This is a paragraph with some plain text.</p>"
     142        "   <p>This paragraph contains <a href=\"http://www.webkitgtk.org\">a link</a> in the middle.</p>"
     143        "  </body>"
     144        "</html>",
     145        nullptr);
     146
     147    auto testServerApp = test->findTestServerApplication();
    153148    g_assert_true(ATSPI_IS_ACCESSIBLE(testServerApp.get()));
    154     checkAtspiAccessible(testServerApp.get(), "AccessibilityTestServer", ATSPI_ROLE_APPLICATION);
    155 
    156     // The main window's accessibility object (UI Process).
    157     GRefPtr<AtspiAccessible> currentParent = testServerApp;
    158     GRefPtr<AtspiAccessible> currentChild = adoptGRef(atspi_accessible_get_child_at_index(currentParent.get(), 0, 0));
    159     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    160     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FRAME);
    161 
    162     // The WebView's accessibility object (UI Process).
    163     currentParent = currentChild;
    164     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    165     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    166     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FILLER);
    167 
    168     // The WebPage's accessibility object (Web Process).
    169     currentParent = currentChild;
    170     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    171     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    172     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_FILLER);
    173 
    174     // HTML root element's accessible element (Web Process).
    175     currentParent = currentChild;
    176     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    177     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    178 
    179     // HTML body's accessible element (Web Process).
    180     currentParent = currentChild;
    181     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    182     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    183     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_DOCUMENT_WEB);
    184 
    185     // HTML H1's accessible element (Web Process).
    186     currentParent = currentChild;
    187     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    188     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    189     checkAtspiAccessible(currentChild.get(), "This is a test", ATSPI_ROLE_HEADING);
    190 
    191     // HTML first paragraph's accessible element (Web Process).
    192     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 1, 0);
    193     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    194     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_PARAGRAPH);
    195 
    196     // HTML second paragraph's accessible element (Web Process).
    197     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 2, 0);
    198     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    199     checkAtspiAccessible(currentChild.get(), "", ATSPI_ROLE_PARAGRAPH);
    200 
    201     // HTML link's accessible element (Web Process).
    202     currentParent = currentChild;
    203     currentChild = atspi_accessible_get_child_at_index(currentParent.get(), 0, 0);
    204     g_assert_true(ATSPI_IS_ACCESSIBLE(currentChild.get()));
    205     checkAtspiAccessible(currentChild.get(), "a link", ATSPI_ROLE_LINK);
     149    GUniquePtr<char> name(atspi_accessible_get_name(testServerApp.get(), nullptr));
     150    g_assert_cmpstr(name.get(), ==, "AccessibilityTestServer");
     151    g_assert_cmpint(atspi_accessible_get_role(testServerApp.get(), nullptr), ==, ATSPI_ROLE_APPLICATION);
     152
     153    auto rootObject = test->findRootObject(testServerApp.get());
     154    g_assert_true(ATSPI_IS_ACCESSIBLE(rootObject.get()));
     155    g_assert_cmpint(atspi_accessible_get_role(rootObject.get(), nullptr), ==, ATSPI_ROLE_FILLER);
     156
     157    auto scrollView = adoptGRef(atspi_accessible_get_child_at_index(rootObject.get(), 0, nullptr));
     158    g_assert_true(ATSPI_IS_ACCESSIBLE(scrollView.get()));
     159    g_assert_cmpint(atspi_accessible_get_role(scrollView.get(), nullptr), ==, ATSPI_ROLE_SCROLL_PANE);
     160
     161    auto documentWeb = adoptGRef(atspi_accessible_get_child_at_index(scrollView.get(), 0, nullptr));
     162    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
     163    g_assert_cmpint(atspi_accessible_get_role(documentWeb.get(), nullptr), ==, ATSPI_ROLE_DOCUMENT_WEB);
     164
     165    auto h1 = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
     166    g_assert_true(ATSPI_IS_ACCESSIBLE(h1.get()));
     167    name.reset(atspi_accessible_get_name(h1.get(), nullptr));
     168    g_assert_cmpstr(name.get(), ==, "This is a test");
     169    g_assert_cmpint(atspi_accessible_get_role(h1.get(), nullptr), ==, ATSPI_ROLE_HEADING);
     170
     171    auto p1 = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 1, nullptr));
     172    g_assert_true(ATSPI_IS_ACCESSIBLE(p1.get()));
     173    g_assert_cmpint(atspi_accessible_get_role(p1.get(), nullptr), ==, ATSPI_ROLE_PARAGRAPH);
     174
     175    auto p2 = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 2, nullptr));
     176    g_assert_true(ATSPI_IS_ACCESSIBLE(p2.get()));
     177    g_assert_cmpint(atspi_accessible_get_role(p2.get(), nullptr), ==, ATSPI_ROLE_PARAGRAPH);
     178
     179    auto link = adoptGRef(atspi_accessible_get_child_at_index(p2.get(), 0, nullptr));
     180    g_assert_true(ATSPI_IS_ACCESSIBLE(link.get()));
     181    name.reset(atspi_accessible_get_name(link.get(), nullptr));
     182    g_assert_cmpstr(name.get(), ==, "a link");
     183    g_assert_cmpint(atspi_accessible_get_role(link.get(), nullptr), ==, ATSPI_ROLE_LINK);
     184
     185    test->loadHTMLAndWaitUntilFinished(
     186        "<html>"
     187        "  <body>"
     188        "   <h1>This is another test</h1>"
     189        "   <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMVwnSZnwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12P8z8DAwMDAxMDAwMDAAAANHQEDK+mmyAAAAABJRU5ErkJggg=='/>"
     190        "  </body>"
     191        "</html>",
     192        nullptr);
     193
     194    // Check that children-changed::remove is emitted on the root object on navigation,
     195    // and the a11y hierarchy is updated.
     196    test->waitUntilChildrenRemoved(rootObject.get());
     197
     198    documentWeb = test->findDocumentWeb(testServerApp.get());
     199    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
     200    g_assert_cmpint(atspi_accessible_get_role(documentWeb.get(), nullptr), ==, ATSPI_ROLE_DOCUMENT_WEB);
     201
     202    h1 = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
     203    g_assert_true(ATSPI_IS_ACCESSIBLE(h1.get()));
     204    name.reset(atspi_accessible_get_name(h1.get(), nullptr));
     205    g_assert_cmpstr(name.get(), ==, "This is another test");
     206    g_assert_cmpint(atspi_accessible_get_role(h1.get(), nullptr), ==, ATSPI_ROLE_HEADING);
     207
     208    auto section = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 1, nullptr));
     209    g_assert_true(ATSPI_IS_ACCESSIBLE(section.get()));
     210    g_assert_cmpint(atspi_accessible_get_role(section.get(), nullptr), ==, ATSPI_ROLE_SECTION);
     211
     212    auto img = adoptGRef(atspi_accessible_get_child_at_index(section.get(), 0, nullptr));
     213    g_assert_true(ATSPI_IS_ACCESSIBLE(img.get()));
     214    g_assert_cmpint(atspi_accessible_get_role(img.get(), nullptr), ==, ATSPI_ROLE_IMAGE);
    206215}
    207216
    208217void beforeAll()
    209218{
    210     // We install a handler to ensure that we kill the child process
    211     // if the parent dies because of whatever the reason is.
    212     signal(SIGABRT, sigAbortHandler);
    213 
    214     // Start the accessibility test server and load the tests.
    215     startTestServer();
    216     WebViewTest::add("WebKitAccessibility", "atspi-basic-hierarchy", testAtspiBasicHierarchy);
     219    bus = new WebKitTestBus();
     220    if (!bus->run())
     221        return;
     222
     223    AccessibilityTest::add("WebKitAccessibility", "atspi-basic-hierarchy", testAtspiBasicHierarchy);
    217224}
    218225
    219226void afterAll()
    220227{
    221     // Ensure we stop the server.
    222     stopTestServer();
    223 }
     228    delete bus;
     229}
Note: See TracChangeset for help on using the changeset viewer.