tdf#157696 a11y: Report spelling error via IA2 "invalid:spelling" attr

Let `AccessibleTextAttributeHelper::GetIAccessible2TextAttributes`
also report spelling errors as a text attribute, since the
"invalid:" text attribute with a value of "spelling" is specified
for that in the IAccessible2 tex attributes specification [1].

In order to adapt the start/end index for the attribute run,
iterate over all of the text markups that can be retrieved from
the `XAccessibleTextMarkup` interface instead of just deterining
whether the offset itself lies within a range of misspelled text
via `XAccessibleTextMarkup::getTextMarkupAtIndex`.
(This is strongly inspired by how the gtk3 a11y implementation
does it, s. `handle_text_markup_as_run_attribute` in
vcl/unx/gtk3/a11y/atktext.cxx.)

When using the qt6 VCL plugin on Linux, the attribute shows up as
expected in Accerciser and the Orca screen reader announces
"misspelled" when moving the cursor in front of a misspelled
word using the Arrow_Right key.

Announcement by NVDA works once winaccessibility and NVDA
have been switched over to use IAccessible2 text attributes
instead of custom LibreOffice ones.

[1] https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes

Change-Id: I54e5bcbb4bef4c73068243f91a3ee69c10326460
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158089
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
Michael Weghorn
2023-10-17 14:36:58 +02:00
parent 15a6e23c4f
commit ec2e02cfa4

View File

@@ -20,10 +20,12 @@
#include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
#include <com/sun/star/accessibility/AccessibleTextType.hpp>
#include <com/sun/star/accessibility/XAccessibleTextMarkup.hpp>
#include <com/sun/star/awt/FontSlant.hpp>
#include <com/sun/star/awt/FontStrikeout.hpp>
#include <com/sun/star/awt/FontUnderline.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/text/TextMarkupType.hpp>
#include <o3tl/any.hxx>
#include <tools/color.hxx>
@@ -303,13 +305,53 @@ OUString AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(
const css::uno::Sequence<css::beans::PropertyValue> attribs
= xText->getCharacterAttributes(nOffset, css::uno::Sequence<OUString>());
const OUString sAttributes = ConvertUnoToIAccessible2TextAttributes(attribs);
OUString sAttributes = ConvertUnoToIAccessible2TextAttributes(attribs);
css::accessibility::TextSegment aAttributeRun
= xText->getTextAtIndex(nOffset, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
rStartOffset = aAttributeRun.SegmentStart;
rEndOffset = aAttributeRun.SegmentEnd;
// report spelling error as "invalid:spelling;" IA2 text attribute and
// adapt start/end index as necessary
css::uno::Reference<css::accessibility::XAccessibleTextMarkup> xTextMarkup(xText,
css::uno::UNO_QUERY);
if (xTextMarkup.is())
{
bool bInvalidSpelling = false;
const sal_Int32 nMarkupCount(
xTextMarkup->getTextMarkupCount(css::text::TextMarkupType::SPELLCHECK));
for (sal_Int32 nMarkupIndex = 0; nMarkupIndex < nMarkupCount; ++nMarkupIndex)
{
const css::accessibility::TextSegment aTextSegment
= xTextMarkup->getTextMarkup(nMarkupIndex, css::text::TextMarkupType::SPELLCHECK);
const sal_Int32 nStartOffsetTextMarkup = aTextSegment.SegmentStart;
const sal_Int32 nEndOffsetTextMarkup = aTextSegment.SegmentEnd;
if (nStartOffsetTextMarkup <= nOffset)
{
if (nOffset < nEndOffsetTextMarkup)
{
// offset is inside invalid spelling
rStartOffset = ::std::max(rStartOffset, nStartOffsetTextMarkup);
rEndOffset = ::std::min(rEndOffset, nEndOffsetTextMarkup);
bInvalidSpelling = true;
break;
}
else
{
rStartOffset = ::std::max(rStartOffset, nEndOffsetTextMarkup);
}
}
else
{
rEndOffset = ::std::min(rEndOffset, nStartOffsetTextMarkup);
}
}
if (bInvalidSpelling)
sAttributes += u"invalid:spelling;"_ustr;
}
return sAttributes;
}