diff --git a/i18nutil/source/utility/unicode.cxx b/i18nutil/source/utility/unicode.cxx index b0e1cd4d85ef..ae40fa421c0a 100644 --- a/i18nutil/source/utility/unicode.cxx +++ b/i18nutil/source/utility/unicode.cxx @@ -1068,7 +1068,7 @@ OUString unicode::formatPercent(double dNumber, return aRet; } -bool ToggleUnicodeCodepoint::AllowMoreInput(sal_Unicode uChar) +bool ToggleUnicodeCodepoint::AllowMoreInput(sal_uInt32 uChar) { //arbitrarily chosen maximum length allowed - normal max usage would be around 30. if( maInput.getLength() > 255 ) @@ -1092,12 +1092,20 @@ bool ToggleUnicodeCodepoint::AllowMoreInput(sal_Unicode uChar) if( rtl::isLowSurrogate(uChar) && maUtf16.isEmpty() && maInput.isEmpty() ) { - maUtf16.append(uChar); + maUtf16.append(sal_Unicode(uChar)); return true; } if( rtl::isHighSurrogate(uChar) && maInput.isEmpty() ) - maUtf16.insert(0, uChar ); - //end of hex strings, or unexpected order of high/low, so don't accept more + maUtf16.insert(0, sal_Unicode(uChar)); + if (maUtf16.getLength() == 2) + { + assert(rtl::isHighSurrogate(maUtf16[0]) && rtl::isLowSurrogate(maUtf16[1])); + // The resulting codepoint may itself be combining, so may allow more + sal_uInt32 nUCS4 = rtl::combineSurrogates(maUtf16[0], maUtf16[1]); + maUtf16.setLength(0); + return AllowMoreInput(nUCS4); + } + // unexpected order of high/low, so don't accept more if( !maUtf16.isEmpty() ) maInput.append(maUtf16); if( !maCombining.isEmpty() ) @@ -1122,7 +1130,7 @@ bool ToggleUnicodeCodepoint::AllowMoreInput(sal_Unicode uChar) mbAllowMoreChars = false; return false; } - maCombining.insert(0, uChar); + maCombining.insertUtf32(0, uChar); break; default: @@ -1138,7 +1146,7 @@ bool ToggleUnicodeCodepoint::AllowMoreInput(sal_Unicode uChar) if( !maCombining.isEmpty() ) { - maCombining.insert(0, uChar); + maCombining.insertUtf32(0, uChar); maInput = maCombining; mbAllowMoreChars = false; return false; diff --git a/include/i18nutil/unicode.hxx b/include/i18nutil/unicode.hxx index be08595e0b10..b7722fd77196 100644 --- a/include/i18nutil/unicode.hxx +++ b/include/i18nutil/unicode.hxx @@ -102,11 +102,11 @@ private: public: /** - Build an input string of valid UTF16 units to toggle. + Build an input string of valid UTF16/UCS4 units to toggle. -do not call the other functions until the input process is complete -build string from Right to Left. (Start from the character to the left of the cursor: move left.) */ - bool AllowMoreInput(sal_Unicode uChar); + bool AllowMoreInput(sal_uInt32 uChar); /** Validates (and potentially modifies) the input string. diff --git a/sw/qa/extras/uiwriter/uiwriter7.cxx b/sw/qa/extras/uiwriter/uiwriter7.cxx index 4b3f1c9c533f..18c7fefd3248 100644 --- a/sw/qa/extras/uiwriter/uiwriter7.cxx +++ b/sw/qa/extras/uiwriter/uiwriter7.cxx @@ -2405,8 +2405,8 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testUnicodeNotationToggle) sDocString = pWrtShell->GetCursor()->GetPointNode().GetTextNode()->GetText(); CPPUNIT_ASSERT_EQUAL(sOriginalDocString, sDocString); - constexpr OUString sWithCombiningSMPName = u"xyzU+e0101"_ustr; - constexpr OUString sWithCombiningSMP = u"xyz\U000e0101"_ustr; + constexpr OUString sWithCombiningSMPName = u"xyzU+4faeU+e0101"_ustr; + constexpr OUString sWithCombiningSMP = u"xyz\U00004fae\U000e0101"_ustr; pWrtShell->SplitNode(); pWrtShell->Insert2(sWithCombiningSMPName); dispatchCommand(mxComponent, u".uno:UnicodeNotationToggle"_ustr, aPropertyValues); @@ -2416,9 +2416,13 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testUnicodeNotationToggle) dispatchCommand(mxComponent, u".uno:UnicodeNotationToggle"_ustr, aPropertyValues); sDocString = pWrtShell->GetCursor()->GetPointNode().GetTextNode()->GetText(); // Before tdf#162656 fix, this failed with - // - Expected: xyzU+e0101 - // - Actual : xyU+e0101 + // - Expected: xyzU+4faeU+e0101 + // - Actual : xyxU+e0101 // i.e., one codepoint to the left of the combining codepoint was removed + // Before tdf#162657 fix, this failed with + // - Expected: xyzU+4faeU+e0101 + // - Actual : xyz侮U+e0101 + // i.e., one codepoint to the left of the combining codepoint was not converted CPPUNIT_ASSERT_EQUAL(sWithCombiningSMPName, sDocString); }