sw/qa/core/uwriter.cxx | 126 +++++++++++++++++++++++++++++++++++++++++ sw/source/core/doc/docruby.cxx | 13 +++- 2 files changed, 136 insertions(+), 3 deletions(-)
New commits: commit 63fbb71f362b16eaa7b7d8617ae3b7e482b41492 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Thu Aug 15 15:18:15 2024 -0600 Commit: Jonathan Clark <jonat...@libreoffice.org> CommitDate: Fri Aug 16 05:02:08 2024 +0200 tdf#141466 sw: Fix incorrect output after editing Ruby base text Previously, the Asian Phonetic Guide dialog could scramble base text during editing due to incorrect handling of PaM after calling ReplaceRange(). This issue has been fixed. The implementation has also been modified to allow base text deletion. Change-Id: I43350272359c7984459aea1604dae0d3f6428cac Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171934 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx index 861b8b3d272e..3504a11130df 100644 --- a/sw/qa/core/uwriter.cxx +++ b/sw/qa/core/uwriter.cxx @@ -72,6 +72,8 @@ #include <pagedesc.hxx> #include <calc.hxx> #include <scriptinfo.hxx> +#include <rubylist.hxx> +#include <txatbase.hxx> #include <tblafmt.hxx> #include <unotbl.hxx> @@ -130,6 +132,7 @@ public: void testTdf92308(); void testTableCellComparison(); void testTdf156211(); + void testSetRubyList(); CPPUNIT_TEST_SUITE(SwDocTest); @@ -168,6 +171,7 @@ public: CPPUNIT_TEST(testTdf92308); CPPUNIT_TEST(testTableCellComparison); CPPUNIT_TEST(testTdf156211); + CPPUNIT_TEST(testSetRubyList); CPPUNIT_TEST_SUITE_END(); private: @@ -1981,6 +1985,128 @@ void SwDocTest::testTdf156211() CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 })); } +void SwDocTest::testSetRubyList() +{ + SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + + SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode(); + CPPUNIT_ASSERT(pTextNode); + + auto& rOps = m_pDoc->getIDocumentContentOperations(); + + auto fnAppendJapanese = [&](const OUString& rText) + { + rOps.AppendTextNode(*aPaM.GetPoint()); + + SvxLanguageItem aCJKLangItem(LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE); + SvxLanguageItem aWestLangItem(LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE); + rOps.InsertPoolItem(aPaM, aCJKLangItem); + rOps.InsertPoolItem(aPaM, aWestLangItem); + + rOps.InsertString(aPaM, rText); + + aPaM.SetMark(); + aPaM.GetPoint()->nContent = 0; + + CPPUNIT_ASSERT_EQUAL(rText, aPaM.GetText()); + }; + + auto fnAppendRuby = [](SwRubyList* rList, OUString aBase, OUString aRuby) + { + auto pEnt = std::make_unique<SwRubyListEntry>(); + pEnt->SetText(std::move(aBase)); + pEnt->SetRubyAttr(SwFormatRuby{ std::move(aRuby) }); + + rList->push_back(std::move(pEnt)); + }; + + auto fnGetCombinedString = [&] + { + OUStringBuffer aTemp; + + auto* pPos = aPaM.GetPoint(); + const auto* pTNd = pPos->GetNode().GetTextNode(); + const auto& rText = pTNd->GetText(); + const auto* pHts = pTNd->GetpSwpHints(); + + for (sal_Int32 i = 0; i < rText.getLength(); ++i) + { + aTemp.append(rText[i]); + + if (pHts) + { + for (size_t j = 0; j < pHts->Count(); ++j) + { + const auto* pHt = pHts->Get(j); + if (pHt->Which() == RES_TXTATR_CJK_RUBY && pHt->GetAnyEnd() == (i + 1)) + { + aTemp.append(u"["_ustr + pHt->GetRuby().GetText() + u"]"_ustr); + } + } + } + } + + return aTemp.toString(); + }; + + // Trivial characteristic test + { + fnAppendJapanese(u"学校"_ustr); + + SwRubyList rList; + fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr); + + m_pDoc->SetRubyList(aPaM, rList); + + CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString()); + } + + // tdf#141466: Characteristic test from bug + { + fnAppendJapanese(u"学校に行きます。"_ustr); + + SwRubyList rList; + fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr); + fnAppendRuby(&rList, u"に"_ustr, u""_ustr); + fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr); + fnAppendRuby(&rList, u"きます"_ustr, u""_ustr); + fnAppendRuby(&rList, u"。"_ustr, u""_ustr); + + m_pDoc->SetRubyList(aPaM, rList); + + CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString()); + } + + // Base text deletion + { + fnAppendJapanese(u"学校に行きます。"_ustr); + + SwRubyList rList; + fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr); + fnAppendRuby(&rList, u"に"_ustr, u""_ustr); + fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr); + fnAppendRuby(&rList, u"きます"_ustr, u""_ustr); + fnAppendRuby(&rList, u"。"_ustr, u""_ustr); + + m_pDoc->SetRubyList(aPaM, rList); + + CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString()); + + SwRubyList rList2; + fnAppendRuby(&rList2, u"学校"_ustr, u"がっこう"_ustr); + fnAppendRuby(&rList2, u"に"_ustr, u""_ustr); + fnAppendRuby(&rList2, u""_ustr, u"い"_ustr); + fnAppendRuby(&rList2, u"来"_ustr, u"き"_ustr); + fnAppendRuby(&rList2, u"ます"_ustr, u""_ustr); + fnAppendRuby(&rList2, u"。"_ustr, u""_ustr); + + m_pDoc->SetRubyList(aPaM, rList2); + + CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に来[き]ます。"_ustr, fnGetCombinedString()); + } +} + CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/docruby.cxx b/sw/source/core/doc/docruby.cxx index 1a1b84ffd7f4..90f4e771d993 100644 --- a/sw/source/core/doc/docruby.cxx +++ b/sw/source/core/doc/docruby.cxx @@ -127,12 +127,19 @@ void SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList ) } } - if( !pEntry->GetText().isEmpty() && - aCheckEntry.GetText() != pEntry->GetText() ) + if (aCheckEntry.GetText() != pEntry->GetText()) { + if (pEntry->GetText().isEmpty()) + { + ResetAttrs(aPam, true, aDelArr); + } + // text is changed, so replace the original - getIDocumentContentOperations().ReplaceRange( aPam, pEntry->GetText(), false ); + getIDocumentContentOperations().ReplaceRange(aPam, pEntry->GetText(), + false); + std::swap(*aPam.GetMark(), *aPam.GetPoint()); } + aPam.DeleteMark(); } else