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/doc/docredln.cxx | 5 +- sw/source/core/text/redlnitr.cxx | 46 +++++++++++++++----- vcl/source/gdi/mtfxmldump.cxx | 1 6 files changed, 62 insertions(+), 12 deletions(-)
New commits: commit b3567d7e1f08df7c050d3cec86cbb200af558172 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Thu Feb 20 18:08:33 2025 +0100 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Tue Feb 25 12:54:22 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> diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx index 20befbaa43d7..6a88a0a3ccd1 100644 --- a/sw/inc/redline.hxx +++ b/sw/inc/redline.hxx @@ -252,7 +252,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 1e73f97af75e..a9cd34f17432 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -522,6 +522,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf129357) assertXPathContent(pXmlDoc, "/metafile/push/push/push/push/push/textarray[2]/text", u"-"); } +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"); +} + 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 2434d4863fb1..27307315724d 100644 --- a/sw/source/core/doc/docredln.cxx +++ b/sw/source/core/doc/docredln.cxx @@ -1750,7 +1750,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 ) @@ -1769,6 +1770,7 @@ void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx, sal_Int32& rStart, sal_I { rStart = COMPLETE_STRING; rEnd = COMPLETE_STRING; + return true; } } else if( pRStt->GetNodeIndex() == nNdIdx ) @@ -1784,6 +1786,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* pStart, const SwPosition* pEnd) diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index 0058064e1513..36eedcf86134 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -800,7 +800,7 @@ short SwRedlineItr::Seek(SwFont& rFnt, { --nRet; Clear_( &rFnt ); // We go behind the current range - ++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) { @@ -820,16 +820,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) @@ -874,13 +893,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) @@ -928,6 +953,7 @@ void SwRedlineItr::FillHints( std::size_t nAuthor, RedlineType eType ) break; case RedlineType::Format: case RedlineType::FmtColl: + case RedlineType::ParagraphFormat: SwModule::get()->GetFormatAuthorAttr(nAuthor, *m_pSet); break; default: diff --git a/vcl/source/gdi/mtfxmldump.cxx b/vcl/source/gdi/mtfxmldump.cxx index 2fa6052567f7..84fb0019e9d1 100644 --- a/vcl/source/gdi/mtfxmldump.cxx +++ b/vcl/source/gdi/mtfxmldump.cxx @@ -1337,6 +1337,7 @@ void MetafileXmlDump::writeXml(const GDIMetaFile& rMetaFile, tools::XmlWriter& r rWriter.attribute("shadow", aFont.IsShadow() ? "true" : "false"); rWriter.attribute("wordunderline", aFont.IsWordLineMode() ? "true" : "false"); rWriter.attribute("outline", aFont.IsOutline() ? "true" : "false"); + rWriter.attribute("strikeout", aFont.GetStrikeout()); rWriter.endElement(); }