summaryrefslogtreecommitdiffstats
path: root/sw/qa/extras/accessibility
diff options
context:
space:
mode:
Diffstat (limited to 'sw/qa/extras/accessibility')
-rw-r--r--sw/qa/extras/accessibility/accessible_relation_set.cxx204
-rw-r--r--sw/qa/extras/accessibility/basics.cxx96
-rw-r--r--sw/qa/extras/accessibility/dialogs.cxx199
-rw-r--r--sw/qa/extras/accessibility/tdf155705.cxx57
-rw-r--r--sw/qa/extras/accessibility/testdocuments/tdf155705.fodt130
-rw-r--r--sw/qa/extras/accessibility/testdocuments/unicode.fodf135
-rw-r--r--sw/qa/extras/accessibility/unicode.cxx102
7 files changed, 923 insertions, 0 deletions
diff --git a/sw/qa/extras/accessibility/accessible_relation_set.cxx b/sw/qa/extras/accessibility/accessible_relation_set.cxx
new file mode 100644
index 0000000000..fcee6d965a
--- /dev/null
+++ b/sw/qa/extras/accessibility/accessible_relation_set.cxx
@@ -0,0 +1,204 @@
+/* -*- 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/
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <test/unoapi_test.hxx>
+
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
+
+#include <test/a11y/AccessibilityTools.hxx>
+
+using namespace com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::accessibility;
+using namespace css::lang;
+
+class AccessibleRelationSet : public UnoApiTest
+{
+public:
+ AccessibleRelationSet()
+ : UnoApiTest("")
+ {
+ }
+
+ void init(uno::Reference<css::accessibility::XAccessible>& para1,
+ uno::Reference<css::accessibility::XAccessible>& para2,
+ uno::Reference<css::accessibility::XAccessible>& para3);
+ void contents_flows_to_and_from();
+
+ CPPUNIT_TEST_SUITE(AccessibleRelationSet);
+ CPPUNIT_TEST(contents_flows_to_and_from);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void AccessibleRelationSet::init(uno::Reference<css::accessibility::XAccessible>& para1,
+ uno::Reference<css::accessibility::XAccessible>& para2,
+ uno::Reference<css::accessibility::XAccessible>& para3)
+{
+ mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+ uno::Reference<text::XTextDocument> xTextDoc(mxComponent, uno::UNO_QUERY);
+
+ css::uno::Reference<text::XText> oText(xTextDoc->getText(), uno::UNO_SET_THROW);
+
+ css::uno::Reference<text::XTextCursor> oCursor = oText->createTextCursor();
+
+ for (int i = 0; i < 5; i++)
+ {
+ oText->insertString(oCursor, "Paragraph Number: " + OUString::number(i), false);
+ oText->insertControlCharacter(oCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
+ }
+
+ css::uno::Reference<css::frame::XModel> aModel(xTextDoc, uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::frame::XController> xController(aModel->getCurrentController());
+
+ css::uno::Reference<css::accessibility::XAccessibleContext> ctx;
+ uno::Reference<frame::XFrame> xFrame(xController->getFrame(), uno::UNO_SET_THROW);
+ uno::Reference<awt::XWindow> xWindow(xFrame->getComponentWindow(), uno::UNO_SET_THROW);
+
+ css::uno::Reference<css::accessibility::XAccessible> xRoot(xWindow, uno::UNO_QUERY_THROW);
+ ctx = AccessibilityTools::getAccessibleObjectForRole(xRoot, AccessibleRole::DOCUMENT_TEXT);
+ CPPUNIT_ASSERT_MESSAGE("Couldn't get AccessibleRole.DOCUMENT_TEXT object", ctx.is());
+ para1 = ctx->getAccessibleChild(0);
+ para2 = ctx->getAccessibleChild(1);
+ para3 = ctx->getAccessibleChild(2);
+}
+
+void AccessibleRelationSet::contents_flows_to_and_from()
+{
+ //contents_flows_to
+
+ css::uno::Reference<css::accessibility::XAccessible> para1;
+ css::uno::Reference<css::accessibility::XAccessible> para2;
+ css::uno::Reference<css::accessibility::XAccessible> para3;
+
+ init(para1, para2, para3);
+ css::uno::Reference<css::accessibility::XAccessibleContext> oObj(para1, uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::accessibility::XAccessibleRelationSet> set
+ = oObj->getAccessibleRelationSet();
+
+ css::uno::Reference<css::accessibility::XAccessibleText> atarget;
+
+ if (set.is())
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct count of relations", sal_Int32(1),
+ set->getRelationCount());
+ sal_Int16 firstrelation = set->getRelation(0).RelationType;
+ css::uno::Reference<css::accessibility::XAccessibleText> adummy(
+ set->getRelation(0).TargetSet[0], uno::UNO_QUERY_THROW);
+ atarget = adummy;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct relation type for paragraph 0",
+ AccessibilityTools::getRelationTypeName(
+ accessibility::AccessibleRelationType::CONTENT_FLOWS_TO),
+ AccessibilityTools::getRelationTypeName(firstrelation));
+
+ css::uno::Reference<css::accessibility::XAccessibleText> paraText2(para2,
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct target paragraph", atarget->getText(),
+ paraText2->getText());
+ }
+
+ //contents_flows_from()
+ css::uno::Reference<css::accessibility::XAccessibleContext> oObj2(para2, uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::accessibility::XAccessibleRelationSet> set2
+ = oObj2->getAccessibleRelationSet();
+
+ sal_Int16 relationtypes[2] = { accessibility::AccessibleRelationType::INVALID,
+ accessibility::AccessibleRelationType::INVALID };
+ css::uno::Reference<css::accessibility::XAccessibleText> atargets[2];
+
+ if (set2.is())
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct count of relations", sal_Int32(2),
+ set2->getRelationCount());
+ sal_Int16 tmprelation = set2->getRelation(0).RelationType;
+ if (tmprelation == accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM)
+ {
+ css::uno::Reference<css::accessibility::XAccessibleText> adummy(
+ set2->getRelation(0).TargetSet[0], uno::UNO_QUERY_THROW);
+ atargets[0] = adummy;
+ relationtypes[0] = tmprelation;
+ }
+ else if (tmprelation == accessibility::AccessibleRelationType::CONTENT_FLOWS_TO)
+ {
+ css::uno::Reference<css::accessibility::XAccessibleText> adummy(
+ set2->getRelation(0).TargetSet[0], uno::UNO_QUERY_THROW);
+ atargets[1] = adummy;
+ relationtypes[1] = tmprelation;
+ }
+ else
+ {
+ CPPUNIT_FAIL("didn't gain correct relation type");
+ }
+ tmprelation = set2->getRelation(1).RelationType;
+ if (tmprelation == accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM)
+ {
+ css::uno::Reference<css::accessibility::XAccessibleText> adummy(
+ set2->getRelation(1).TargetSet[0], uno::UNO_QUERY_THROW);
+ atargets[0] = adummy;
+ relationtypes[0] = tmprelation;
+ }
+ else if (tmprelation == accessibility::AccessibleRelationType::CONTENT_FLOWS_TO)
+ {
+ css::uno::Reference<css::accessibility::XAccessibleText> adummy(
+ set2->getRelation(1).TargetSet[0], uno::UNO_QUERY_THROW);
+ atargets[1] = adummy;
+ relationtypes[1] = tmprelation;
+ }
+ else
+ {
+ CPPUNIT_FAIL("didn't gain correct relation type");
+ }
+ }
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct relation type for paragraph 1",
+ AccessibilityTools::getRelationTypeName(
+ accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM),
+ AccessibilityTools::getRelationTypeName(relationtypes[0]));
+
+ css::uno::Reference<css::accessibility::XAccessibleText> paraText1(para1, uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct target paragraph", atargets[0]->getText(),
+ paraText1->getText());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct relation type for paragraph 3",
+ AccessibilityTools::getRelationTypeName(
+ accessibility::AccessibleRelationType::CONTENT_FLOWS_TO),
+ AccessibilityTools::getRelationTypeName(relationtypes[1]));
+
+ css::uno::Reference<css::accessibility::XAccessibleText> paraText3(para3, uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("didn't gain correct target paragraph", atargets[1]->getText(),
+ paraText3->getText());
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AccessibleRelationSet);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/accessibility/basics.cxx b/sw/qa/extras/accessibility/basics.cxx
new file mode 100644
index 0000000000..6bdd992c22
--- /dev/null
+++ b/sw/qa/extras/accessibility/basics.cxx
@@ -0,0 +1,96 @@
+/* -*- 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/awt/Key.hpp>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <vcl/scheduler.hxx>
+
+#include <test/a11y/swaccessibletestbase.hxx>
+#include <test/a11y/AccessibilityTools.hxx>
+
+using namespace css;
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestBasicStructure)
+{
+ loadFromSrc(u"/sw/qa/python/testdocuments/xtextcontent.odt"_ustr);
+ auto xContext = getDocumentAccessibleContext();
+ CPPUNIT_ASSERT(xContext.is());
+
+ dumpA11YTree(xContext);
+ CPPUNIT_ASSERT_EQUAL(
+ rtl::OUString("<PARAGRAPH>String1</PARAGRAPH><PARAGRAPH/><PARAGRAPH/><PARAGRAPH/>"
+ "<TABLE name=\"Table1-1\" description=\"Table1 on page 1\">"
+ "<TABLE_CELL name=\"A1\" description=\"A1\">"
+ "<PARAGRAPH>String2</PARAGRAPH>"
+ "</TABLE_CELL>"
+ "</TABLE>"
+ "<PARAGRAPH/>"
+ "<TEXT_FRAME name=\"Frame1\"><PARAGRAPH>Frame1</PARAGRAPH></TEXT_FRAME>"
+ "<TEXT_FRAME name=\"Frame2\"><PARAGRAPH>Frame2</PARAGRAPH></TEXT_FRAME>"),
+ collectText(xContext));
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestTypeSimple)
+{
+ load(u"private:factory/swriter"_ustr);
+ auto xContext = getDocumentAccessibleContext();
+ CPPUNIT_ASSERT(xContext.is());
+
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'h', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'e', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'l', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'l', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'o', 0);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>hello</PARAGRAPH>"), collectText(xContext));
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestTypeMultiPara)
+{
+ load(u"private:factory/swriter"_ustr);
+ auto xContext = getDocumentAccessibleContext();
+ CPPUNIT_ASSERT(xContext.is());
+
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'A', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'B', 0);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 'C', 0);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(
+ rtl::OUString("<PARAGRAPH>A</PARAGRAPH><PARAGRAPH>B</PARAGRAPH><PARAGRAPH>C</PARAGRAPH>"),
+ collectText(xContext));
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestMenuInsertPageNumber)
+{
+ load(u"private:factory/swriter"_ustr);
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Field", u"Page Number"));
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>1</PARAGRAPH>"), collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestMenuInsertPageBreak)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Field", u"Page Number"));
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Page Break"));
+ // we need to move focus to the paragraph after the page break to insert the page number there
+ documentPostKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::DOWN);
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Field", u"Page Number"));
+
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>1</PARAGRAPH><PARAGRAPH>2</PARAGRAPH>"),
+ collectText());
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/qa/extras/accessibility/dialogs.cxx b/sw/qa/extras/accessibility/dialogs.cxx
new file mode 100644
index 0000000000..a14eed6bdb
--- /dev/null
+++ b/sw/qa/extras/accessibility/dialogs.cxx
@@ -0,0 +1,199 @@
+/* -*- 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/awt/Key.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+#include <vcl/scheduler.hxx>
+
+#include <test/a11y/swaccessibletestbase.hxx>
+#include <test/a11y/AccessibilityTools.hxx>
+
+using namespace css;
+
+// FIXME: dialog API doesn't work on macos yet
+#if !defined(MACOSX)
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestSpecialCharactersDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Special Characters", [this](Dialog& dialog) {
+ dumpA11YTree(dialog.getAccessible()->getAccessibleContext());
+
+ CPPUNIT_ASSERT_EQUAL(
+ AccessibilityTools::getAccessibleObjectForName(
+ dialog.getAccessible(), accessibility::AccessibleRole::TEXT, u"Search:"),
+ getFocusedObject(dialog.getAccessible()));
+
+ // search for (c) symbol
+ dialog.postExtTextEventAsync(u"copyright"_ustr);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::TABLE_CELL, u"©"));
+
+ /* there was a focus issue in this dialog: the table holding the characters always had the
+ * selected element as focused, even when tabbing outside.
+ * Fixed with https://gerrit.libreoffice.org/c/core/+/147660.
+ * Anyway, we still use the target element match API to also exercise it. */
+ auto xChild = AccessibilityTools::getAccessibleObjectForName(
+ dialog.getAccessible(), accessibility::AccessibleRole::PUSH_BUTTON, u"Insert");
+ CPPUNIT_ASSERT(xChild);
+ CPPUNIT_ASSERT(dialog.tabTo(xChild));
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Special Character..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(u"<PARAGRAPH>©</PARAGRAPH>"_ustr, collectText());
+}
+
+/* checks for the fix from https://gerrit.libreoffice.org/c/core/+/147660 */
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, TestSpecialCharactersDialogFocus)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Special Characters", [](Dialog& dialog) {
+ CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::TABLE_CELL, u" "));
+
+ /* as there is a bug that focusing the character table doesn't enable the Insert button
+ * (https://bugs.documentfoundation.org/show_bug.cgi?id=153806), we move to another cell
+ * so it works. */
+
+ // tdf#153918: Check that '!' char has correct accessible name and insert it
+ dialog.postKeyEventAsync(0, awt::Key::RIGHT);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(
+ AccessibilityTools::getAccessibleObjectForName(
+ dialog.getAccessible(), accessibility::AccessibleRole::TABLE_CELL, u"!"),
+ getFocusedObject(dialog.getAccessible()));
+
+ CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::PUSH_BUTTON, u"Insert"));
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Special Character..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(u"<PARAGRAPH>!</PARAGRAPH>"_ustr, collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestHyperlinkDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Hyperlink", [this](Dialog& dialog) {
+ dumpA11YTree(dialog.getAccessible()->getAccessibleContext());
+
+ // Focus the URL box (should be default, but make sure we're on it)
+ CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::COMBO_BOX, u"URL:"));
+ // Fill in an address
+ dialog.postExtTextEventAsync(u"https://libreoffice.org/"_ustr);
+ // Validate the whole dialog
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ // Activate the Insert->Hyperlink... menu item to open the Hyperlink dialog
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Hyperlink..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>https://libreoffice.org/</PARAGRAPH>"),
+ collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestBookmarkDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Bookmark", [this](Dialog& dialog) {
+ dumpA11YTree(dialog.getAccessible()->getAccessibleContext());
+
+ CPPUNIT_ASSERT(dialog.tabTo(accessibility::AccessibleRole::TEXT, u"Name:"));
+ dialog.postKeyEventAsync(0, awt::Key::SELECT_ALL);
+ dialog.postKeyEventAsync(0, awt::Key::DELETE);
+ dialog.postExtTextEventAsync(u"Test Bookmark 1"_ustr);
+ // Validate the whole dialog
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ // Activate the Insert->Bookmark... menu item to open the Bookmark dialog
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Bookmark..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH>#Test Bookmark 1 Bookmark </PARAGRAPH>"),
+ collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestSectionDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Insert Section", [this](Dialog& dialog) {
+ dumpA11YTree(dialog.getAccessible()->getAccessibleContext());
+
+ // Validate the whole dialog
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Section..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(rtl::OUString("<PARAGRAPH/><PARAGRAPH/>"), collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestFontworkDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Fontwork Gallery", [this](Dialog& dialog) {
+ dumpA11YTree(dialog.getAccessible()->getAccessibleContext());
+
+ // Validate the whole dialog
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Fontwork..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(
+ rtl::OUString("<PARAGRAPH/><SHAPE name=\"Simple\" description=\" \"><PARAGRAPH "
+ "description=\"Paragraph: 0 Simple\">Simple</PARAGRAPH></SHAPE>"),
+ collectText());
+}
+
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, BasicTestFrameDialog)
+{
+ load(u"private:factory/swriter"_ustr);
+
+ auto dialogWaiter = awaitDialog(u"Frame", [](Dialog& dialog) {
+ // Validate the whole dialog
+ dialog.postKeyEventAsync(0, awt::Key::RETURN);
+ Scheduler::ProcessEventsToIdle();
+ });
+
+ CPPUNIT_ASSERT(activateMenuItem(u"Insert", u"Frame", u"Frame..."));
+ CPPUNIT_ASSERT(dialogWaiter->waitEndDialog());
+
+ CPPUNIT_ASSERT_EQUAL(
+ rtl::OUString("<PARAGRAPH/><TEXT_FRAME name=\"Frame1\"><PARAGRAPH/></TEXT_FRAME>"),
+ collectText());
+}
+
+#endif //defined(MACOSX)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/qa/extras/accessibility/tdf155705.cxx b/sw/qa/extras/accessibility/tdf155705.cxx
new file mode 100644
index 0000000000..c145c7b2c8
--- /dev/null
+++ b/sw/qa/extras/accessibility/tdf155705.cxx
@@ -0,0 +1,57 @@
+/* -*- 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/XAccessibleTextMarkup.hpp>
+#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceManager2.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <com/sun/star/text/TextMarkupType.hpp>
+#include <i18nlangtag/lang.h>
+
+#include <vcl/scheduler.hxx>
+
+#include <test/a11y/swaccessibletestbase.hxx>
+#include <test/a11y/AccessibilityTools.hxx>
+
+using namespace css;
+
+/* This test only works if spell checking is available for en_US */
+CPPUNIT_TEST_FIXTURE(test::SwAccessibleTestBase, tdf155705)
+{
+ loadFromSrc(u"/sw/qa/extras/accessibility/testdocuments/tdf155705.fodt"_ustr);
+
+ /* we need to give it a second to fully set up the XAccessibleTextMarkup, otherwise we get a
+ * dysfunctional one that asserts out on m_pTextFrame */
+ Scheduler::ProcessEventsToIdle();
+
+ uno::Reference<linguistic2::XLinguServiceManager2> xLSM2
+ = linguistic2::LinguServiceManager::create(m_xContext);
+ uno::Reference<linguistic2::XSpellChecker1> xSpell(xLSM2->getSpellChecker(), uno::UNO_QUERY);
+ if (!xSpell.is() || !xSpell->hasLanguage(static_cast<sal_uInt16>(LANGUAGE_ENGLISH_US)))
+ return;
+
+ auto xContext = getDocumentAccessibleContext();
+ CPPUNIT_ASSERT(xContext.is());
+
+ auto xChildContext = getAllChildren(xContext).back();
+ uno::Reference<accessibility::XAccessibleTextMarkup> xMarkup(xChildContext,
+ uno::UNO_QUERY_THROW);
+
+ // make sure the idle spellcheck pass runs
+ AccessibilityTools::Await(
+ [&xMarkup]() { return 0 < xMarkup->getTextMarkupCount(text::TextMarkupType::SPELLCHECK); });
+
+ CPPUNIT_ASSERT_GREATER(sal_Int32(0),
+ xMarkup->getTextMarkupCount(text::TextMarkupType::SPELLCHECK));
+ auto aSegment = xMarkup->getTextMarkup(0, text::TextMarkupType::SPELLCHECK);
+ CPPUNIT_ASSERT_GREATEREQUAL(sal_Int32(0), aSegment.SegmentStart);
+ CPPUNIT_ASSERT_GREATER(aSegment.SegmentStart, aSegment.SegmentEnd);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/qa/extras/accessibility/testdocuments/tdf155705.fodt b/sw/qa/extras/accessibility/testdocuments/tdf155705.fodt
new file mode 100644
index 0000000000..8a22551ca9
--- /dev/null
+++ b/sw/qa/extras/accessibility/testdocuments/tdf155705.fodt
@@ -0,0 +1,130 @@
+<?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>2023-04-25T17:37:52.159526391</meta:creation-date><dc:date>2023-06-06T15:18:10.069098642</dc:date><meta:editing-duration>P6DT23H42M3S</meta:editing-duration><meta:editing-cycles>23</meta:editing-cycles><meta:generator>LibreOfficeDev/7.6.0.0.alpha1$Linux_X86_64 LibreOffice_project/b0d48d46ca30e7ea8f38af9a29080d76d01ad0ae</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="2" meta:paragraph-count="1" meta:word-count="138" meta:character-count="891" meta:non-whitespace-character-count="754"/></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"/>
+ </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="en" fo:country="US" 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="en" fo:country="US" 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"/>
+ <style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.247cm" style:contextual-spacing="false" fo:line-height="115%"/>
+ </style:style>
+ <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:theme-colors loext:name="LibreOffice">
+ <loext:color loext:name="dark1" loext:color="#000000"/>
+ <loext:color loext:name="light1" loext:color="#ffffff"/>
+ <loext:color loext:name="dark2" loext:color="#000000"/>
+ <loext:color loext:name="light2" 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="hyperlink" loext:color="#0000ee"/>
+ <loext:color loext:name="followed-hyperlink" loext:color="#551a8b"/>
+ </loext:theme-colors>
+ </loext:theme>
+ </office:styles>
+ <office:automatic-styles>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="10.5cm" fo:page-height="14.801cm" 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:use-soft-page-breaks="true">
+ <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="Text_20_body">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo <text:soft-page-break/>consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</text:p>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/accessibility/testdocuments/unicode.fodf b/sw/qa/extras/accessibility/testdocuments/unicode.fodf
new file mode 100644
index 0000000000..9bdccebf03
--- /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 0000000000..0130ee1dc4
--- /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"_ustr);
+
+ 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(u"\U0001f0a1"_ustr, 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(u"\U0001f0a1"_ustr, 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(u"\U0001f0ae"_ustr, 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"_ustr);
+
+ 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(u""_ustr, 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(u""_ustr, 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(u"\U0001f0ab"_ustr, 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(u""_ustr, 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(u""_ustr, 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(u"j"_ustr, 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: */