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);

Reply via email to