⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286055 in webkit


Ignore:
Timestamp:
Nov 19, 2021, 5:35:55 AM (5 years ago)
Author:
Carlos Garcia Campos
Message:

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

Reviewed by Adrian Perez de Castro.

Source/WebCore:

  • SourcesGTK.txt:
  • accessibility/atspi/AccessibilityAtspi.cpp:

(WebCore::AccessibilityAtspi::unregisterObject):
(WebCore::AccessibilityAtspi::registerHyperlink):

  • accessibility/atspi/AccessibilityAtspi.h:
  • accessibility/atspi/AccessibilityObjectAtspi.cpp:

(WebCore::AccessibilityObjectAtspi::interfacesForObject):
(WebCore::AccessibilityObjectAtspi::path):
(WebCore::AccessibilityObjectAtspi::hyperlinkReference):
(WebCore::AccessibilityObjectAtspi::buildInterfaces const):

  • accessibility/atspi/AccessibilityObjectAtspi.h:
  • accessibility/atspi/AccessibilityObjectHypertextAtspi.cpp: Added.

(WebCore::AccessibilityObjectAtspi::hyperlinkCount const):
(WebCore::AccessibilityObjectAtspi::hyperlink const):
(WebCore::AccessibilityObjectAtspi::hyperlinkIndex const):

  • accessibility/atspi/AccessibilityObjectTextAtspi.cpp:

(WebCore::AccessibilityObjectAtspi::characterIndex const):

Tools:

Add unit tests to check hypertext interface.

  • TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:

(testHypertextBasic):
(beforeAll):

Location:
trunk
Files:
1 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r286050 r286055  
     12021-11-19  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK][a11y] Add implementation of hypertext interface when building with ATSPI
     4        https://bugs.webkit.org/show_bug.cgi?id=232708
     5
     6        Reviewed by Adrian Perez de Castro.
     7
     8        * SourcesGTK.txt:
     9        * accessibility/atspi/AccessibilityAtspi.cpp:
     10        (WebCore::AccessibilityAtspi::unregisterObject):
     11        (WebCore::AccessibilityAtspi::registerHyperlink):
     12        * accessibility/atspi/AccessibilityAtspi.h:
     13        * accessibility/atspi/AccessibilityObjectAtspi.cpp:
     14        (WebCore::AccessibilityObjectAtspi::interfacesForObject):
     15        (WebCore::AccessibilityObjectAtspi::path):
     16        (WebCore::AccessibilityObjectAtspi::hyperlinkReference):
     17        (WebCore::AccessibilityObjectAtspi::buildInterfaces const):
     18        * accessibility/atspi/AccessibilityObjectAtspi.h:
     19        * accessibility/atspi/AccessibilityObjectHypertextAtspi.cpp: Added.
     20        (WebCore::AccessibilityObjectAtspi::hyperlinkCount const):
     21        (WebCore::AccessibilityObjectAtspi::hyperlink const):
     22        (WebCore::AccessibilityObjectAtspi::hyperlinkIndex const):
     23        * accessibility/atspi/AccessibilityObjectTextAtspi.cpp:
     24        (WebCore::AccessibilityObjectAtspi::characterIndex const):
     25
    1262021-11-19  Carlos Garcia Campos  <cgarcia@igalia.com>
    227
  • trunk/Source/WebCore/SourcesGTK.txt

    r286050 r286055  
    4444accessibility/atspi/AccessibilityObjectComponentAtspi.cpp
    4545accessibility/atspi/AccessibilityObjectHyperlinkAtspi.cpp
     46accessibility/atspi/AccessibilityObjectHypertextAtspi.cpp
    4647accessibility/atspi/AccessibilityObjectTextAtspi.cpp
    4748accessibility/atspi/AccessibilityObjectValueAtspi.cpp
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspi.cpp

    r285997 r286055  
    136136            return;
    137137
     138        if (m_atspiHyperlinks.contains(atspiObject.ptr())) {
     139            auto registeredObjects = m_atspiHyperlinks.take(atspiObject.ptr());
     140            for (auto id : registeredObjects)
     141                g_dbus_connection_unregister_object(m_connection.get(), id);
     142        }
     143
    138144        g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "StateChanged",
    139145            g_variant_new("(siiva{sv})", "defunct", TRUE, 0, g_variant_new_string("0"), nullptr), nullptr);
     
    145151            g_dbus_connection_unregister_object(m_connection.get(), id);
    146152    });
     153}
     154
     155String AccessibilityAtspi::registerHyperlink(AccessibilityObjectAtspi& atspiObject, Vector<std::pair<GDBusInterfaceInfo*, GDBusInterfaceVTable*>>&& interfaces)
     156{
     157    RELEASE_ASSERT(!isMainThread());
     158    if (!m_connection)
     159        return { };
     160
     161    String path = makeString("/org/a11y/atspi/accessible/", createCanonicalUUIDString().replace('-', '_'));
     162    Vector<unsigned, 1> registeredObjects;
     163    registeredObjects.reserveInitialCapacity(interfaces.size());
     164    for (const auto& interface : interfaces) {
     165        auto id = g_dbus_connection_register_object(m_connection.get(), path.utf8().data(), interface.first, interface.second, &atspiObject, nullptr, nullptr);
     166        registeredObjects.uncheckedAppend(id);
     167    }
     168    m_atspiHyperlinks.add(&atspiObject, WTFMove(registeredObjects));
     169
     170    return path;
    147171}
    148172
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspi.h

    r285997 r286055  
    5353    String registerObject(AccessibilityObjectAtspi&, Vector<std::pair<GDBusInterfaceInfo*, GDBusInterfaceVTable*>>&&);
    5454    void unregisterObject(AccessibilityObjectAtspi&);
     55    String registerHyperlink(AccessibilityObjectAtspi&, Vector<std::pair<GDBusInterfaceInfo*, GDBusInterfaceVTable*>>&&);
    5556
    5657    enum class ChildrenChanged { Added, Removed };
     
    7980    HashMap<AccessibilityRootAtspi*, Vector<unsigned, 2>> m_rootObjects;
    8081    HashMap<AccessibilityObjectAtspi*, Vector<unsigned, 20>> m_atspiObjects;
     82    HashMap<AccessibilityObjectAtspi*, Vector<unsigned, 20>> m_atspiHyperlinks;
    8183    unsigned m_cacheID { 0 };
    8284    HashMap<String, AccessibilityObjectAtspi*> m_cache;
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp

    r286050 r286055  
    7070    else if (!coreObject.isWebArea()) {
    7171        if (coreObject.roleValue() != AccessibilityRole::Table) {
     72            interfaces.add(Interface::Hypertext);
    7273            if ((renderer && renderer->childrenInline()) || roleIsTextType(coreObject.roleValue()) || coreObject.isMathToken())
    7374                interfaces.add(Interface::Text);
     
    481482        if (m_interfaces.contains(Interface::Hyperlink))
    482483            interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_hyperlink_interface), &s_hyperlinkFunctions });
     484        if (m_interfaces.contains(Interface::Hypertext))
     485            interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_hypertext_interface), &s_hypertextFunctions });
    483486        m_path = atspiRoot->atspi().registerObject(*this, WTFMove(interfaces));
    484487    }
     
    491494    RELEASE_ASSERT(!isMainThread());
    492495    return g_variant_new("(so)", root()->atspi().uniqueName(), path().utf8().data());
     496}
     497
     498GVariant* AccessibilityObjectAtspi::hyperlinkReference()
     499{
     500    RELEASE_ASSERT(!isMainThread());
     501    if (m_hyperlinkPath.isNull()) {
     502        path();
     503        m_hyperlinkPath = root()->atspi().registerHyperlink(*this, { { const_cast<GDBusInterfaceInfo*>(&webkit_hyperlink_interface), &s_hyperlinkFunctions } });
     504    }
     505
     506    return g_variant_new("(so)", root()->atspi().uniqueName(), m_hyperlinkPath.utf8().data());
    493507}
    494508
     
    11001114    if (m_interfaces.contains(Interface::Hyperlink))
    11011115        g_variant_builder_add(builder, "s", webkit_hyperlink_interface.name);
     1116    if (m_interfaces.contains(Interface::Hypertext))
     1117        g_variant_builder_add(builder, "s", webkit_hypertext_interface.name);
    11021118}
    11031119
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h

    r286050 r286055  
    4848        Text = 1 << 2,
    4949        Value = 1 << 3,
    50         Hyperlink = 1 << 4
     50        Hyperlink = 1 << 4,
     51        Hypertext = 1 << 5
    5152    };
    5253    const OptionSet<Interface>& interfaces() const { return m_interfaces; }
     
    6768    const String& path();
    6869    GVariant* reference();
     70    GVariant* hyperlinkReference();
    6971    void serialize(GVariantBuilder*) const;
    7072
     
    144146    int characterAtOffset(int) const;
    145147    std::optional<unsigned> characterOffset(UChar, int) const;
     148    std::optional<unsigned> characterIndex(UChar, unsigned) const;
    146149    IntRect textExtents(int, int, uint32_t) const;
    147150    int offsetAtPoint(const IntPoint&, uint32_t) const;
     
    155158    unsigned offsetInParent() const;
    156159
     160    unsigned hyperlinkCount() const;
     161    AccessibilityObjectAtspi* hyperlink(unsigned) const;
     162    std::optional<unsigned> hyperlinkIndex(unsigned) const;
     163
    157164    static OptionSet<Interface> interfacesForObject(AXCoreObject&);
    158165
     
    162169    static GDBusInterfaceVTable s_valueFunctions;
    163170    static GDBusInterfaceVTable s_hyperlinkFunctions;
     171    static GDBusInterfaceVTable s_hypertextFunctions;
    164172
    165173    AXCoreObject* m_axObject { nullptr };
     
    170178    Atomic<bool> m_isRegistered { false };
    171179    String m_path;
     180    String m_hyperlinkPath;
    172181    mutable int m_indexInParent { -1 };
    173182    mutable Lock m_rootLock;
  • trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp

    r286050 r286055  
    509509}
    510510
     511std::optional<unsigned> AccessibilityObjectAtspi::characterIndex(UChar character, unsigned offset) const
     512{
     513    auto utf16Text = text();
     514    auto utf8Text = utf16Text.utf8();
     515    if (utf8Text.isNull())
     516        return std::nullopt;
     517
     518    auto length = g_utf8_strlen(utf8Text.data(), -1);
     519    if (offset >= length)
     520        return std::nullopt;
     521
     522    auto mapping = offsetMapping(utf16Text);
     523    auto utf16Offset = UTF8OffsetToUTF16(mapping, offset);
     524    if (utf16Text[utf16Offset] != character)
     525        return std::nullopt;
     526
     527    unsigned start = 0;
     528    int index = -1;
     529    size_t position;
     530    while ((position = utf16Text.find(character, start)) != notFound) {
     531        index++;
     532        if (static_cast<unsigned>(position) == utf16Offset)
     533            break;
     534        start = position + 1;
     535    }
     536
     537    if (index == -1)
     538        return std::nullopt;
     539
     540    return index;
     541}
     542
    511543IntRect AccessibilityObjectAtspi::boundsForRange(unsigned utf16Offset, unsigned length, uint32_t coordinateType) const
    512544{
  • trunk/Tools/ChangeLog

    r286054 r286055  
     12021-11-19  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK][a11y] Add implementation of hypertext interface when building with ATSPI
     4        https://bugs.webkit.org/show_bug.cgi?id=232708
     5
     6        Reviewed by Adrian Perez de Castro.
     7
     8        Add unit tests to check hypertext interface.
     9
     10        * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
     11        (testHypertextBasic):
     12        (beforeAll):
     13
    1142021-11-19  Carlos Garcia Campos  <cgarcia@igalia.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp

    r286050 r286055  
    18181818}
    18191819
     1820static void testHypertextBasic(AccessibilityTest* test, gconstpointer)
     1821{
     1822    test->showInWindow(800, 600);
     1823    test->loadHtml(
     1824        "<html>"
     1825        "  <body>"
     1826        "    <p>This is <button>button</button> and <a href='https://www.webkitgtk.org'>link</a> in a paragraph</p>"
     1827        "  </body>"
     1828        "</html>",
     1829        nullptr);
     1830    test->waitUntilLoadFinished();
     1831
     1832    auto testApp = test->findTestApplication();
     1833    g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get()));
     1834
     1835    auto documentWeb = test->findDocumentWeb(testApp.get());
     1836    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
     1837    g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1);
     1838
     1839    auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
     1840    g_assert_true(ATSPI_IS_HYPERTEXT(p.get()));
     1841    g_assert_cmpint(atspi_hypertext_get_n_links(ATSPI_HYPERTEXT(p.get()), nullptr), ==, 2);
     1842
     1843    auto link = adoptGRef(atspi_hypertext_get_link(ATSPI_HYPERTEXT(p.get()), 0, nullptr));
     1844    g_assert_true(ATSPI_IS_HYPERLINK(link.get()));
     1845    g_assert_cmpint(atspi_hyperlink_get_n_anchors(ATSPI_HYPERLINK(link.get()), nullptr), ==, 1);
     1846    g_assert_true(atspi_hyperlink_is_valid(ATSPI_HYPERLINK(link.get()), nullptr));
     1847    g_assert_cmpint(atspi_hyperlink_get_start_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 8);
     1848#if USE(ATSPI)
     1849    g_assert_cmpint(atspi_hyperlink_get_end_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 9);
     1850#else
     1851    g_assert_cmpint(atspi_hyperlink_get_end_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 15);
     1852#endif
     1853    GUniquePtr<char> uri(atspi_hyperlink_get_uri(ATSPI_HYPERLINK(link.get()), 0, nullptr));
     1854    g_assert_cmpstr(uri.get(), ==, "");
     1855    auto button = adoptGRef(atspi_accessible_get_child_at_index(p.get(), 0, nullptr));
     1856    g_assert_true(atspi_hyperlink_get_object(ATSPI_HYPERLINK(link.get()), 0, nullptr) == button.get());
     1857
     1858    link = adoptGRef(atspi_hypertext_get_link(ATSPI_HYPERTEXT(p.get()), 1, nullptr));
     1859    g_assert_true(ATSPI_IS_HYPERLINK(link.get()));
     1860    g_assert_cmpint(atspi_hyperlink_get_n_anchors(ATSPI_HYPERLINK(link.get()), nullptr), ==, 1);
     1861    g_assert_true(atspi_hyperlink_is_valid(ATSPI_HYPERLINK(link.get()), nullptr));
     1862#if USE(ATSPI)
     1863    g_assert_cmpint(atspi_hyperlink_get_start_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 14);
     1864    g_assert_cmpint(atspi_hyperlink_get_end_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 15);
     1865#else
     1866    g_assert_cmpint(atspi_hyperlink_get_start_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 20);
     1867    g_assert_cmpint(atspi_hyperlink_get_end_index(ATSPI_HYPERLINK(link.get()), nullptr), ==, 24);
     1868#endif
     1869    uri.reset(atspi_hyperlink_get_uri(ATSPI_HYPERLINK(link.get()), 0, nullptr));
     1870    g_assert_cmpstr(uri.get(), ==, "https://www.webkitgtk.org/");
     1871    auto a = adoptGRef(atspi_accessible_get_child_at_index(p.get(), 1, nullptr));
     1872    g_assert_true(atspi_hyperlink_get_object(ATSPI_HYPERLINK(link.get()), 0, nullptr) == a.get());
     1873
     1874    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 0, nullptr), ==, -1);
     1875    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 8, nullptr), ==, 0);
     1876#if USE(ATSPI)
     1877    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 9, nullptr), ==, -1);
     1878    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 14, nullptr), ==, 1);
     1879    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 15, nullptr), ==, -1);
     1880#else
     1881    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 15, nullptr), ==, -1);
     1882    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 20, nullptr), ==, 1);
     1883    g_assert_cmpint(atspi_hypertext_get_link_index(ATSPI_HYPERTEXT(p.get()), 24, nullptr), ==, -1);
     1884#endif
     1885}
     1886
    18201887void beforeAll()
    18211888{
     
    18401907    AccessibilityTest::add("WebKitAccessibility", "value/basic", testValueBasic);
    18411908    AccessibilityTest::add("WebKitAccessibility", "hyperlink/basic", testHyperlinkBasic);
     1909    AccessibilityTest::add("WebKitAccessibility", "hypertext/basic", testHypertextBasic);
    18421910}
    18431911
Note: See TracChangeset for help on using the changeset viewer.