From 3af30bafbedb8eb481024efb35cb7876c63d26dc Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Thu, 27 Jul 2023 19:03:28 +0300 Subject: [PATCH] sw: Handle surrogate pairs when tweaking script info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I18e8358657303571d5d90e5162dbb68cbe067980 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154995 Tested-by: Jenkins Reviewed-by: خالد حسني --- .../text/data/scriptinfo-surrogate-pairs.fodt | 292 ++++++++++++++++++ sw/qa/core/text/text.cxx | 17 + sw/source/core/text/porlay.cxx | 27 +- 3 files changed, 321 insertions(+), 15 deletions(-) create mode 100644 sw/qa/core/text/data/scriptinfo-surrogate-pairs.fodt 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