diff --git a/sw/qa/core/text/data/scriptinfo-surrogate-pairs.fodt b/sw/qa/core/text/data/scriptinfo-surrogate-pairs.fodt
new file mode 100644
index 000000000000..c14997a80741
--- /dev/null
+++ b/sw/qa/core/text/data/scriptinfo-surrogate-pairs.fodt
@@ -0,0 +1,292 @@
+
+
+
+ 2023-07-27T18:43:02.5378016242023-07-27T18:43:53.298342476PT51S1LibreOfficeDev/24.2.0.0.alpha0$MacOSX_X86_64 LibreOffice_project/cf8f7b91f41821b79495c0388359c4cb1156ea67
+
+
+ 0
+ 0
+ 17805
+ 9950
+ true
+ false
+
+
+ view2
+ 3332
+ 2501
+ 0
+ 0
+ 17803
+ 9948
+ 0
+ 1
+ false
+ 200
+ false
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+ true
+ true
+ true
+ false
+
+ false
+ false
+ true
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ 0
+ 0
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ true
+ false
+ false
+
+ false
+ false
+
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ true
+ true
+ false
+
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ 162604
+ true
+ true
+ false
+
+ false
+ true
+ false
+ high-resolution
+ 1
+ 1
+ true
+ false
+ false
+ true
+ true
+ true
+ true
+ true
+ false
+ true
+
+ false
+ true
+ 162604
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 11◌𐻽
+
+
+
\ No newline at end of file
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx
index 308098c85699..4f75de8af533 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -1463,6 +1463,23 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testTdf129810)
}
}
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testScriptinfosurrogatePairs)
+{
+ createSwDoc("scriptinfo-surrogate-pairs.fodt");
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // Test that a dotted circle is grouped with the mark after it, even if the
+ // mark is outside Unicode’s Basic Multilingual Plan (i.e. a surrogate pair
+ // in UTF-8)
+ //
+ // Without the fix it fails with:
+ // - Expected: 11
+ // - Actual : 11◌
+ assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion[1]", "portion", u"11");
+ assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion[2]", "portion",
+ u"\u25CC\U00010EFD");
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 4f15fbcccbf7..92d40f8878aa 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1440,25 +1441,21 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode,
// special case for dotted circle since it can be used with complex
// before a mark, so we want it associated with the mark's script
- if (nChg < TextFrameIndex(rText.getLength()) && nChg > TextFrameIndex(0)
- && (i18n::ScriptType::WEAK ==
- g_pBreakIt->GetBreakIter()->getScriptType(rText, sal_Int32(nChg) - 1)))
+ auto nPos = sal_Int32(nChg);
+ auto nPrevPos = nPos;
+ rText.iterateCodePoints(&nPrevPos, -1);
+ if (nChg < TextFrameIndex(rText.getLength()) && nChg > TextFrameIndex(0) &&
+ i18n::ScriptType::WEAK == g_pBreakIt->GetBreakIter()->getScriptType(rText, nPrevPos))
{
- int8_t nType = u_charType(rText[sal_Int32(nChg)]);
- if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
- nType == U_COMBINING_SPACING_MARK )
+ auto nType = unicode::getUnicodeType(rText.iterateCodePoints(&nPos, 0));
+ if (nType == css::i18n::UnicodeType::NON_SPACING_MARK ||
+ nType == css::i18n::UnicodeType::ENCLOSING_MARK ||
+ nType == css::i18n::UnicodeType::COMBINING_SPACING_MARK)
{
- m_ScriptChanges.emplace_back(nChg-TextFrameIndex(1), nScript);
- }
- else
- {
- m_ScriptChanges.emplace_back(nChg, nScript);
+ --nPos;
}
}
- else
- {
- m_ScriptChanges.emplace_back(nChg, nScript);
- }
+ m_ScriptChanges.emplace_back(TextFrameIndex(nPos), nScript);
++nCnt;
// if current script is asian, we search for compressible characters