diff options
author | Colomban Wendling <cwendling@hypra.fr> | 2023-05-02 20:50:52 +0200 |
---|---|---|
committer | Michael Weghorn <m.weghorn@posteo.de> | 2023-05-23 18:39:08 +0200 |
commit | bd5c3582581f37513f45b518e348f443d5d57334 (patch) | |
tree | 6e9bce540afb614154d695b6e3280a198254b089 /sw | |
parent | dce8d2dbc48eb1c7597afec236dc51b4b8aede9c (diff) |
a11y: Fix returning unpaired surrogates when retrieving characters
Fix implementations of XAccessibleText's getTextAtIndex(),
getTextBeforeIndex() and getTextBehindIndex() when called with
AccessibleTextType::CHARACTER to return the whole code point rather
than an unpaired surrogate.
This is still not perfect because XAccessibleText::getCharacterCount()
will return an incorrect value (code units rather than code points),
but it fixes the most useful case of retrieving the character at e.g.
the caret offset.
This fixes the GTK3 and Windows backends as well without further
changes. Qt6 also mostly works according to Michael Weghorn, but for a
bug on Qt's side (https://bugreports.qt.io/browse/QTBUG-113438).
MacOS backend doesn't seem to be affected in the first place.
Change-Id: I53f07bcba78c6b267939257542a521b106101e96
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151303
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/CppunitTest_sw_a11y.mk | 1 | ||||
-rw-r--r-- | sw/qa/extras/accessibility/testdocuments/unicode.fodf | 135 | ||||
-rw-r--r-- | sw/qa/extras/accessibility/unicode.cxx | 102 | ||||
-rw-r--r-- | sw/source/core/access/accpara.cxx | 19 | ||||
-rw-r--r-- | sw/source/core/access/accpara.hxx | 1 |
5 files changed, 252 insertions, 6 deletions
diff --git a/sw/CppunitTest_sw_a11y.mk b/sw/CppunitTest_sw_a11y.mk index 282f580423aa..070f0e402d88 100644 --- a/sw/CppunitTest_sw_a11y.mk +++ b/sw/CppunitTest_sw_a11y.mk @@ -12,6 +12,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sw_a11y)) $(eval $(call gb_CppunitTest_add_exception_objects,sw_a11y, \ sw/qa/extras/accessibility/basics \ sw/qa/extras/accessibility/dialogs \ + sw/qa/extras/accessibility/unicode \ )) $(eval $(call gb_CppunitTest_use_libraries,sw_a11y, \ diff --git a/sw/qa/extras/accessibility/testdocuments/unicode.fodf b/sw/qa/extras/accessibility/testdocuments/unicode.fodf new file mode 100644 index 000000000000..9bdccebf03ec --- /dev/null +++ b/sw/qa/extras/accessibility/testdocuments/unicode.fodf @@ -0,0 +1,135 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2022-10-12T18:05:31.408900485</meta:creation-date><dc:date>2023-05-11T10:35:16.229411275</dc:date><meta:editing-duration>PT9M45S</meta:editing-duration><meta:editing-cycles>3</meta:editing-cycles><meta:generator>LibreOfficeDev/7.6.0.0.alpha0$Linux_X86_64 LibreOffice_project/44c4d9ba0d480c8e2f05c9400f310184efc7e40c</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="2" meta:word-count="2" meta:character-count="8" meta:non-whitespace-character-count="8"/></office:meta> + <office:font-face-decls> + <style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="FreeSans1" svg:font-family="FreeSans" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Quivira" svg:font-family="Quivira" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="fr" fo:country="FR" style:letter-kerning="true" style:font-name-asian="DejaVu Sans" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="FreeSans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="fr" fo:country="FR" style:letter-kerning="true" style:font-name-asian="DejaVu Sans" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="FreeSans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" loext:num-list-format="%1%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" loext:num-list-format="%2%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" loext:num-list-format="%3%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" loext:num-list-format="%4%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" loext:num-list-format="%5%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" loext:num-list-format="%6%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" loext:num-list-format="%7%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" loext:num-list-format="%8%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" loext:num-list-format="%9%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" loext:num-list-format="%10%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + <loext:theme loext:name="Office Theme"> + <loext:color-table loext:name="LibreOffice"> + <loext:color loext:name="dk1" loext:color="#000000"/> + <loext:color loext:name="lt1" loext:color="#ffffff"/> + <loext:color loext:name="dk2" loext:color="#000000"/> + <loext:color loext:name="lt2" loext:color="#ffffff"/> + <loext:color loext:name="accent1" loext:color="#18a303"/> + <loext:color loext:name="accent2" loext:color="#0369a3"/> + <loext:color loext:name="accent3" loext:color="#a33e03"/> + <loext:color loext:name="accent4" loext:color="#8e03a3"/> + <loext:color loext:name="accent5" loext:color="#c99c00"/> + <loext:color loext:name="accent6" loext:color="#c9211e"/> + <loext:color loext:name="hlink" loext:color="#0000ee"/> + <loext:color loext:name="folHlink" loext:color="#551a8b"/> + </loext:color-table> + </loext:theme> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties style:font-name="Quivira" fo:font-size="24pt" style:font-name-asian="Quivira" style:font-size-asian="24pt" style:font-name-complex="Quivira" style:font-size-complex="24pt"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties style:font-name="Quivira" fo:font-size="24pt" style:font-name-asian="Quivira" style:font-size-asian="24pt" style:font-name-complex="Quivira" style:font-size-complex="24pt"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="full"/> + </style:style> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="P1">🂡🂮🂬🂫</text:p> + <text:p text:style-name="P2">akcj</text:p> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/accessibility/unicode.cxx b/sw/qa/extras/accessibility/unicode.cxx new file mode 100644 index 000000000000..b4b2b5f6fc84 --- /dev/null +++ b/sw/qa/extras/accessibility/unicode.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/XAccessibleText.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + +#include <test/a11y/swaccessibletestbase.hxx> + +using namespace css; +using namespace accessibility; + +// Checks fetching multi-unit characters +CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestUnicodeSP) +{ + loadFromSrc(u"/sw/qa/extras/accessibility/testdocuments/unicode.fodf"); + + auto xContext = getDocumentAccessibleContext()->getAccessibleChild(0)->getAccessibleContext(); + + uno::Reference<XAccessibleText> para(xContext, uno::UNO_QUERY_THROW); + auto segment = para->getTextAtIndex(0, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u"\U0001f0a1"), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), segment.SegmentEnd); + + segment = para->getTextBeforeIndex(2, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u"\U0001f0a1"), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), segment.SegmentEnd); + + segment = para->getTextBehindIndex(0, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u"\U0001f0ae"), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4), segment.SegmentEnd); +} + +// Checks getTextBehindIndex() with multi-unit characters +CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestUnicodeSPBehindIndex) +{ + loadFromSrc(u"/sw/qa/extras/accessibility/testdocuments/unicode.fodf"); + + auto xContext = getDocumentAccessibleContext()->getAccessibleChild(0)->getAccessibleContext(); + + uno::Reference<XAccessibleText> para(xContext, uno::UNO_QUERY_THROW); + auto nChCount = para->getCharacterCount(); + + // verify bounds are properly handled + CPPUNIT_ASSERT_THROW(para->getTextBehindIndex(-1, AccessibleTextType::CHARACTER), + lang::IndexOutOfBoundsException); + CPPUNIT_ASSERT_THROW(para->getTextBehindIndex(nChCount + 1, AccessibleTextType::CHARACTER), + lang::IndexOutOfBoundsException); + + auto segment = para->getTextBehindIndex(nChCount, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u""), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentEnd); + + segment = para->getTextBehindIndex(nChCount - 2, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u""), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentEnd); + + segment = para->getTextBehindIndex(nChCount - 4, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u"\U0001f0ab"), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(6), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), segment.SegmentEnd); + + // verify bounds behave the same with single unit characters, just as a validation + xContext = getNextFlowingSibling(xContext); + CPPUNIT_ASSERT(xContext.is()); + para.set(xContext, uno::UNO_QUERY_THROW); + + nChCount = para->getCharacterCount(); + + CPPUNIT_ASSERT_THROW(para->getTextBehindIndex(-1, AccessibleTextType::CHARACTER), + lang::IndexOutOfBoundsException); + CPPUNIT_ASSERT_THROW(para->getTextBehindIndex(nChCount + 1, AccessibleTextType::CHARACTER), + lang::IndexOutOfBoundsException); + + segment = para->getTextBehindIndex(nChCount, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u""), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentEnd); + + segment = para->getTextBehindIndex(nChCount - 1, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u""), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), segment.SegmentEnd); + + segment = para->getTextBehindIndex(nChCount - 2, AccessibleTextType::CHARACTER); + CPPUNIT_ASSERT_EQUAL(OUString(u"j"), segment.SegmentText); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), segment.SegmentStart); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4), segment.SegmentEnd); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx index d00a49d10227..05bbacfbbd2a 100644 --- a/sw/source/core/access/accpara.cxx +++ b/sw/source/core/access/accpara.cxx @@ -536,13 +536,18 @@ const SwRangeRedline* SwAccessibleParagraph::GetRedlineAtIndex() bool SwAccessibleParagraph::GetCharBoundary( i18n::Boundary& rBound, + std::u16string_view text, sal_Int32 nPos ) { if( GetPortionData().FillBoundaryIFDateField( rBound, nPos) ) return true; + auto nPosEnd = nPos; + o3tl::iterateCodePoints(text, &nPosEnd); + rBound.startPos = nPos; - rBound.endPos = nPos+1; + rBound.endPos = nPosEnd; + return true; } @@ -669,7 +674,7 @@ bool SwAccessibleParagraph::GetTextBoundary( break; case AccessibleTextType::CHARACTER: - bRet = GetCharBoundary( rBound, nPos ); + bRet = GetCharBoundary( rBound, rText, nPos ); break; case AccessibleTextType::LINE: @@ -2331,8 +2336,9 @@ OUString SwAccessibleParagraph::getTextRange( i18n::Boundary preBound = aBound; while(preBound.startPos==aBound.startPos && nIndex > 0) { - nIndex = min( nIndex, preBound.startPos ) - 1; - if( nIndex < 0 ) break; + nIndex = min(nIndex, preBound.startPos); + if (nIndex <= 0) break; + rText.iterateCodePoints(&nIndex, -1); GetTextBoundary( preBound, rText, nIndex, nTextType ); } //if (nIndex>0) @@ -2349,9 +2355,10 @@ OUString SwAccessibleParagraph::getTextRange( bool bWord = false; while( !bWord ) { - nIndex = min( nIndex, aBound.startPos ) - 1; - if( nIndex >= 0 ) + nIndex = min(nIndex, aBound.startPos); + if (nIndex > 0) { + rText.iterateCodePoints(&nIndex, -1); bWord = GetTextBoundary( aBound, rText, nIndex, nTextType ); } else diff --git a/sw/source/core/access/accpara.hxx b/sw/source/core/access/accpara.hxx index eb5825b54fb9..3f6c57231d49 100644 --- a/sw/source/core/access/accpara.hxx +++ b/sw/source/core/access/accpara.hxx @@ -195,6 +195,7 @@ protected: //helpers for word boundaries bool GetCharBoundary( css::i18n::Boundary& rBound, + std::u16string_view text, sal_Int32 nPos ); bool GetWordBoundary( css::i18n::Boundary& rBound, const OUString& rText, |