sw/qa/core/uwriter.cxx | 141 ++++++++++++++++++++++++++++++++++++++ sw/source/core/doc/docruby.cxx | 13 ++- sw/source/core/inc/scriptinfo.hxx | 6 + sw/source/core/text/porlay.cxx | 2 4 files changed, 157 insertions(+), 5 deletions(-)
New commits: commit bd32bf20deda61093362216a9b6c68afbe172783 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Thu Aug 15 15:18:15 2024 -0600 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Tue Aug 20 10:47:46 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> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172085 diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx index bf60b24421ff..49f3739d65ca 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: @@ -1941,6 +1945,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 commit 2879a1c441548bcac66ea5e6274840e65a9b05da Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Tue Aug 13 12:32:18 2024 -0600 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Tue Aug 20 10:47:39 2024 +0200 tdf#156211 sw: Fix spurious kashida inserted after undo This change fixes an issue presenting as incorrectly-positioned kashida glyphs overlapping Arabic text after certain edit operations. During layout with kashida justification, Writer builds a table of lines that require fallback to whitespace justification. Normally, this table is built sequentially from the first line, but it may be updated out-of-order following certain edit operations. Due to an off-by-one error, if Writer cleared the exclusion for a line immediately before a legitimately-excluded line, Writer would also clear the legitimate exclusion. In such a situation, portions of excluded text would be redrawn with kashida justification, and because that text usually does not have enough free space, the kashida glyphs would be drawn on top of the base text. Change-Id: I204661286531fa6064f7a6adc35f1606e35e5d39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171878 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> (cherry picked from commit dda85e275d70d6365009042b8e207337f2e712c2) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172069 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx index 436e4c1c934a..bf60b24421ff 100644 --- a/sw/qa/core/uwriter.cxx +++ b/sw/qa/core/uwriter.cxx @@ -71,6 +71,7 @@ #include <calbck.hxx> #include <pagedesc.hxx> #include <calc.hxx> +#include <scriptinfo.hxx> #include <tblafmt.hxx> #include <unotbl.hxx> @@ -128,6 +129,7 @@ public: void test64kPageDescs(); void testTdf92308(); void testTableCellComparison(); + void testTdf156211(); CPPUNIT_TEST_SUITE(SwDocTest); @@ -165,6 +167,7 @@ public: CPPUNIT_TEST(test64kPageDescs); CPPUNIT_TEST(testTdf92308); CPPUNIT_TEST(testTableCellComparison); + CPPUNIT_TEST(testTdf156211); CPPUNIT_TEST_SUITE_END(); private: @@ -1926,6 +1929,18 @@ void SwDocTest::tearDown() BootstrapFixture::tearDown(); } +void SwDocTest::testTdf156211() +{ + SwScriptInfo oSI; + oSI.SetNoKashidaLine(TextFrameIndex{ 89 }, TextFrameIndex{ 95 }); + + CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 })); + + oSI.ClearNoKashidaLine(TextFrameIndex{ 0 }, TextFrameIndex{ 89 }); + + CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 })); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index 21c3c2240cc4..377455f6e15f 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -96,7 +96,6 @@ private: void ClearKashidaInvalid(size_t nKashPos); bool MarkOrClearKashidaInvalid(TextFrameIndex nStt, TextFrameIndex nLen, bool bMark, sal_Int32 nMarkCount); - bool IsKashidaLine(TextFrameIndex nCharIdx) const; // examines the range [ nStart, nStart + nEnd ] if there are kanas // returns start index of kana entry in array, otherwise SAL_MAX_SIZE size_t HasKana(TextFrameIndex nStart, TextFrameIndex nEnd) const; @@ -335,6 +334,11 @@ public: */ void ClearNoKashidaLine(TextFrameIndex nStt, TextFrameIndex nLen); +/** Checks whether the character is on a line excluded from kashida justification. + nCharIdx Char index within the paragraph. +*/ + bool IsKashidaLine(TextFrameIndex nCharIdx) const; + /** Checks if text is Arabic text. @descr Checks if text is Arabic text. diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index bb33c11bf8b4..b7e4310e1f4d 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -2543,7 +2543,7 @@ void SwScriptInfo::ClearNoKashidaLine(TextFrameIndex const nStt, TextFrameIndex size_t i = 0; while (i < m_NoKashidaLine.size()) { - if (nStt + nLen >= m_NoKashidaLine[i] && nStt < m_NoKashidaLineEnd[i]) + if (nStt + nLen > m_NoKashidaLine[i] && nStt < m_NoKashidaLineEnd[i]) { m_NoKashidaLine.erase(m_NoKashidaLine.begin() + i); m_NoKashidaLineEnd.erase(m_NoKashidaLineEnd.begin() + i);