diff options
author | Michael Weghorn <m.weghorn@posteo.de> | 2024-02-22 11:58:08 +0100 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2024-02-22 15:20:36 +0100 |
commit | e268efd612d12ae9a459d6b9d0cb23220f025163 (patch) | |
tree | 2e8ef2ff5e0a6668ee0c6f2462a56024fb4dabe2 /vcl/unx | |
parent | 56e5c2c35d8febb17decaae1d526d3c98ae08f09 (diff) |
gtk4 a11y: Implement new GtkAccessibleTextInterface
Implement most of the methods of the
`GtkAccessibleInterface` newly added to Gtk 4 in
Gtk commit [1]
commit 0ca8d74842837b1ad5dc42c1fcff8b1270e5750b
Author: Matthias Clasen <mclasen@redhat.com>
Date: Tue Feb 20 12:18:27 2024 -0500
a11y: Add GtkAccessibleText interface
The AccessibleText interface is meant to be implemented by widgets and
other accessible objects that expose selectable, navigatable, or rich
text to assistive technologies.
This kind of text is not covered by the plain accessible name and
description, as it contains things like a caret, or text attributes.
This commit adds a stub GtkAccessibleText with its basic virtual
functions; the interface will be implemented by widgets like GtkLabel,
GtkInscription, GtkText, and GtkTextView. A further commit will ensure
that the AT-SPI implementation will convert from GTK to AT-SPI through a
generic (internal API); and, finally, we'll remove the widget type
checks in the AT-SPI implementation of GtkATContext, and only check for
GtkAccessibleText.
Fixes: #5912
and follow-up commits. The `css::accessibility::XAccessibleText`
interface provides the required functionality.
With a Writer paragraph consisting of the text
"Hello world. And another sentence."
and the word "world" selected, using some of the AT-SPI Text
interface methods via Accerciser's IPython console behaves as expected
now when the paragraph's a11y object is selected in Accerciser's
treeview:
In [9]: text = acc.queryText()
In [10]: text.get_caretOffset()
Out[10]: 11
In [11]: text.getText(0, -1)
Out[11]: 'Hello world. And another sentence.'
In [12]: text.getText(2,5)
Out[12]: 'llo'
In [13]: text.getStringAtOffset(10, pyatspi.TEXT_GRANULARITY_CHAR)
Out[13]: ('d', 10, 11)
In [14]: text.getStringAtOffset(10, pyatspi.TEXT_GRANULARITY_WORD)
Out[14]: ('world', 6, 11)
In [15]: text.getStringAtOffset(10, pyatspi.TEXT_GRANULARITY_SENTENCE)
Out[15]: ('Hello world. ', 0, 13)
In [16]: text.getStringAtOffset(10, pyatspi.TEXT_GRANULARITY_PARAGRAPH)
Out[16]: ('Hello world. And another sentence.', 0, 34)
In [17]: text.getNSelections()
Out[17]: 1
In [18]: text.getSelection(0)
Out[18]: (6, 11)
Actual handling of text attributes is left for later (s. TODO comment
in the newly added `lo_accessible_text_get_attributes`).
[1] https://gitlab.gnome.org/GNOME/gtk/-/commit/0ca8d74842837b1ad5dc42c1fcff8b1270e5750b
Change-Id: Icad236cd87285d9a336883e67b191f633e9e4413
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163733
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'vcl/unx')
-rw-r--r-- | vcl/unx/gtk4/a11y.cxx | 7 | ||||
-rw-r--r-- | vcl/unx/gtk4/gtkaccessibletext.cxx | 145 | ||||
-rw-r--r-- | vcl/unx/gtk4/gtkaccessibletext.hxx | 20 |
3 files changed, 171 insertions, 1 deletions
diff --git a/vcl/unx/gtk4/a11y.cxx b/vcl/unx/gtk4/a11y.cxx index 19cb941b9158..41e49bf2845b 100644 --- a/vcl/unx/gtk4/a11y.cxx +++ b/vcl/unx/gtk4/a11y.cxx @@ -23,6 +23,7 @@ #include "a11y.hxx" #include "gtkaccessibleeventlistener.hxx" #include "gtkaccessibleregistry.hxx" +#include "gtkaccessibletext.hxx" #define OOO_TYPE_FIXED (ooo_fixed_get_type()) #define OOO_FIXED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OOO_TYPE_FIXED, OOoFixed)) @@ -410,9 +411,13 @@ const struct GetGIfaceType const aGetGIfaceType; const css::uno::Type& (*aGetUnoType)(); } TYPE_TABLE[] = { +#if GTK_CHECK_VERSION(4, 13, 8) + { "Text", reinterpret_cast<GInterfaceInitFunc>(lo_accessible_text_init), + gtk_accessible_text_get_type, cppu::UnoType<css::accessibility::XAccessibleText>::get }, +#endif #if GTK_CHECK_VERSION(4, 10, 0) { "Value", reinterpret_cast<GInterfaceInitFunc>(lo_accessible_range_init), - gtk_accessible_range_get_type, cppu::UnoType<css::accessibility::XAccessibleValue>::get } + gtk_accessible_range_get_type, cppu::UnoType<css::accessibility::XAccessibleValue>::get }, #endif }; diff --git a/vcl/unx/gtk4/gtkaccessibletext.cxx b/vcl/unx/gtk4/gtkaccessibletext.cxx new file mode 100644 index 000000000000..32e1448a5f65 --- /dev/null +++ b/vcl/unx/gtk4/gtkaccessibletext.cxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/TextSegment.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <sal/log.hxx> + +#include "a11y.hxx" +#include "gtkaccessibletext.hxx" + +#if GTK_CHECK_VERSION(4, 13, 8) + +namespace +{ +sal_Int16 lcl_GtkTextGranularityToUNOBoundaryType(GtkAccessibleTextGranularity eGranularity) +{ + switch (eGranularity) + { + case GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER: + return com::sun::star::accessibility::AccessibleTextType::CHARACTER; + case GTK_ACCESSIBLE_TEXT_GRANULARITY_WORD: + return com::sun::star::accessibility::AccessibleTextType::WORD; + case GTK_ACCESSIBLE_TEXT_GRANULARITY_SENTENCE: + return com::sun::star::accessibility::AccessibleTextType::SENTENCE; + case GTK_ACCESSIBLE_TEXT_GRANULARITY_LINE: + return com::sun::star::accessibility::AccessibleTextType::LINE; + case GTK_ACCESSIBLE_TEXT_GRANULARITY_PARAGRAPH: + return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH; + default: + assert(false && "Unhandled GtkAccessibleTextGranularity."); + return GTK_ACCESSIBLE_TEXT_GRANULARITY_CHARACTER; + } +} + +css::uno::Reference<css::accessibility::XAccessibleText> getXText(GtkAccessibleText* pGtkText) +{ + LoAccessible* pAccessible = LO_ACCESSIBLE(pGtkText); + if (!pAccessible->uno_accessible) + return nullptr; + + css::uno::Reference<css::accessibility::XAccessibleContext> xContext( + pAccessible->uno_accessible->getAccessibleContext()); + + css::uno::Reference<css::accessibility::XAccessibleText> xText(xContext, css::uno::UNO_QUERY); + return xText; +} +} + +static GBytes* lo_accessible_text_get_contents(GtkAccessibleText* self, unsigned int start, + unsigned int end) +{ + css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self); + if (!xText.is()) + return nullptr; + + // G_MAXUINT has special meaning: end of the text + const sal_Int32 nEndIndex = (end == G_MAXUINT) ? xText->getCharacterCount() : end; + + const OString sText + = rtl::OUStringToOString(xText->getTextRange(start, nEndIndex), RTL_TEXTENCODING_UTF8); + return g_bytes_new(sText.getStr(), sText.getLength()); +} + +static GBytes* lo_accessible_text_get_contents_at(GtkAccessibleText* self, unsigned int offset, + GtkAccessibleTextGranularity eGranularity, + unsigned int* start, unsigned int* end) +{ + css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self); + if (!xText.is()) + return nullptr; + + if (offset < 0 || offset > o3tl::make_unsigned(xText->getCharacterCount())) + { + SAL_WARN("vcl.gtk", + "lo_accessible_text_get_contents_at called with invalid offset: " << offset); + return nullptr; + } + + const sal_Int16 nUnoBoundaryType = lcl_GtkTextGranularityToUNOBoundaryType(eGranularity); + const css::accessibility::TextSegment aSegment + = xText->getTextAtIndex(offset, nUnoBoundaryType); + *start = o3tl::make_unsigned(aSegment.SegmentStart); + *end = o3tl::make_unsigned(aSegment.SegmentEnd); + const OString sText = rtl::OUStringToOString(aSegment.SegmentText, RTL_TEXTENCODING_UTF8); + return g_bytes_new(sText.getStr(), sText.getLength()); +} + +static unsigned int lo_accessible_text_get_caret_position(GtkAccessibleText* self) +{ + css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self); + if (!xText.is()) + return 0; + + return std::max(0, xText->getCaretPosition()); +} + +static gboolean lo_accessible_text_get_selection(GtkAccessibleText* self, gsize* n_ranges, + GtkAccessibleTextRange** ranges) +{ + css::uno::Reference<css::accessibility::XAccessibleText> xText = getXText(self); + if (!xText.is()) + return 0; + + if (xText->getSelectedText().isEmpty()) + return false; + + const sal_Int32 nSelectionStart = xText->getSelectionStart(); + const sal_Int32 nSelectionEnd = xText->getSelectionEnd(); + + *n_ranges = 1; + *ranges = g_new(GtkAccessibleTextRange, 1); + (*ranges)[0].start = std::min(nSelectionStart, nSelectionEnd); + (*ranges)[0].length = std::abs(nSelectionEnd - nSelectionStart); + return true; +} + +static gboolean lo_accessible_text_get_attributes(GtkAccessibleText* /* self */, + unsigned int /* offset */, gsize* /* n_ranges */, + GtkAccessibleTextRange** /* ranges */, + char*** /* attribute_names */, + char*** /* attribute_values */) +{ + // TODO: implement + return false; +} + +void lo_accessible_text_init(GtkAccessibleTextInterface* iface) +{ + iface->get_contents = lo_accessible_text_get_contents; + iface->get_contents_at = lo_accessible_text_get_contents_at; + iface->get_caret_position = lo_accessible_text_get_caret_position; + iface->get_selection = lo_accessible_text_get_selection; + iface->get_attributes = lo_accessible_text_get_attributes; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk4/gtkaccessibletext.hxx b/vcl/unx/gtk4/gtkaccessibletext.hxx new file mode 100644 index 000000000000..3e8a08db0d73 --- /dev/null +++ b/vcl/unx/gtk4/gtkaccessibletext.hxx @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <gtk/gtk.h> + +#if GTK_CHECK_VERSION(4, 13, 8) + +void lo_accessible_text_init(GtkAccessibleTextInterface* iface); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |