include/vcl/accessibility/AccessibleTextAttributeHelper.hxx |   14 ++
 vcl/qt5/QtAccessibleWidget.cxx                              |   11 --
 vcl/source/accessibility/AccessibleTextAttributeHelper.cxx  |   61 ++++++++++++
 3 files changed, 77 insertions(+), 9 deletions(-)

New commits:
commit ec2e02cfa41510c3d30b118cbf7595c84a046d03
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Tue Oct 17 14:36:58 2023 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Wed Oct 18 12:48:57 2023 +0200

    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.wegh...@posteo.de>

diff --git a/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx 
b/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
index 5862b96a86c6..f69b7483d9e5 100644
--- a/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
+++ b/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
@@ -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;
 }
 
commit 15a6e23c4fc160c50a316da3d18980a02fc10ce8
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Tue Oct 17 14:16:54 2023 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Wed Oct 18 12:48:49 2023 +0200

    tdf#157696 qt a11y: Move handling for text attr offsets to helper
    
    Add a new method
    `AccessibleTextAttributeHelper::GetIAccessible2TextAttributes`
    and move some more of the logic from
    `QtAccessibleWidget::attributes` there to prepare adding handling
    for spelling errors via the "invalid:spelling" IAccessible2 text attribute
    and for reuse in winaccessibility.
    
    Change-Id: I3b4a89ee680437fa2c35c429639b372a55f5a4b1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158088
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/include/vcl/accessibility/AccessibleTextAttributeHelper.hxx 
b/include/vcl/accessibility/AccessibleTextAttributeHelper.hxx
index 6f8ef6dab66e..8c4b43b99e11 100644
--- a/include/vcl/accessibility/AccessibleTextAttributeHelper.hxx
+++ b/include/vcl/accessibility/AccessibleTextAttributeHelper.hxx
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
 #include <com/sun/star/beans/PropertyValue.hdl>
 #include <com/sun/star/uno/Sequence.hxx>
 #include <rtl/ustring.hxx>
@@ -34,6 +35,19 @@ public:
      */
     static OUString ConvertUnoToIAccessible2TextAttributes(
         const css::uno::Sequence<css::beans::PropertyValue>& rUnoAttributes);
+
+    /**
+     * Get the IAccessible2 text attributes and the span of the attributes at 
the given index.
+     * @param xText The interace to query for the information.
+     * @param nOffset Character offset for which to retrieve the information.
+     * @param rStartOffset Out param that is set to the start index of the 
attribute run.
+     * @param rEndOffset Out param that is set to the end index of the 
attribute run.
+     * @return IAccessible2 text attributes at the given character offset.
+     */
+    static OUString
+    
GetIAccessible2TextAttributes(css::uno::Reference<css::accessibility::XAccessibleText>
 xText,
+                                  sal_Int32 nOffset, sal_Int32& rStartOffset,
+                                  sal_Int32& rEndOffset);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx
index cd50af4aed9f..02a46147ce99 100644
--- a/vcl/qt5/QtAccessibleWidget.cxx
+++ b/vcl/qt5/QtAccessibleWidget.cxx
@@ -882,15 +882,8 @@ QString QtAccessibleWidget::attributes(int offset, int* 
startOffset, int* endOff
         return QString();
     }
 
-    const Sequence<PropertyValue> attribs
-        = xText->getCharacterAttributes(offset, Sequence<OUString>());
-    const OUString aRet
-        = 
AccessibleTextAttributeHelper::ConvertUnoToIAccessible2TextAttributes(attribs);
-
-    accessibility::TextSegment aAttributeRun
-        = xText->getTextAtIndex(offset, 
accessibility::AccessibleTextType::ATTRIBUTE_RUN);
-    *startOffset = aAttributeRun.SegmentStart;
-    *endOffset = aAttributeRun.SegmentEnd;
+    const OUString aRet = 
AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(
+        xText, offset, *startOffset, *endOffset);
     return toQString(aRet);
 }
 
diff --git a/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx 
b/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
index ccd900e9edc1..5862b96a86c6 100644
--- a/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
+++ b/vcl/source/accessibility/AccessibleTextAttributeHelper.cxx
@@ -19,6 +19,7 @@
 
 #include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
 
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
 #include <com/sun/star/awt/FontSlant.hpp>
 #include <com/sun/star/awt/FontStrikeout.hpp>
 #include <com/sun/star/awt/FontUnderline.hpp>
@@ -294,4 +295,22 @@ OUString 
AccessibleTextAttributeHelper::ConvertUnoToIAccessible2TextAttributes(
     return aRet;
 }
 
+OUString AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(
+    css::uno::Reference<css::accessibility::XAccessibleText> xText, sal_Int32 
nOffset,
+    sal_Int32& rStartOffset, sal_Int32& rEndOffset)
+{
+    assert(xText.is());
+
+    const css::uno::Sequence<css::beans::PropertyValue> attribs
+        = xText->getCharacterAttributes(nOffset, 
css::uno::Sequence<OUString>());
+    const OUString sAttributes = 
ConvertUnoToIAccessible2TextAttributes(attribs);
+
+    css::accessibility::TextSegment aAttributeRun
+        = xText->getTextAtIndex(nOffset, 
css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
+    rStartOffset = aAttributeRun.SegmentStart;
+    rEndOffset = aAttributeRun.SegmentEnd;
+
+    return sAttributes;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to