vcl/qa/cppunit/a11y/atspi2/atspi2.cxx | 40 ++++++++++++++++++-------------- vcl/qt5/QtAccessibleWidget.cxx | 3 ++ vcl/unx/gtk3/a11y/atktextattributes.cxx | 6 +++- vcl/unx/gtk4/a11y.cxx | 2 + 4 files changed, 32 insertions(+), 19 deletions(-)
New commits: commit c1cf093b1c5ccdff118c1a066e5a8e8c0470be56 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Mar 4 19:30:05 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Thu Mar 5 11:20:44 2026 +0100 a11y: Handle empty extended attributes string In the toolkit a11y bridges not doing so yet (gtk3, gtk4, qt5/qt6), handle an empty string returned by XAccessibleExtendedAttributes::getExtendedAttributes to not report any attributes. Adjust gtk3 a11y test Atspi2TestTree::compareObjects accordingly as well. This prepares for an upcoming commit that will add a default implementation to OAccessible that returns an empty string. The Windows/IAccessible2 bridge already handles an empty string just fine. The macOS one currently doesn't use XAccessibleExtendedAttributes at all. Change-Id: I84252f8764d3385d71b9ada24125ca96762baf9d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200970 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/qa/cppunit/a11y/atspi2/atspi2.cxx b/vcl/qa/cppunit/a11y/atspi2/atspi2.cxx index 13cb6e6b1318..cd7dff0ec59a 100644 --- a/vcl/qa/cppunit/a11y/atspi2/atspi2.cxx +++ b/vcl/qa/cppunit/a11y/atspi2/atspi2.cxx @@ -329,25 +329,31 @@ void Atspi2TestTree::compareObjects(const uno::Reference<accessibility::XAccessi sal_Int32 nIndex = 0; const auto atspiAttrs = pAtspiAccessible.getAttributes(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Only one of AT-SPI attributes or attributes via " + "XAccessibleExtendedAttributes are empty", + sExtendedAttrs.isEmpty(), atspiAttrs.empty()); - do + if (!sExtendedAttrs.isEmpty()) { - OUString sProperty = sExtendedAttrs.getToken(0, ';', nIndex); - - sal_Int32 nColonPos = 0; - const OString sPropertyName = OUStringToOString( - o3tl::getToken(sProperty, 0, ':', nColonPos), RTL_TEXTENCODING_UTF8); - const OString sPropertyValue = OUStringToOString( - o3tl::getToken(sProperty, 0, ':', nColonPos), RTL_TEXTENCODING_UTF8); - - const auto atspiAttrIter = atspiAttrs.find(std::string(sPropertyName)); - CPPUNIT_ASSERT_MESSAGE(std::string("Missing attribute: ") + sPropertyName.getStr(), - atspiAttrIter != atspiAttrs.end()); - CPPUNIT_ASSERT_EQUAL(std::string_view(sPropertyName), - std::string_view(atspiAttrIter->first)); - CPPUNIT_ASSERT_EQUAL(std::string_view(sPropertyValue), - std::string_view(atspiAttrIter->second)); - } while (nIndex >= 0 && nIndex < sExtendedAttrs.getLength()); + do + { + OUString sProperty = sExtendedAttrs.getToken(0, ';', nIndex); + + sal_Int32 nColonPos = 0; + const OString sPropertyName = OUStringToOString( + o3tl::getToken(sProperty, 0, ':', nColonPos), RTL_TEXTENCODING_UTF8); + const OString sPropertyValue = OUStringToOString( + o3tl::getToken(sProperty, 0, ':', nColonPos), RTL_TEXTENCODING_UTF8); + + const auto atspiAttrIter = atspiAttrs.find(std::string(sPropertyName)); + CPPUNIT_ASSERT_MESSAGE(std::string("Missing attribute: ") + sPropertyName.getStr(), + atspiAttrIter != atspiAttrs.end()); + CPPUNIT_ASSERT_EQUAL(std::string_view(sPropertyName), + std::string_view(atspiAttrIter->first)); + CPPUNIT_ASSERT_EQUAL(std::string_view(sPropertyValue), + std::string_view(atspiAttrIter->second)); + } while (nIndex >= 0 && nIndex < sExtendedAttrs.getLength()); + } } // relations diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx index ee74404091df..5914dcf9f0fc 100644 --- a/vcl/qt5/QtAccessibleWidget.cxx +++ b/vcl/qt5/QtAccessibleWidget.cxx @@ -1003,6 +1003,9 @@ QHash<QAccessible::Attribute, QVariant> QtAccessibleWidget::attributes() const return aQtAttrs; const OUString sAttrs = xAttributes->getExtendedAttributes(); + if (sAttrs.isEmpty()) + return aQtAttrs; + sal_Int32 nIndex = 0; do { diff --git a/vcl/unx/gtk3/a11y/atktextattributes.cxx b/vcl/unx/gtk3/a11y/atktextattributes.cxx index 7510c02f21c3..c1fe05ee4478 100644 --- a/vcl/unx/gtk3/a11y/atktextattributes.cxx +++ b/vcl/unx/gtk3/a11y/atktextattributes.cxx @@ -1231,11 +1231,13 @@ AtkAttributeSet* attribute_set_new_from_extended_attributes( const css::uno::Reference< css::accessibility::XAccessibleExtendedAttributes >& rExtendedAttributes ) { - AtkAttributeSet *pSet = nullptr; - // extended attributes is a string of colon-separated pairs of property and value, // with pairs separated by semicolons. Example: "heading-level:2;weight:bold;" const OUString sExtendedAttrs = rExtendedAttributes->getExtendedAttributes(); + if (sExtendedAttrs.isEmpty()) + return nullptr; + + AtkAttributeSet* pSet = nullptr; sal_Int32 nIndex = 0; do { diff --git a/vcl/unx/gtk4/a11y.cxx b/vcl/unx/gtk4/a11y.cxx index e68337caa6d7..f8c69b6c9e78 100644 --- a/vcl/unx/gtk4/a11y.cxx +++ b/vcl/unx/gtk4/a11y.cxx @@ -376,6 +376,8 @@ applyObjectAttributes(GtkAccessible* pGtkAccessible, return; const OUString sAttrs = xAttributes->getExtendedAttributes(); + if (sAttrs.isEmpty()) + return; sal_Int32 nIndex = 0; do
