sw/inc/redline.hxx                                  |    3 -
 sw/qa/extras/layout/data/CT-formatted-deletion.docx |binary
 sw/qa/extras/layout/layout2.cxx                     |   19 ++++++++
 sw/source/core/crsr/crstrvl.cxx                     |   32 +++++++++++++
 sw/source/core/doc/docredln.cxx                     |    5 +-
 sw/source/core/text/redlnitr.cxx                    |   46 +++++++++++++++-----
 vcl/source/gdi/mtfxmldump.cxx                       |    1 
 7 files changed, 93 insertions(+), 13 deletions(-)

New commits:
commit 9bd50bdd21145199fd4be48e24d1a7b270175fcd
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Feb 20 18:08:33 2025 +0100
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Tue Feb 25 17:45:53 2025 +0100

    tdf#165322 sw: apply formatting for multiple redlines in SwRedlineItr
    
    SwRedlineItr::Seek() assumes that redlines don't overlap, but sometimes
    they do, at least a ParagraphFormat and a Delete redline can overlap
    (unsure if that is a good idea) when imported from DOCX.
    
    Change-Id: Ic13080bfe8c9910ffef44f3e48d11c7f852427ba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181961
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit b3567d7e1f08df7c050d3cec86cbb200af558172)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182163
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx
index ef7c8129ce6a..2078a57ffa7f 100644
--- a/sw/inc/redline.hxx
+++ b/sw/inc/redline.hxx
@@ -250,7 +250,8 @@ public:
     void ShowOriginal(sal_uInt16 nLoop, size_t nMyPos, bool bForced = false);
 
     /// Calculates the intersection with text node number nNdIdx.
-    void CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32& rStart, sal_Int32& rEnd) 
const;
+    /// @return true if the entire redline precedes nNdIdx
+    bool CalcStartEnd(SwNodeOffset nNdIdx, sal_Int32& rStart, sal_Int32& rEnd) 
const;
 
     enum class Invalidation { Add, Remove };
     /// Initiate the layout.
diff --git a/sw/qa/extras/layout/data/CT-formatted-deletion.docx 
b/sw/qa/extras/layout/data/CT-formatted-deletion.docx
new file mode 100644
index 000000000000..585d7ba27cab
Binary files /dev/null and 
b/sw/qa/extras/layout/data/CT-formatted-deletion.docx differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index f968b10bf698..8c069e76374a 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -677,6 +677,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf129357)
                        u"-"_ustr);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf165322)
+{
+    createSwDoc("CT-formatted-deletion.docx");
+    SwDocShell* pShell = getSwDocShell();
+
+    // Dump the rendering of the first page as an XML file.
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+    MetafileXmlDump dumper;
+
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    CPPUNIT_ASSERT(pXmlDoc);
+
+    // paragraph with 2 redlines was not marked as deleted
+    assertXPath(pXmlDoc,
+                "//text[text() = 'Nunc viverra imperdiet enim. Fusce est. 
Vivamus a "
+                "tellus.']/parent::textarray/preceding-sibling::font[1]",
+                "strikeout", u"1"_ustr);
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineNumberInNumbering)
 {
     createSwDoc("tdf42748.fodt");
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index b16dcb3b1490..f49c74dae574 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1748,7 +1748,8 @@ void SwRangeRedline::InvalidateRange(Invalidation const 
eWhy)
 
 /** Calculates the start and end position of the intersection rTmp and
     text node nNdIdx */
-void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, sal_Int32& rStart, 
sal_Int32& rEnd ) const
+bool SwRangeRedline::CalcStartEnd(SwNodeOffset const nNdIdx,
+        sal_Int32 & rStart, sal_Int32 & rEnd) const
 {
     auto [pRStt, pREnd] = StartEnd(); // SwPosition*
     if( pRStt->GetNodeIndex() < nNdIdx )
@@ -1767,6 +1768,7 @@ void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, 
sal_Int32& rStart, sal_I
         {
             rStart = COMPLETE_STRING;
             rEnd = COMPLETE_STRING;
+            return true;
         }
     }
     else if( pRStt->GetNodeIndex() == nNdIdx )
@@ -1782,6 +1784,7 @@ void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, 
sal_Int32& rStart, sal_I
         rStart = COMPLETE_STRING;
         rEnd = COMPLETE_STRING;
     }
+    return false;
 }
 
 static void lcl_storeAnnotationMarks(SwDoc& rDoc, const SwPosition* pStt, 
const SwPosition* pEnd)
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index a49f6d03dc50..53b9b9641699 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -789,7 +789,7 @@ short SwRedlineItr::Seek(SwFont& rFnt,
             {
                 --nRet;
                 Clear_( &rFnt );    // We go behind the current section
-                ++m_nAct;             // and check the next one
+//                ++m_nAct; // don't increment, could be in next range too if 
overlap
             }
             else if (nNew < m_nStart)
             {
@@ -809,16 +809,35 @@ short SwRedlineItr::Seek(SwFont& rFnt,
         m_nStart = COMPLETE_STRING;
         m_nEnd = COMPLETE_STRING;
         const SwRedlineTable& rTable = 
m_rDoc.getIDocumentRedlineAccess().GetRedlineTable();
+        ::std::optional<decltype(m_nAct)> oFirstMatch;
 
         for ( ; m_nAct < rTable.size() ; ++m_nAct)
         {
-            rTable[ m_nAct ]->CalcStartEnd(nNode, m_nStart, m_nEnd);
+            decltype(m_nStart) nStart;
+            decltype(m_nEnd) nEnd;
+            if (rTable[m_nAct]->CalcStartEnd(nNode, nStart, nEnd))
+            { // previous redline intersected nNode but this one precedes it
+                continue;
+            }
 
-            if (nNew < m_nEnd)
+            // redline table is sorted, but here it's not the complete redlines
+            assert(m_nStart == COMPLETE_STRING || m_nStart <= nStart);
+            assert(m_nStart == COMPLETE_STRING || m_nStart <= nEnd);
+            if (oFirstMatch && nNew < nStart)
             {
-                if (nNew >= m_nStart) // only possible candidate
+                m_nEnd = std::min(m_nEnd, nStart);
+                break;
+            }
+            if (nNew < nEnd)
+            {
+                m_nStart = nStart;
+                m_nEnd = std::min(m_nEnd, nEnd);
+                if (nStart <= nNew) // there can be a format and another 
redline...
                 {
-                    m_bOn = true;
+                    if (!oFirstMatch)
+                    {
+                        oFirstMatch.emplace(m_nAct);
+                    }
                     const SwRangeRedline *pRed = rTable[ m_nAct ];
 
                     if (m_pSet)
@@ -862,13 +881,19 @@ short SwRedlineItr::Seek(SwFont& rFnt,
                         }
                         nWhich = aIter.NextWhich();
                     }
-
-                    ++nRet;
                 }
-                break;
+                else
+                {
+                    break;
+                }
             }
-            m_nStart = COMPLETE_STRING;
-            m_nEnd = COMPLETE_STRING;
+        }
+
+        if (oFirstMatch)
+        {
+            m_bOn = true;
+            m_nAct = *oFirstMatch; // rewind
+            ++nRet; // increment only once per m_nStart/m_nEnd range
         }
     }
     else if (m_eMode == Mode::Hide)
@@ -916,6 +941,7 @@ void SwRedlineItr::FillHints( std::size_t nAuthor, 
RedlineType eType )
             break;
         case RedlineType::Format:
         case RedlineType::FmtColl:
+        case RedlineType::ParagraphFormat:
             SW_MOD()->GetFormatAuthorAttr(nAuthor, *m_pSet);
             break;
         default:
diff --git a/vcl/source/gdi/mtfxmldump.cxx b/vcl/source/gdi/mtfxmldump.cxx
index fda2db24ecb9..7311d8431cf2 100644
--- a/vcl/source/gdi/mtfxmldump.cxx
+++ b/vcl/source/gdi/mtfxmldump.cxx
@@ -1333,6 +1333,7 @@ void MetafileXmlDump::writeXml(const GDIMetaFile& 
rMetaFile, tools::XmlWriter& r
                 rWriter.attribute("orientation", aFont.GetOrientation().get());
                 rWriter.attribute("weight", 
convertFontWeightToString(aFont.GetWeight()));
                 rWriter.attribute("vertical", aFont.IsVertical() ? "true" : 
"false");
+                rWriter.attribute("strikeout", aFont.GetStrikeout());
 
                 rWriter.endElement();
             }
commit b016c132eed47439fe96a1d9f933f3d6368a9718
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Feb 20 19:00:04 2025 +0100
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Tue Feb 25 17:45:40 2025 +0100

    tdf#165322 sw: prefer insert/delete redline in mouse-over tooltip
    
    Unfortunately SwCursorShell::GetContentAtPos() can only report 1 redline
    for a given position; in case there is a format and a insert/delete
    redline at the same position, the latter is more important.
    
    This is then used in SwEditWin::RequestHelp() to display a tooltip if
    the user moves the mouse cursor over a redline.
    
    Change-Id: I32af7a154873e3fa5775a711980bb3dab3e307ad
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181960
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit f439448d21ef2feb03a9920d95d30f23795db6ac)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182153
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index effc825987c7..ca4538974864 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1859,10 +1859,40 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt,
 
             if( !bRet && IsAttrAtPos::Redline & rContentAtPos.eContentAtPos )
             {
-                const SwRangeRedline* pRedl = 
GetDoc()->getIDocumentRedlineAccess().GetRedline(aPos, nullptr);
+                SwRedlineTable::size_type index;
+                IDocumentRedlineAccess const& 
rIDRA{GetDoc()->getIDocumentRedlineAccess()};
+                const SwRangeRedline* pRedl{rIDRA.GetRedline(aPos, &index)};
 
                 if( pRedl )
                 {
+                    // treat insert/delete as more important than formatting
+                    for (; index < rIDRA.GetRedlineTable().size(); ++index)
+                    {
+                        SwRangeRedline const*const 
pTmp{rIDRA.GetRedlineTable()[index]};
+                        if (aPos < *pTmp->Start())
+                        {
+                            break;
+                        }
+                        switch (pRedl->GetType())
+                        {
+                            case RedlineType::Format:
+                            case RedlineType::FmtColl:
+                            case RedlineType::ParagraphFormat:
+                                switch (pTmp->GetType())
+                                {
+                                    case RedlineType::Insert:
+                                    case RedlineType::Delete:
+                                        pRedl = pTmp;
+                                        break;
+                                    default:
+                                        break;
+                                }
+                            break;
+                            default:
+                                break;
+                        }
+                    };
+
                     rContentAtPos.aFnd.pRedl = pRedl;
                     rContentAtPos.eContentAtPos = IsAttrAtPos::Redline;
                     rContentAtPos.pFndTextAttr = nullptr;

Reply via email to