online.git: engine/sw

0 views
Skip to first unread message

"Mike Kaganski (via cogerrit)"

unread,
Apr 20, 2026, 11:57:47 AM (9 days ago) Apr 20
to collaboraon...@googlegroups.com
engine/sw/inc/shellio.hxx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

New commits:
commit 7ccbac64212f7af5690b0899db553210023c575b
Author: Mike Kaganski <mike.k...@collabora.com>
AuthorDate: Fri Apr 17 17:11:19 2026 +0500
Commit: Andras Timar <andras...@collabora.com>
CommitDate: Mon Apr 20 15:57:31 2026 +0000

Fix windows build

... after commit e1a599aa5082a528b36ba2d4711111c4cd39eb7a (cool#15535 sw
markdown import: handle pasting into an existing paragraph, 2026-04-17).

C:\lo\core\include\rtl/ref.hxx(122): error C2027: use of undefined type 'SwXTextRange'
C:\lo\core\sw\inc\shellio.hxx(51): note: see declaration of 'SwXTextRange'
C:\lo\core\include\rtl/ref.hxx(122): note: the template instantiation context (the oldest one first) is
C:\lo\core\sw\inc\shellio.hxx(216): note: see reference to class template instantiation 'rtl::Reference<SwXTextRange>' being compiled
C:\lo\core\include\rtl/ref.hxx(119): note: while compiling class template member function 'rtl::Reference<SwXTextRange>::~Reference(void)'
C:\lo\core\sw\inc\shellio.hxx(221): note: see the first reference to 'rtl::Reference<SwXTextRange>::~Reference' in 'SwPasteInfo::~SwPasteInfo'

Change-Id: I15c09b9bb01325330669e154a1d4aa38e1be9e61
Reviewed-on: https://gerrit.collaboraoffice.com/c/core/+/1130
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1170
Tested-by: Andras Timar <andras...@collabora.com>
Reviewed-by: Andras Timar <andras...@collabora.com>

diff --git a/engine/sw/inc/shellio.hxx b/engine/sw/inc/shellio.hxx
index 425bdebbd077..dc61e3f9b9ea 100644
--- a/engine/sw/inc/shellio.hxx
+++ b/engine/sw/inc/shellio.hxx
@@ -34,6 +34,7 @@
#include "swdllapi.h"
#include "docfac.hxx"
#include "unocrsr.hxx"
+#include "unotextrange.hxx"

class SfxItemPool;
class SfxItemSet;
@@ -48,7 +49,6 @@ class SwPaM;
class SwTextBlocks;
struct SwPosition;
struct Writer_Impl;
-class SwXTextRange;
namespace sw::mark { class MarkBase; }
namespace com::sun::star::embed { class XStorage; }


"Miklos Vajna (via cogerrit)"

unread,
Apr 21, 2026, 11:45:03 AM (8 days ago) Apr 21
to collaboraon...@googlegroups.com
engine/sw/qa/filter/md/md.cxx | 15 +++++++++++++++
engine/sw/source/filter/basflt/shellio.cxx | 3 ---
engine/sw/source/filter/md/swmd.cxx | 16 ++++++++++++++--
engine/sw/source/filter/rtf/swparrtf.cxx | 3 +++
4 files changed, 32 insertions(+), 5 deletions(-)

New commits:
commit 840bd79a47fad50a80b9720176ad53dd50649091
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Tue Apr 21 09:03:39 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Tue Apr 21 15:44:32 2026 +0000

Related: cool#15535 sw markdown import: use matching paragraph formatting

Open the bugdoc, position the cursor before "A", paste the markdown
snippet: the content is OK, the bullet size is OK, but the paragraph
style & margins of the new content is different to the existing content.

Given that markdown has no way to specify a paragraph style for normal
(non-heading) text and also no way to specify paragraph margins, it's
reasonable to expect these are just copied from the paste insertion
point for consistency.

Fix this by:
1) Putting the end of Reader::StartPaste() back to SwRTFReader::Read(),
so the RTF paste behavior is unchanged, but we don't reset the
paragraph style in Reader::StartPaste() for markdown
2) Extending SwMarkdownParser::CallParser() to not reset the paragraph
style in the paste case before calling md_parse()
3) Extending SwMarkdownParser::EndNumberedBulletListItem() to not touch
paragraph margins when pasting.

The behavior for normal (non-paste) markdown import is unchanged.

(cherry picked from commit 21c6c0139ceb307525fb0cc05c7a547b8e07d16f)

Change-Id: I57e9f329f48bcd9a6e1388bb635c7a2a9489aecf
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1249
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/filter/md/md.cxx b/engine/sw/qa/filter/md/md.cxx
index e5b3c37aade1..60ee4e738458 100644
--- a/engine/sw/qa/filter/md/md.cxx
+++ b/engine/sw/qa/filter/md/md.cxx
@@ -1017,6 +1017,21 @@ CPPUNIT_TEST_FIXTURE(Test, testPaste)
// - Actual : WWNum2
// i.e. List 1 & 2 had a non-named list style instead of being consistent with "A".
CPPUNIT_ASSERT_EQUAL(aList2Style, aAStyle);
+
+ // Also check that paragraph style and margins are preserved from the insertion point:
+ OUString aList2ParaStyle = getProperty<OUString>(getParagraph(3), u"ParaStyleName"_ustr);
+ OUString aAParaStyle = getProperty<OUString>(getParagraph(4), u"ParaStyleName"_ustr);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Standard
+ // - Actual : Text body
+ // i.e. the pasted paragraphs lost paragraph style from the insertion point.
+ CPPUNIT_ASSERT_EQUAL(aAParaStyle, aList2ParaStyle);
+ sal_Int32 aList2Top = getProperty<sal_Int32>(getParagraph(3), u"ParaTopMargin"_ustr);
+ sal_Int32 aATop = getProperty<sal_Int32>(getParagraph(4), u"ParaTopMargin"_ustr);
+ CPPUNIT_ASSERT_EQUAL(aATop, aList2Top);
+ sal_Int32 aList2Bottom = getProperty<sal_Int32>(getParagraph(3), u"ParaBottomMargin"_ustr);
+ sal_Int32 aABottom = getProperty<sal_Int32>(getParagraph(4), u"ParaBottomMargin"_ustr);
+ CPPUNIT_ASSERT_EQUAL(aABottom, aList2Bottom);
}

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/engine/sw/source/filter/basflt/shellio.cxx b/engine/sw/source/filter/basflt/shellio.cxx
index 157717acb848..419cb5ae915e 100644
--- a/engine/sw/source/filter/basflt/shellio.cxx
+++ b/engine/sw/source/filter/basflt/shellio.cxx
@@ -672,9 +672,6 @@ void Reader::StartPaste(SwPasteInfo& rPasteInfo)

// Step 4: Insert all content into the new node
rPasteInfo.m_rPam.Move(fnMoveBackward);
- rPasteInfo.m_rDoc.SetTextFormatColl(rPasteInfo.m_rPam, rPasteInfo.m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(
- SwPoolFormatId::COLL_STANDARD, false));
-
}

void Reader::EndPaste(SwPasteInfo& rPasteInfo)
diff --git a/engine/sw/source/filter/md/swmd.cxx b/engine/sw/source/filter/md/swmd.cxx
index bdae5e03389d..31d7a915dda5 100644
--- a/engine/sw/source/filter/md/swmd.cxx
+++ b/engine/sw/source/filter/md/swmd.cxx
@@ -568,7 +568,15 @@ void SwMarkdownParser::StartNumberedBulletListItem(MD_BLOCK_LI_DETAIL aDetail)
void SwMarkdownParser::EndNumberedBulletListItem()
{
if (m_pPam->GetPoint()->GetContentIndex())
- AppendTextNode(AM_SPACE);
+ {
+ SwMdAppendMode eMode = AM_SPACE;
+ if (!m_bNewDoc)
+ {
+ // Don't touch paragraph margins when pasting.
+ eMode = AM_NORMAL;
+ }
+ AppendTextNode(eMode);
+ }
}

void SwMarkdownParser::BeginHtmlBlock()
@@ -920,7 +928,11 @@ ErrCode SwMarkdownParser::CallParser()

SwTextFormatColl* pColl
= m_xDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(SwPoolFormatId::COLL_TEXT);
- m_xDoc->SetTextFormatColl(*m_pPam, pColl);
+ if (m_bNewDoc)
+ {
+ // Don't touch the paragraph style when pasting.
+ m_xDoc->SetTextFormatColl(*m_pPam, pColl);
+ }

ErrCode nRet;

diff --git a/engine/sw/source/filter/rtf/swparrtf.cxx b/engine/sw/source/filter/rtf/swparrtf.cxx
index 8c0c0a0aec49..e2d272462bdc 100644
--- a/engine/sw/source/filter/rtf/swparrtf.cxx
+++ b/engine/sw/source/filter/rtf/swparrtf.cxx
@@ -65,6 +65,9 @@ ErrCodeMsg SwRTFReader::Read(SwDoc& rDoc, const OUString& /*rBaseURL*/, SwPaM& r

SwPasteInfo aPasteInfo(rDoc, rPam);
StartPaste(aPasteInfo);
+ // Reset paragraph style to Body Text.
+ rDoc.SetTextFormatColl(rPam, rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(
+ SwPoolFormatId::COLL_STANDARD, false));

auto ret = ERRCODE_NONE;
SwDocShell* pDocShell(rDoc.GetDocShell());

"Michael Stahl (via cogerrit)"

unread,
Apr 22, 2026, 6:59:45 AM (7 days ago) Apr 22
to collaboraon...@googlegroups.com
engine/sw/qa/extras/rtfexport/data/FWDP90_min.rtf | 373 +++++++++++++
engine/sw/qa/extras/rtfexport/rtfexport7.cxx | 40 +
engine/sw/source/filter/basflt/shellio.cxx | 6
engine/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx | 2
engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx | 114 ++-
engine/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx | 22
engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx | 17
engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx | 76 ++
8 files changed, 558 insertions(+), 92 deletions(-)

New commits:
commit 5667f90febb0d62dc920af2c805ca54ec5238414
Author: Michael Stahl <michae...@collabora.com>
AuthorDate: Tue Apr 21 15:33:29 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed Apr 22 10:59:37 2026 +0000

sw: RTF import: ignore spurious table properties like Word, part 2

The bugdoc has several consecutive table definitions before a table, and
the first one's borders are erroneously applied to the table cells,
instead of the last one's (no borders).

Create a new struct `TableRowDef` for the top-level table cells state,
and actually clear it on `\trowd`.

Also use it for both "backup" and "previous" table row.

Move the sending of `tblStart` from `\cellx` handling to `\par` and
`\cell` where it is determined if it is actually a table.

`m_nTopLevelCells` is redundant and can be removed.

Leave the table row properties as-is for now, could be added to
`TableRowDef` later...

Unfortunately UITest_sw_table sheetToTable.sheetToTable.test_tdf116685
fails with `~SwIndexReg` assert.

This is because previously, `tblStart` was sent from `\cellx`, and in
`DomainMapper::sprmWithProps()` the `rContext` did not exist yet, so
the whole `AddDummyParaForTableInSection` was skipped; now it is done
and the `pUndoPam` in `SwReader::Read()` points to the deleted node.

Change-Id: Iba60e871e6c3ac0bc2559c975358edc14a7e2d6b
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1331
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sw/qa/extras/rtfexport/data/FWDP90_min.rtf b/engine/sw/qa/extras/rtfexport/data/FWDP90_min.rtf
new file mode 100644
index 000000000000..41e28f78b58d
--- /dev/null
+++ b/engine/sw/qa/extras/rtfexport/data/FWDP90_min.rtf
@@ -0,0 +1,373 @@
+{\rtf1\ansi\deff0\adeff0
+{\fonttbl{\f0\fbidi\froman\fcharset0\fprq2
+{\*\panose 02020603050405020304}
+{\*\falt Times New Roman}
+Times New Roman;}{\f41\fbidi\fswiss\fcharset0\fprq2
+{\*\panose 020b0604030504040204}
+{\*\falt Times New Roman}
+Tahoma;}{\f42\fbidi\fswiss\fcharset0\fprq2
+{\*\panose 020b0502040204020203}
+Segoe UI;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;
+\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255
+\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0
+\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128
+\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192
+\green192\blue192;\red153\green0\blue0;\red51\green153\blue102;\red255
+\green255\blue255;}
+\adeflang1025\ansicpg1252\stshfdbch0\stshfloch0\stshfhich0
+\stshfbi0\deflang3079\deflangfe3079\themelang3079\themelangfe0\themelangcs0
+{\*\defchp\fs22}
+{\*\defpap\ql\li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha
+\aspnum\faauto\adjustright\rin0\lin0\itap0}
+{\stylesheet{\ql\li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto
+\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\snext0\sqformat
+\spriority0 Normal;}
+{\*\cs10\additive\ssemihidden Default Paragraph Font;}
+{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3
+\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt
+\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv\ql\li0
+\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto
+\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs22\alang1025\ltrch\fcs0\fs22
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\snext11\ssemihidden
+\sunhideused Normal Table;}
+{\*\ts15\tsrowd\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs
+\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10\trbrdrv\brdrs\brdrw10
+\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3
+\trcbpat1\trcfpat1\tblind0\tblindtype0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb
+\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv\ql\li0\ri0\widctlpar
+\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1
+\af0\afs20\alang1025\ltrch\fcs0\fs20\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079\sbasedon11\snext15 Table Grid;}
+{\s16\ql\li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\itap0\rtlch\fcs1\af41\afs16\alang1025\ltrch\fcs0\f41\fs16
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\sbasedon0\snext16
+\slink18\ssemihidden Balloon Text;}{\s17\ql\li0\ri0
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+\cbpat9\rtlch\fcs1\af41\afs20\alang1025\ltrch\fcs0\f41\fs20\lang3079
+\langfe3079\cgrid\langnp3079\langfenp3079\sbasedon0\snext17\slink20
+\ssemihidden Document Map;}
+{\*\cs18\additive\rtlch\fcs1\af42\afs18\ltrch\fcs0\f42\fs18\sbasedon10
+\slink16\slocked\ssemihidden Balloon Text Char;}
+{\*\cs19\additive\rtlch\fcs1\af0\ltrch\fcs0\cf17\sbasedon10
+t1;}
+{\*\cs20\additive\rtlch\fcs1\af42\afs16\ltrch\fcs0\f42\fs16\sbasedon10
+\slink17\slocked\ssemihidden Document Map Char;}
+{\s21\ql\li0\ri0\widctlpar\tqc\tx4536\tqr\tx9072\wrapdefault\aspalpha
+\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24\alang1025
+\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079\langfenp3079
+\sbasedon0\snext21\slink23 header;}{\s22\ql\li0\ri0\widctlpar
+\tqc\tx4536\tqr\tx9072\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0
+\lin0\itap0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079
+\langfe3079\cgrid\langnp3079\langfenp3079\sbasedon0\snext22\slink25
+ footer;}
+{\*\cs23\additive\rtlch\fcs1\af0\afs24\ltrch\fcs0\fs24\sbasedon10\slink21
+\slocked\ssemihidden Header Char;}
+{\*\cs24\additive\rtlch\fcs1\ab\af0\ltrch\fcs0\b\sbasedon10
+tx1;}
+{\*\cs25\additive\rtlch\fcs1\af0\afs24\ltrch\fcs0\fs24\sbasedon10\slink22
+\slocked\ssemihidden Footer Char;}
+}
+{\*\revtbl Unknown;}
+\paperw16838\paperh11906\margl567\margr567\margt567\margb567\gutter0
+\deftab709\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1
+\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0
+\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
+\showxmlerrors0\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul
+\hyphcaps0\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin567
+\dgvorigin567\dghshow1\dgvshow1\jexpand\viewkind1\viewscale100\splytwnine
+\ftnlytwnine\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr
+\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
+\asianbrkrule\rsidroot4195955\newtblstyruls\nogrowautofit\usenormstyforlist
+\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl
+\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet
+\cachedcolbal\nouicompat\fet0
+{\*\wgrffmtfilter 013f}
+\nofeaturethrottle1\ilfomacatclnup0
+{\*\ftnsep\ltrpar\pard\plain\ltrpar\ql\li0\ri0\widctlpar\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079{\rtlch\fcs1\af0\ltrch\fcs0\chftnsep\par
+}}
+{\*\ftnsepc\ltrpar\pard\plain\ltrpar\ql\li0\ri0\widctlpar\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079{\rtlch\fcs1\af0\ltrch\fcs0\chftnsepc\par
+}}
+{\*\aftnsep\ltrpar\pard\plain\ltrpar\ql\li0\ri0\widctlpar\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079{\rtlch\fcs1\af0\ltrch\fcs0\chftnsep\par
+}}
+{\*\aftnsepc\ltrpar\pard\plain\ltrpar\ql\li0\ri0\widctlpar\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079{\rtlch\fcs1\af0\ltrch\fcs0\chftnsepc\par
+}}
+{\*\generator CIB merge 3.9.184}
+\uc1\noqfpromote{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0
+\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}
+{\*\xmlnstbl{\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\ltrsect\pgbrdrhead\pgbrdrfoot
+
+\ltrpar\sectd\ltrsect\lndscpsxn
+\psz9\linex0\headery709\footery709\colsx708\endnhere\pgbrdropt32
+\sectlinegrid360\sectdefaultcl\sftnbj
+{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang
+{\pntxta.}}
+{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang
+{\pntxta.}}
+{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang
+{\pntxta.}}
+{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang
+{\pntxta)}}
+{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang
+{\pntxtb(}
+{\pntxta)}}
+{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang
+{\pntxtb(}
+{\pntxta)}}
+{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb(}
+{\pntxta)}}
+{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang
+{\pntxtb(}
+{\pntxta)}}
+{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb(}
+{\pntxta)}}\pard\plain\ltrpar\ql\li0\ri0\widctlpar\wrapdefault\aspalpha
+\aspnum\faauto\adjustright\rin0\lin0\itap0\rtlch\fcs1\af0
+\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709
+\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18\par
+}
+{\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+\trowd\ltrrow\ts15\trgaph70\trleft-70\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs
+\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10
+\trbrdrv\brdrs\brdrw10\trftsWidth1\trftsWidthB3\trftsWidthA3\trautofit1
+\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1
+\trcfpat1\tbllkhdrrows\tbllklastrow\tbllkhdrcols
+\tbllklastcol\tblind38\tblindtype3\clvertalt\clbrdrt\brdrs\brdrw10\clbrdrl
+\brdrs\brdrw10\clbrdrb\brdrs\brdrw10\clbrdrr\brdrs\brdrw10\clcfpat1
+\clcbpat8\cltxlrtb\clftsWidth3\clwWidth2279\clcbpatraw8\clcfpatraw1
+\cellx2209\clvertalt\clbrdrt\brdrs\brdrw10\clbrdrl\brdrs\brdrw10\clbrdrb
+\brdrs\brdrw10\clbrdrr\brdrs\brdrw10\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3
+\clwWidth1372\clcbpatraw8\clcfpatraw1\cellx3581\clvertalt\clbrdrt\brdrs
+\brdrw10\clbrdrl\brdrs\brdrw10\clbrdrb\brdrs\brdrw10\clbrdrr\brdrs\brdrw10
+\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth1372\clcbpatraw8
+\clcfpatraw1\cellx4953\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar\intbl
+\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079
+\cgrid\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259
+\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079
+\langfe3079\cgrid\langnp3079\langfenp3079\trowd\ltrrow\ts15\trgaph70
+\trleft-70\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs
+\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10\trbrdrv\brdrs\brdrw10
+\trftsWidth1\trftsWidthB3\trftsWidthA3\trautofit1\trpaddl108\trpaddr108
+\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1
+\tbllkhdrrows\tbllklastrow\tbllkhdrcols\tbllklastcol\tblind38\tblindtype3
+\clvertalt\clbrdrt\brdrs\brdrw10\clbrdrl\brdrs\brdrw10\clbrdrb\brdrnone
+\clbrdrr\brdrs\brdrw10\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth2279
+\clcbpatraw8\clcfpatraw1\cellx2209\clvertalt\clbrdrt\brdrs\brdrw10\clbrdrl
+\brdrs\brdrw10\clbrdrb\brdrnone\clbrdrr\brdrs\brdrw10\clcfpat1\clcbpat8
+\cltxlrtb\clftsWidth3\clwWidth1372\clcbpatraw8\clcfpatraw1\cellx3581
+\clvertalt\clbrdrt\brdrs\brdrw10\clbrdrl\brdrs\brdrw10\clbrdrb\brdrnone
+\clbrdrr\brdrs\brdrw10\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth1372
+\clcbpatraw8\clcfpatraw1\cellx4953\pard\plain\ltrpar\ql\li0\ri0\keep
+\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0\ri0
+\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0
+\lin0\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1
+\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid
+\langnp3079\langfenp3079\trowd\ltrrow\ts15\trgaph70\trleft-70\trbrdrt\brdrs
+\brdrw10\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10
+\trbrdrh\brdrs\brdrw10\trbrdrv\brdrs\brdrw10\trftsWidth1\trftsWidthB3
+\trftsWidthA3\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddft3
+\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tbllkhdrrows
+\tbllklastrow\tbllkhdrcols\tbllklastcol\tblind38\tblindtype3\clvertalt
+\clbrdrt\brdrnone\clbrdrl\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone
+\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth2279\clcbpatraw8
+\clcfpatraw1\cellx2209\clvertalt\clbrdrt\brdrnone\clbrdrl\brdrnone\clbrdrb
+\brdrnone\clbrdrr\brdrnone\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3
+\clwWidth1372\clcbpatraw8\clcfpatraw1\cellx3581\clvertalt\clbrdrt\brdrnone
+\clbrdrl\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone\clcfpat1\clcbpat8
+\cltxlrtb\clftsWidth3\clwWidth1372\clcbpatraw8\clcfpatraw1\cellx4953\pard
+\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum
+\faauto\adjustright\rin0\lin0\yts15\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079\pard\ltrpar\qr\li0\ri0\keep\nowidctlpar\intbl\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\yts15\sectd
+\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708\endnhere
+\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj\sectd
+\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708\endnhere
+\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj\pard
+\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1\widctlpar\intbl\wrapdefault
+\aspalpha\aspnum\faauto\adjustright\rin0\lin0\rtlch\fcs1\af0\afs24
+\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar\intbl
+\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079
+\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0\ri0\keep\nowidctlpar
+\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1
+\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid
+\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar
+\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0\ri0
+\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0
+\lin0\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1
+\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid
+\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar
+\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0\ri0
+\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0
+\lin0\yts15\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259
+\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079
+\langfe3079\cgrid\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\keep
+\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0\ri0
+\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0
+\lin0\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1
+\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid
+\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar
+\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\sectd\ltrsect\lndscpsxn
+\psz9\linex0\headery709\footery709\colsx708\endnhere\pgbrdropt32
+\sectlinegrid360\sectdefaultcl\sftnbj\pard\ltrpar\qr\li0
+\ri0\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0
+\headery709\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360
+\sectdefaultcl\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0
+\headery709\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360
+\sectdefaultcl\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160
+\sl259\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto
+\adjustright\rin0\lin0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\plain\ltrpar\ql\li0
+\ri0\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0
+\fs24\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\qr\li0
+\ri0\keep\nowidctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright
+\rin0\lin0\yts15\sectd\ltrsect\lndscpsxn\psz9\linex0
+\headery709\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360
+\sectdefaultcl\sftnbj\sectd\ltrsect\lndscpsxn\psz9\linex0
+\headery709\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360
+\sectdefaultcl\sftnbj\pard\plain\ltrpar\ql\li0\ri0\sa160
+\sl259\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto
+\adjustright\rin0\lin0\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24
+\lang3079\langfe3079\cgrid\langnp3079\langfenp3079\pard\ltrpar\ql\li0\ri0
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0
+{\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709
+\footery709\colsx708\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl
+\sftnbj{\rtlch\fcs1\af0\afs18\ltrch\fcs0\fs18\cf1
+\par
+}\trowd\ltrrow\ts15\trgaph70\trleft-70\trbrdrt\brdrs\brdrw10\trbrdrl\brdrs
+\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh\brdrs\brdrw10
+\trbrdrv\brdrs\brdrw10\trftsWidth1\trftsWidthB3\trftsWidthA3\trautofit1
+\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1
+\trcfpat1\tbllkhdrrows\tbllklastrow\tbllkhdrcols
+\tbllklastcol\tblind38\tblindtype3\clvertalt\clbrdrt\brdrnone\clbrdrl
+\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone\clcfpat1\clcbpat8\cltxlrtb
+\clftsWidth3\clwWidth2279\clcbpatraw8\clcfpatraw1\cellx2209\clvertalt
+\clbrdrt\brdrnone\clbrdrl\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone
+\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth1372\clcbpatraw8
+\clcfpatraw1\cellx3581\pard\plain\ltrpar\ql\li0\ri0\keep\nowidctlpar\intbl
+\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0
+\yts15\rtlch\fcs1\af0\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079
+\cgrid\langnp3079\langfenp3079{\rtlch\fcs1\af0\afs18\ltrch\fcs0\fs18\cf1
+ Einkommen der letzten\cell
+3 Monate\cell
+}\pard\plain\ltrpar\ql\li0\ri0\sa160\sl259\slmult1\widctlpar\intbl
+\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\rtlch\fcs1\af0
+\afs24\alang1025\ltrch\fcs0\fs24\lang3079\langfe3079\cgrid\langnp3079
+\langfenp3079{\rtlch\fcs1\af0\afs18\ltrch\fcs0\fs18\cf1
+\trowd\ltrrow\ts15\trgaph70\trleft-70\trbrdrt\brdrs\brdrw10
+\trbrdrl\brdrs\brdrw10\trbrdrb\brdrs\brdrw10\trbrdrr\brdrs\brdrw10\trbrdrh
+\brdrs\brdrw10\trbrdrv\brdrs\brdrw10\trftsWidth1\trftsWidthB3\trftsWidthA3
+\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3
+\trcbpat1\trcfpat1\tbllkhdrrows\tbllklastrow\tbllkhdrcols
+\tbllklastcol\tblind38\tblindtype3\clvertalt\clbrdrt\brdrnone\clbrdrl
+\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone\clcfpat1\clcbpat8\cltxlrtb
+\clftsWidth3\clwWidth2279\clcbpatraw8\clcfpatraw1\cellx2209\clvertalt
+\clbrdrt\brdrnone\clbrdrl\brdrnone\clbrdrb\brdrnone\clbrdrr\brdrnone
+\clcfpat1\clcbpat8\cltxlrtb\clftsWidth3\clwWidth1372\clcbpatraw8
+\clcfpatraw1\cellx3581\row
+}
+}
+}}
+\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+\sectd\ltrsect\lndscpsxn\psz9\linex0\headery709\footery709\colsx708
+\endnhere\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj
+{\rtlch\fcs1\af0\afs18\ltrch\fcs0\v\fs18
+\line
+}}
+\sectd\ltrsect\lndscpsxn\linex0\headery709\footery709\colsx708\endnhere
+\pgbrdropt32\sectlinegrid360\sectdefaultcl\sftnbj{\rtlch
+\fcs1\af0\afs18\ltrch\fcs0\v\fs18\par
+}
+}
diff --git a/engine/sw/qa/extras/rtfexport/rtfexport7.cxx b/engine/sw/qa/extras/rtfexport/rtfexport7.cxx
index fe0fcf47e1b0..6b1e841f5720 100644
--- a/engine/sw/qa/extras/rtfexport/rtfexport7.cxx
+++ b/engine/sw/qa/extras/rtfexport/rtfexport7.cxx
@@ -888,6 +888,46 @@ CPPUNIT_TEST_FIXTURE(Test, testItapIntblCell)
verify("reload");
}

+CPPUNIT_TEST_FIXTURE(Test, testIgnoreTableDefinitionBorders)
+{
+ createSwDoc("FWDP90_min.rtf");
+
+ auto verify = [this]() {
+ uno::Reference<text::XTextTable> xTable{ getParagraphOrTable(3), uno::UNO_QUERY };
+ uno::Reference<text::XTextRange> xA1(xTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
+ // problem was that the cells had borders from an unused table definition
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xA1, u"TopBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xA1, u"BottomBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xA1, u"LeftBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xA1, u"RightBorder"_ustr));
+ uno::Reference<text::XTextRange> xB1(xTable->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xB1, u"TopBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xB1, u"BottomBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xB1, u"LeftBorder"_ustr));
+ CPPUNIT_ASSERT_BORDER_EQUAL(
+ table::BorderLine2(0x000000, 0, 0, 0, table::BorderLineStyle::NONE, 0),
+ getProperty<table::BorderLine2>(xB1, u"RightBorder"_ustr));
+ };
+
+ verify();
+ saveAndReload(TestFilter::RTF);
+ verify();
+}
+
CPPUNIT_TEST_FIXTURE(Test, testTdf113550)
{
auto verify = [this]() {
diff --git a/engine/sw/source/filter/basflt/shellio.cxx b/engine/sw/source/filter/basflt/shellio.cxx
index 419cb5ae915e..3cca73aef383 100644
--- a/engine/sw/source/filter/basflt/shellio.cxx
+++ b/engine/sw/source/filter/basflt/shellio.cxx
@@ -178,12 +178,14 @@ ErrCodeMsg SwReader::Read( const Reader& rOptions )

mxDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::Ignore );

- std::optional<SwPaM> pUndoPam;
+ ::std::shared_ptr<SwUnoCursor> pUndoPam;
if( bDocUndo || mpCursor )
{
// set Pam to the previous node, so that it is not also moved
const SwNode& rTmp = pPam->GetPoint()->GetNode();
- pUndoPam.emplace( rTmp, rTmp, SwNodeOffset(0), SwNodeOffset(-1) );
+ pUndoPam = mxDoc->CreateUnoCursor(*pPam->GetPoint(), false);
+ pUndoPam->SetMark();
+ *pUndoPam->GetPoint() = SwPosition(rTmp, SwNodeOffset(-1));
}

// store for now all Fly's
diff --git a/engine/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx b/engine/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx
index 6b1165972db4..2ea1670e46a2 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx
@@ -590,7 +590,7 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
m_aStates.top().getParagraphSprms() = m_aDefaultState.getParagraphSprms();
m_aStates.top().getParagraphAttributes() = m_aDefaultState.getParagraphAttributes();

- if (m_nTopLevelCells != 0 || m_nNestedCells != 0)
+ if (m_TopLevelTableRow.getCells() != 0 || m_nNestedCells != 0)
{
// Ideally getDefaultSPRM() would take care of this, but it would not when we're buffering.
// TODO: is this the right place to do this?
diff --git a/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx b/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
index 4ddd44bc1078..6604f4ad72d8 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
@@ -24,6 +24,37 @@ using namespace com::sun::star;

namespace writerfilter::rtftok
{
+void RTFDocumentImpl::checkTableStart()
+{
+ if (m_TopLevelTableRow.checkTableStart())
+ {
+ // Wasn't in table, but now is -> tblStart.
+ // (this detection only works if the table definition
+ // precedes the cells...)
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+}
+
+void RTFDocumentImpl::checkTableEnd()
+{
+ // Not in table? Reset max width.
+ if (m_TopLevelTableRow.checkTableEnd())
+ {
+ // Was in table, but not anymore -> tblEnd.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblEnd, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+}
+
RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
{
setNeedSect(true);
@@ -124,30 +155,24 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
pCurrentBuffer->push_back(Buf_t(RTFBufferTypes::PAR, pValue, nullptr));
}

- if (!isTable)
+ if (isTable)
+ {
+ checkTableStart();
+ }
+ else
{
// Not actually in table!
// Clear the buffer so this new \par will not be seen
// when next \par or \cell checks the buffer.
replayBuffer(*pCurrentBuffer, nullptr, nullptr);
assert(pCurrentBuffer->empty());
+ checkTableEnd();
}
}
else
{
parBreak();
- // Not in table? Reset max width.
- if (m_nCellxMax)
- {
- // Was in table, but not anymore -> tblEnd.
- RTFSprms aAttributes;
- RTFSprms aSprms;
- aSprms.set(NS_ooxml::LN_tblEnd, new RTFValue(1));
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
- Mapper().props(pProperties);
- }
- m_nCellxMax = 0;
+ checkTableEnd();
}

// but don't emit properties yet, since they may change till the first text token arrives
@@ -238,6 +263,7 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
// if there was no \par, it is also a table regardless of \itap
if (iter == pCurrentBuffer->end() || ::std::get<0>(*iter) == RTFBufferTypes::Props)
{
+ checkTableStart(); // testTdf59454
// must send *all* paragraph properties (testTdf164945),
// else getDefaultSPRM() will overwrite things
oSprms.emplace(m_aStates.top().getParagraphSprms());
@@ -309,7 +335,7 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
RTFConflictPolicy::Append);
dispatchSymbol(RTFKeyword::CELL);
// Adjust total width, which is done in the \cellx handler for normal cells.
- m_nTopLevelCurrentCellX += m_aStates.top().getTableRowWidthAfter();
+ m_TopLevelTableRow.nCurrentCellX += m_aStates.top().getTableRowWidthAfter();

int nCellCount = 0;
for (Buf_t& i : m_aTableBufferStack.back())
@@ -317,20 +343,19 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
if (RTFBufferTypes::CellEnd == std::get<0>(i))
++nCellCount;
}
- if (m_nTopLevelCells < nCellCount)
+ if (m_TopLevelTableRow.getCells() < o3tl::make_unsigned(nCellCount))
{
- m_nTopLevelCells++;
- m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
- m_aTopLevelTableCellsAttributes.push_back(
+ m_TopLevelTableRow.cellSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_TopLevelTableRow.cellAttributes.push_back(
m_aStates.top().getTableCellAttributes());
}

- if (m_aTopLevelTableCellsSprms.size() >= o3tl::make_unsigned(nCellCount))
+ if (m_TopLevelTableRow.getCells() >= o3tl::make_unsigned(nCellCount))
{
Id aBorderIds[]
= { NS_ooxml::LN_CT_TcBorders_bottom, NS_ooxml::LN_CT_TcBorders_top,
NS_ooxml::LN_CT_TcBorders_left, NS_ooxml::LN_CT_TcBorders_right };
- RTFSprms& rCurrentCellSprms = m_aTopLevelTableCellsSprms[nCellCount - 1];
+ RTFSprms& rCurrentCellSprms{ m_TopLevelTableRow.cellSprms[nCellCount - 1] };
for (size_t i = 0; i < 4; i++)
{
RTFSprms aAttributes;
@@ -395,39 +420,37 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
bool bRestored = false;
// Ending a row, but no cells defined?
// See if there was an invalid table row reset, so we can restore cell infos to help invalid documents.
- if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX)
+ if (!m_TopLevelTableRow.nCurrentCellX && m_BackupTopLevelTableRow.nCurrentCellX)
{
restoreTableRowProperties();
bRestored = true;
}

- // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell
- const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
- if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY)
+ if (m_TopLevelTableRow.getCells() != 0)
{
- auto pXValueLast = m_aStates.top().getTableRowSprms().find(
- NS_ooxml::LN_CT_TblGridBase_gridCol, false);
- const int nXValueLast = pXValueLast ? pXValueLast->getInt() : 0;
- auto pXValue = new RTFValue(nXValueLast + m_nCellxMax - m_nTopLevelCurrentCellX);
- m_aStates.top().getTableRowSprms().eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol);
- m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
- RTFConflictPolicy::Append);
- m_nTopLevelCurrentCellX = m_nCellxMax;
- }
+ // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell
+ const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
+ if ((m_TopLevelTableRow.nCellXMax - m_TopLevelTableRow.nCurrentCellX) >= MINLAY)
+ {
+ auto pXValueLast = m_aStates.top().getTableRowSprms().find(
+ NS_ooxml::LN_CT_TblGridBase_gridCol, false);
+ const int nXValueLast = pXValueLast ? pXValueLast->getInt() : 0;
+ auto pXValue = new RTFValue(nXValueLast + m_TopLevelTableRow.nCellXMax
+ - m_TopLevelTableRow.nCurrentCellX);
+ m_aStates.top().getTableRowSprms().eraseLast(
+ NS_ooxml::LN_CT_TblGridBase_gridCol);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol,
+ pXValue, RTFConflictPolicy::Append);
+ m_TopLevelTableRow.nCurrentCellX = m_TopLevelTableRow.nCellXMax;
+ }

- if (m_nTopLevelCells)
- {
// Make a backup before we start popping elements
- m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms;
- m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes;
- m_nInheritingCells = m_nTopLevelCells;
+ m_PreviousTopLevelTableRow = m_TopLevelTableRow;
}
else
{
// No table definition? Then inherit from the previous row
- m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms;
- m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes;
- m_nTopLevelCells = m_nInheritingCells;
+ m_TopLevelTableRow = m_PreviousTopLevelTableRow;
}

while (m_aTableBufferStack.size() > 1)
@@ -444,8 +467,9 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
m_aTableBufferStack.pop_back();
}

- replayRowBuffer(m_aTableBufferStack.back(), m_aTopLevelTableCellsSprms,
- m_aTopLevelTableCellsAttributes, m_nTopLevelCells);
+ auto const nCells{ m_TopLevelTableRow.getCells() }; // replayRowBuffer clears it!
+ replayRowBuffer(m_aTableBufferStack.back(), m_TopLevelTableRow.cellSprms,
+ m_TopLevelTableRow.cellAttributes, nCells);

// The scope of the table cell defaults is one row.
m_aDefaultState.getTableCellSprms().clear();
@@ -456,13 +480,13 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
writerfilter::Reference<Properties>::Pointer_t frameProperties;
writerfilter::Reference<Properties>::Pointer_t rowProperties;
prepareProperties(m_aStates.top(), paraProperties, frameProperties, rowProperties,
- m_nTopLevelCells, m_nTopLevelCurrentCellX, m_nTopLevelTRLeft);
+ nCells, m_TopLevelTableRow.nCurrentCellX, m_TopLevelTableRow.nTRLeft);
sendProperties(paraProperties, frameProperties, rowProperties);

m_bNeedPap = true;
m_bNeedFinalPar = true;
m_aTableBufferStack.back().clear();
- m_nTopLevelCells = 0;
+ m_TopLevelTableRow.reset();
// reset buffer => outside of table, until next \trowd
// table buffer is our own concept, doesn't map to RTF pushState/popState
// ... see test165805Tdf where \row is in deeper scope than \intbl
diff --git a/engine/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx b/engine/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
index ebc654e64acf..0a77c5bf9a06 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
@@ -394,7 +394,7 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
int& rCurrentCellX(
(Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
? m_nNestedCurrentCellX
- : m_nTopLevelCurrentCellX);
+ : m_TopLevelTableRow.nCurrentCellX);
int nCellWidth = nParam - rCurrentCellX;
rCurrentCellX = nParam;
auto pXValue = new RTFValue(nCellWidth);
@@ -409,26 +409,16 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
}
else
{
- m_nTopLevelCells++;
// Push cell properties.
- m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
- m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ m_TopLevelTableRow.cellSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_TopLevelTableRow.cellAttributes.push_back(
+ m_aStates.top().getTableCellAttributes());
+ m_TopLevelTableRow.setCellXMax();
}

m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
// Don't assume that following text is in a table!
- if (!m_nCellxMax)
- {
- // Wasn't in table, but now is -> tblStart.
- RTFSprms aAttributes;
- RTFSprms aSprms;
- aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
- writerfilter::Reference<Properties>::Pointer_t pProperties
- = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
- Mapper().props(pProperties);
- }
- m_nCellxMax = std::max(m_nCellxMax, nParam);
return true;
}
break;
@@ -461,7 +451,7 @@ bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
auto const aDestination = m_aStates.top().getDestination();
int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination)
? m_nNestedTRLeft
- : m_nTopLevelTRLeft);
+ : m_TopLevelTableRow.nTRLeft);
rCurrentTRLeft = nParam;
return true;
}
diff --git a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx
index 5a1bbf150878..2c473595247f 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx
@@ -317,13 +317,8 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x
, m_bNeedPar(true)
, m_bNeedFinalPar(false)
, m_nNestedCells(0)
- , m_nTopLevelCells(0)
- , m_nInheritingCells(0)
, m_nNestedTRLeft(0)
- , m_nTopLevelTRLeft(0)
, m_nNestedCurrentCellX(0)
- , m_nTopLevelCurrentCellX(0)
- , m_nBackupTopLevelCurrentCellX(0)
, m_aTableBufferStack(1) // create top-level buffer already
, m_pSuperstream(nullptr)
, m_nStreamType(0)
@@ -343,7 +338,6 @@ RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& x
, m_bWasInFrame(false)
, m_bHadPicture(false)
, m_bHadSect(false)
- , m_nCellxMax(0)
, m_nListPictureId(0)
, m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault(u"InsertMode"_ustr, false))
, m_rMediaDescriptor(rMediaDescriptor)
@@ -1668,7 +1662,7 @@ void RTFDocumentImpl::text(OUString& rString)

// Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
- && m_nTopLevelCells == 0)
+ && m_TopLevelTableRow.getCells() == 0)
{
m_aTableBufferStack.back().emplace_back(RTFBufferTypes::UText, new RTFValue(rString),
nullptr);
@@ -1990,11 +1984,11 @@ bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, cons

void RTFDocumentImpl::backupTableRowProperties()
{
- if (m_nTopLevelCurrentCellX)
+ if (m_TopLevelTableRow.nCurrentCellX)
{
m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
- m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
+ m_BackupTopLevelTableRow = m_TopLevelTableRow;
}
}

@@ -2002,7 +1996,7 @@ void RTFDocumentImpl::restoreTableRowProperties()
{
m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
- m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
+ m_TopLevelTableRow = m_BackupTopLevelTableRow;
}

void RTFDocumentImpl::resetTableRowProperties()
@@ -2018,8 +2012,7 @@ void RTFDocumentImpl::resetTableRowProperties()
}
else
{
- m_nTopLevelTRLeft = 0;
- m_nTopLevelCurrentCellX = 0;
+ m_TopLevelTableRow.reset();
}
}

diff --git a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
index 4ac391327eaa..bc6ed52c4fdb 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
@@ -811,6 +811,8 @@ private:
void checkUnicode(bool bUnicode, bool bHex);
/// If we need a final section break at the end of the document.
void setNeedSect(bool bNeedSect);
+ void checkTableStart();
+ void checkTableEnd();
void resetTableRowProperties();
void backupTableRowProperties();
void restoreTableRowProperties();
@@ -877,6 +879,60 @@ private:

std::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;

+ struct TableRowDef
+ {
+ /// cell props
+ std::deque<RTFSprms> cellSprms;
+ std::deque<RTFSprms> cellAttributes;
+
+ /// Left row margin
+ int nTRLeft{ 0 };
+
+ /// Current cellx value (top-level table)
+ int nCurrentCellX{ 0 };
+
+ /// Max width of the rows in the current table.
+ int nCellXMax{ 0 };
+ bool isStartTable{ false };
+
+ void reset()
+ {
+ cellSprms.clear();
+ cellAttributes.clear();
+ nTRLeft = 0;
+ nCurrentCellX = 0;
+ // leave nCellXMax / isStartTable alone - very special handling!
+ }
+
+ void setCellXMax()
+ {
+ if (nCellXMax == 0)
+ {
+ isStartTable = true;
+ }
+ nCellXMax = ::std::max(nCurrentCellX, nCellXMax);
+ }
+ bool checkTableStart()
+ {
+ bool const ret{ isStartTable };
+ isStartTable = false;
+ return ret;
+ }
+ bool checkTableEnd()
+ {
+ bool const ret{ nCellXMax != 0 };
+ nCellXMax = 0;
+ return ret;
+ }
+
+ size_t getCells() { return cellSprms.size(); }
+ };
+
+ /// cell props buffer for top-level table, reset by \row or \trowd
+ TableRowDef m_TopLevelTableRow;
+ /// backup of top-level props, to support inheriting cell props
+ TableRowDef m_PreviousTopLevelTableRow;
+
/// cell props buffer for nested tables, reset by \nestrow
/// the \nesttableprops is a destination and must follow the
/// nested cells, so it should be sufficient to store the
@@ -884,28 +940,18 @@ private:
int m_nNestedCells;
std::deque<RTFSprms> m_aNestedTableCellsSprms;
std::deque<RTFSprms> m_aNestedTableCellsAttributes;
- /// cell props buffer for top-level table, reset by \row
- int m_nTopLevelCells;
- std::deque<RTFSprms> m_aTopLevelTableCellsSprms;
- std::deque<RTFSprms> m_aTopLevelTableCellsAttributes;
- /// backup of top-level props, to support inheriting cell props
- int m_nInheritingCells;
- std::deque<RTFSprms> m_aTableInheritingCellsSprms;
- std::deque<RTFSprms> m_aTableInheritingCellsAttributes;

- // Left row margin (for nested and top-level rows)
+ // Left row margin (for nested rows)
int m_nNestedTRLeft;
- int m_nTopLevelTRLeft;

/// Current cellx value (nested table)
int m_nNestedCurrentCellX;
- /// Current cellx value (top-level table)
- int m_nTopLevelCurrentCellX;

- // Backup of what \trowd clears, to work around invalid input.
+ // Backup of what \trowd clears, purely to work around input that Word
+ // considers invalid but which OpenOffice.org was able to import as table.
RTFSprms m_aBackupTableRowSprms;
RTFSprms m_aBackupTableRowAttributes;
- int m_nBackupTopLevelCurrentCellX;
+ TableRowDef m_BackupTopLevelTableRow;

/// Buffered table cells, till cell definitions are not reached.
/// for nested table, one buffer per table level
@@ -978,8 +1024,6 @@ private:
bool m_bHadPicture;
/// The document has multiple sections.
bool m_bHadSect;
- /// Max width of the rows in the current table.
- int m_nCellxMax;
/// ID of the next \listlevel picture.
int m_nListPictureId;


"Michael Stahl (via cogerrit)"

unread,
Apr 23, 2026, 3:06:25 AM (6 days ago) Apr 23
to collaboraon...@googlegroups.com
engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx | 8 ++++----
engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx | 1 +
2 files changed, 5 insertions(+), 4 deletions(-)

New commits:
commit 159c389eee4a1986403aa307b93c0c9f5f765534
Author: Michael Stahl <michae...@collabora.com>
AuthorDate: Wed Apr 22 13:33:38 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu Apr 23 07:05:34 2026 +0000

sw: RTF import: fix signedness of cell counter variables

Change-Id: I20c94254eee8c612a6bcdd88c47e911aa66000f4
Signed-off-by: Michael Stahl <michae...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1382
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx b/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
index 6604f4ad72d8..d30c42a45df8 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
@@ -337,20 +337,20 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
// Adjust total width, which is done in the \cellx handler for normal cells.
m_TopLevelTableRow.nCurrentCellX += m_aStates.top().getTableRowWidthAfter();

- int nCellCount = 0;
+ size_t nCellCount{ 0 };
for (Buf_t& i : m_aTableBufferStack.back())
{
if (RTFBufferTypes::CellEnd == std::get<0>(i))
++nCellCount;
}
- if (m_TopLevelTableRow.getCells() < o3tl::make_unsigned(nCellCount))
+ if (m_TopLevelTableRow.getCells() < nCellCount)
{
m_TopLevelTableRow.cellSprms.push_back(m_aStates.top().getTableCellSprms());
m_TopLevelTableRow.cellAttributes.push_back(
m_aStates.top().getTableCellAttributes());
}

- if (m_TopLevelTableRow.getCells() >= o3tl::make_unsigned(nCellCount))
+ if (m_TopLevelTableRow.getCells() >= nCellCount)
{
Id aBorderIds[]
= { NS_ooxml::LN_CT_TcBorders_bottom, NS_ooxml::LN_CT_TcBorders_top,
@@ -377,7 +377,7 @@ RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
//Overwrite font size attribute on fill cells
RTFValue::Pointer_t pFontSize;
RTFValue::Pointer_t pFontSizeCs;
- int nCell = 1;
+ size_t nCell{ 1 };
for (Buf_t& rTableBufferElement : m_aTableBufferStack.back())
{
if (RTFBufferTypes::CellEnd == std::get<0>(rTableBufferElement))
diff --git a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
index bc6ed52c4fdb..cb94c2716b71 100644
--- a/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
+++ b/engine/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
@@ -879,6 +879,7 @@ private:

std::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;

+ /// table row definition, store state of table cells, see <tbldef>/<celldef>
struct TableRowDef
{
/// cell props

"Karthik (via cogerrit)"

unread,
Apr 24, 2026, 1:15:51 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sw/qa/extras/ooxmlimport/data/tdf171762.docx |binary
engine/sw/qa/extras/ooxmlimport/ooxmlimport.cxx | 9 +++++
engine/sw/source/writerfilter/dmapper/DomainMapper.cxx | 26 +++++++++++++++--
engine/sw/source/writerfilter/dmapper/PropertyIds.cxx | 2 +
engine/sw/source/writerfilter/dmapper/PropertyIds.hxx | 2 +
5 files changed, 36 insertions(+), 3 deletions(-)

New commits:
commit 9fce988742260ef35024a6f4af60e662ef01eb55
Author: Karthik <karthi...@collabora.com>
AuthorDate: Wed Apr 22 16:39:04 2026 +0530
Commit: Karthik Godha <karthi...@collabora.com>
CommitDate: Fri Apr 24 05:15:03 2026 +0000

tdf#171762: Font's charset property is never used

<w:font> element contains a child element <w:charset>, which denotes
the font's charset value, `<w:charset w:val="02"/>` indicates that its
a symbol font. This value is properly imported and stored in the
FontEntry.

But when processing the text runs, we do not use the charset property
of the font.

Change-Id: If791c52a3a3678be47a158b8e763d38e339b03fc
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1388
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Michael Stahl <michae...@collabora.com>

diff --git a/engine/sw/qa/extras/ooxmlimport/data/tdf171762.docx b/engine/sw/qa/extras/ooxmlimport/data/tdf171762.docx
new file mode 100644
index 000000000000..d12b25157df9
Binary files /dev/null and b/engine/sw/qa/extras/ooxmlimport/data/tdf171762.docx differ
diff --git a/engine/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/engine/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
index a1789141036a..31c136985f36 100644
--- a/engine/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
+++ b/engine/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
@@ -1558,6 +1558,15 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf103664)
CPPUNIT_ASSERT_EQUAL(awt::CharSet::SYMBOL, getProperty<sal_Int16>(xRun, u"CharFontCharSet"_ustr));
}

+CPPUNIT_TEST_FIXTURE(Test, testTdf171762)
+{
+ createSwDoc("tdf171762.docx");
+ uno::Reference<text::XTextRange> xPara(getParagraph(1));
+ uno::Reference<beans::XPropertySet> xRun(getRun(xPara, 2), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(u"Wingdings 2"_ustr, getProperty<OUString>(xRun, u"CharFontName"_ustr));
+ CPPUNIT_ASSERT_EQUAL(awt::CharSet::SYMBOL, getProperty<sal_Int16>(xRun, u"CharFontCharSet"_ustr));
+}
+
CPPUNIT_TEST_FIXTURE(Test, testTdf82824)
{
createSwDoc("tdf82824.docx");
diff --git a/engine/sw/source/writerfilter/dmapper/DomainMapper.cxx b/engine/sw/source/writerfilter/dmapper/DomainMapper.cxx
index 378c7e4decd5..ac075a32d74c 100644
--- a/engine/sw/source/writerfilter/dmapper/DomainMapper.cxx
+++ b/engine/sw/source/writerfilter/dmapper/DomainMapper.cxx
@@ -433,10 +433,14 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val)

// Set the matching font family if we have one.
FontEntry::Pointer_t pFontEntry = m_pImpl->GetFontTable()->getFontEntryByName(sStringValue);
- if (pFontEntry && pFontEntry->m_nFontFamily != awt::FontFamily::DONTKNOW)
+ if (pFontEntry)
{
- m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_FAMILY,
- uno::Any(pFontEntry->m_nFontFamily));
+ if (pFontEntry->m_nFontFamily != awt::FontFamily::DONTKNOW)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_FAMILY,
+ uno::Any(pFontEntry->m_nFontFamily));
+ if (pFontEntry->nTextEncoding == RTL_TEXTENCODING_SYMBOL)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_CHAR_SET,
+ uno::Any(awt::CharSet::SYMBOL));
}
}
break;
@@ -461,7 +465,15 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val)
break;
case NS_ooxml::LN_CT_Fonts_eastAsia:
if (m_pImpl->GetTopContext())
+ {
m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( sStringValue ));
+
+ FontEntry::Pointer_t pFontEntry
+ = m_pImpl->GetFontTable()->getFontEntryByName(sStringValue);
+ if (pFontEntry && pFontEntry->nTextEncoding == RTL_TEXTENCODING_SYMBOL)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_CHAR_SET_ASIAN,
+ uno::Any(awt::CharSet::SYMBOL));
+ }
break;
case NS_ooxml::LN_CT_Fonts_eastAsiaTheme:
m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, u"eastAsiaTheme"_ustr, ThemeHandler::getStringForTheme(nIntValue));
@@ -475,7 +487,15 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val)
break;
case NS_ooxml::LN_CT_Fonts_cs:
if (m_pImpl->GetTopContext())
+ {
m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( sStringValue ));
+
+ FontEntry::Pointer_t pFontEntry
+ = m_pImpl->GetFontTable()->getFontEntryByName(sStringValue);
+ if (pFontEntry && pFontEntry->nTextEncoding == RTL_TEXTENCODING_SYMBOL)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_CHAR_SET_COMPLEX,
+ uno::Any(awt::CharSet::SYMBOL));
+ }
break;
case NS_ooxml::LN_CT_Fonts_cstheme:
m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, u"cstheme"_ustr, ThemeHandler::getStringForTheme(nIntValue));
diff --git a/engine/sw/source/writerfilter/dmapper/PropertyIds.cxx b/engine/sw/source/writerfilter/dmapper/PropertyIds.cxx
index 187c8e8111cd..9b35f314ea94 100644
--- a/engine/sw/source/writerfilter/dmapper/PropertyIds.cxx
+++ b/engine/sw/source/writerfilter/dmapper/PropertyIds.cxx
@@ -55,6 +55,8 @@ const OUString & getPropertyName( PropertyIds eId )
{ PROP_CHAR_STYLE_NAME, u"CharStyleName"_ustr},
{ PROP_CHAR_FONT_NAME, u"CharFontName"_ustr},
{ PROP_CHAR_FONT_CHAR_SET, u"CharFontCharSet"_ustr},
+ { PROP_CHAR_FONT_CHAR_SET_ASIAN, u"CharFontCharSetAsian"_ustr},
+ { PROP_CHAR_FONT_CHAR_SET_COMPLEX, u"CharFontCharSetComplex"_ustr},
{ PROP_CHAR_FONT_NAME_ASIAN, u"CharFontNameAsian"_ustr},
{ PROP_CHAR_HEIGHT_ASIAN, u"CharHeightAsian"_ustr},
{ PROP_CHAR_FONT_NAME_COMPLEX, u"CharFontNameComplex"_ustr},
diff --git a/engine/sw/source/writerfilter/dmapper/PropertyIds.hxx b/engine/sw/source/writerfilter/dmapper/PropertyIds.hxx
index 9d2257303775..d37b4e651313 100644
--- a/engine/sw/source/writerfilter/dmapper/PropertyIds.hxx
+++ b/engine/sw/source/writerfilter/dmapper/PropertyIds.hxx
@@ -84,6 +84,8 @@ enum PropertyIds
,PROP_CHAR_ESCAPEMENT_HEIGHT
,PROP_CHAR_FLASH
,PROP_CHAR_FONT_CHAR_SET
+ ,PROP_CHAR_FONT_CHAR_SET_ASIAN
+ ,PROP_CHAR_FONT_CHAR_SET_COMPLEX
,PROP_CHAR_FONT_NAME
,PROP_CHAR_FONT_NAME_ASIAN
,PROP_CHAR_FONT_NAME_COMPLEX

"Miklos Vajna (via cogerrit)"

unread,
Apr 24, 2026, 7:48:53 AM (5 days ago) Apr 24
to collaboraon...@googlegroups.com
engine/sw/qa/core/doc/DocumentRedlineManager.cxx | 46 +++++++++++++++++++
engine/sw/source/core/doc/DocumentRedlineManager.cxx | 14 +++++
2 files changed, 59 insertions(+), 1 deletion(-)

New commits:
commit bd7f20bdf7d1e66ab13c46074c0482ccab6d6867
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Fri Apr 24 08:39:58 2026 +0200
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Fri Apr 24 11:48:37 2026 +0000

cool#15451 sw interdependent redlines: fix creating a format on top of format-on-delete

Enable track changes, delete a sentence, select the deleted text, format
the selection as bold, then format as italics: the delete redline is
lost.

What happens is that we first have a format-on-delete redline. But then
we try to insert a new format redline for italic, Writer doesn't know
how to combine this new format redline with the existing
format-on-delete redline, so it deletes the old redline by default.

Fix the problem by not creating the new redline in this case. This works
because the format redline needs to deal with the old format and the new
format. If you apply a new formatting, the old format doesn't change and
the new format goes to the model. This means that not creating the new
redline preserves the old delete redline and accept/reject works
correctly, too.

Regression from commit eef0dfed817e40cd83e8ba8e290f45c224257f97
(tdf#166319 sw interdependent redlines: add UI to create format inside
insert, 2025-06-12), previously simply no format redline was created, so
the delete redline wasn't lost.

Change-Id: Ia81b748fd5095bc9141117197edac9d21d95f834
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1478
Reviewed-by: Caolán McNamara <caolan....@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/core/doc/DocumentRedlineManager.cxx b/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
index fbab59d08ee5..1e7aa236078c 100644
--- a/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -10,6 +10,7 @@
#include <swmodeltestbase.hxx>

#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/propertyvalue.hxx>

@@ -437,6 +438,51 @@ CPPUNIT_TEST_FIXTURE(Test, testFormatThenDel)
CPPUNIT_ASSERT(!rRedlineData.Next());
}
}
+
+CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatFormat)
+{
+ // Given a document with "test" that has a delete redline and a bold
+ // format redline applied on top of it:
+ createSwDoc();
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ pWrtShell->Insert(u"test"_ustr);
+ pDocShell->SetChangeRecording(true);
+ SwView& rView = pWrtShell->GetView();
+ pWrtShell->SelAll();
+ pWrtShell->DelLeft();
+ pWrtShell->SelAll();
+ {
+ SvxWeightItem aWeightItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
+ SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet(rView.GetPool());
+ aSet.Put(aWeightItem);
+ pWrtShell->SetAttrSet(aSet);
+ }
+
+ // When applying an additional italic format on the same range:
+ {
+ SvxPostureItem aPostureItem(ITALIC_NORMAL, RES_CHRATR_POSTURE);
+ SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet(rView.GetPool());
+ aSet.Put(aPostureItem);
+ pWrtShell->SetAttrSet(aSet);
+ }
+
+ // Then make sure the delete-then-format stack is kept unchanged, instead
+ // of being replaced with a single plain format redline:
+ SwDoc* pDoc = pDocShell->GetDoc();
+ IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+ SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+ const SwRedlineData& rRedlineData = rRedlines[0]->GetRedlineData(0);
+ CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData.GetType());
+ // Without the accompanying fix in place, this test would have failed here,
+ // i.e. the new italic redline destroyed the existing format-on-delete
+ // redline, losing the underlying delete redline.
+ CPPUNIT_ASSERT(rRedlineData.Next());
+ const SwRedlineData& rRedlineData2 = *rRedlineData.Next();
+ CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType());
+ CPPUNIT_ASSERT(!rRedlineData2.Next());
+}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/engine/sw/source/core/doc/DocumentRedlineManager.cxx b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
index 668654e66e17..38219390f53f 100644
--- a/engine/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -2342,8 +2342,20 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
case RedlineType::Format:
switch( rCtx.eCmpPos )
{
- case SwComparePosition::Outside:
case SwComparePosition::Equal:
+ if (rCtx.pRedl->GetRedlineData(0).Next())
+ {
+ // rCtx.pRedl already has an underlying redline data entry (insert/delete) and
+ // rCtx.pRedl already records the old format to be restored on reject, so just leave
+ // the redline table unchanged.
+ delete rCtx.pNewRedl;
+ rCtx.pNewRedl = nullptr;
+
+ MaybeNotifyRedlineModification(*rCtx.pRedl, m_rDoc);
+ break;
+ }
+ [[fallthrough]];
+ case SwComparePosition::Outside:
{
// Overlaps the current one completely or has the
// same dimension, delete the old one

"Miklos Vajna (via cogerrit)"

unread,
Apr 28, 2026, 2:21:00 AM (yesterday) Apr 28
to collaboraon...@googlegroups.com
engine/sw/qa/core/doc/DocumentRedlineManager.cxx | 53 +++++++++++++++++++
engine/sw/source/core/doc/DocumentRedlineManager.cxx | 12 +++-
2 files changed, 62 insertions(+), 3 deletions(-)

New commits:
commit 0e50a49b4c41c7767d51a829c71d3c064f4d5b93
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Mon Apr 27 08:31:54 2026 +0200
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Tue Apr 28 06:20:13 2026 +0000

cool#15451 sw interdependent redlines: fix creating an inner format on top of format-on-delete

Enable track changes, delete a sentence, select the deleted text, format
the selection as bold, then reduce the selection to just one word inside
the sentence, format as italics: the delete redline is lost for that
word.

This is similar to commit bd7f20bdf7d1e66ab13c46074c0482ccab6d6867
(cool#15451 sw interdependent redlines: fix creating a format on top of
format-on-delete, 2026-04-24), which works because comparing the
to-be-inserted format redline with the existing format-on-delete redline
results in SwComparePosition::Equal.

Here we hit the SwComparePosition::Inside case, so fix that in a similar
way. It already has code to drop the to-be-inserted redline when the
existing redline is an "own" one: do the same if the existing redline is
a hierarchical one, too.

The other way around (bold on just one word, italic on the entire
sentence) was working already.

Signed-off-by: Miklos Vajna <vmi...@collabora.com>
Change-Id: I40b1a06daa8fa158da25825e46abd087adeb767d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1698
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Caolán McNamara <caolan....@collabora.com>

diff --git a/engine/sw/qa/core/doc/DocumentRedlineManager.cxx b/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
index 1e7aa236078c..c8bc7a0f5c14 100644
--- a/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -483,6 +483,59 @@ CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatFormat)
CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType());
CPPUNIT_ASSERT(!rRedlineData2.Next());
}
+
+CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatFormatInside)
+{
+ // Given "AAA BBB CCC" with a delete redline and a bold format redline
+ // applied on top of the full range:
+ createSwDoc();
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ pWrtShell->Insert(u"AAA BBB CCC"_ustr);
+ pDocShell->SetChangeRecording(true);
+ SwView& rView = pWrtShell->GetView();
+ pWrtShell->SelAll();
+ pWrtShell->DelLeft();
+ pWrtShell->SelAll();
+ {
+ SvxWeightItem aWeightItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
+ SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet(rView.GetPool());
+ aSet.Put(aWeightItem);
+ pWrtShell->SetAttrSet(aSet);
+ }
+
+ // When applying an additional italic format on only the middle word:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ // Skip "AAA ".
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
+ // Select "BBB".
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 3, /*bBasicCall=*/false);
+ {
+ SvxPostureItem aPostureItem(ITALIC_NORMAL, RES_CHRATR_POSTURE);
+ SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aSet(rView.GetPool());
+ aSet.Put(aPostureItem);
+ pWrtShell->SetAttrSet(aSet);
+ }
+
+ // Then make sure the delete-then-format redline is kept unchanged, instead
+ // of being replaced with a single plain format redline for BBB:
+ SwDoc* pDoc = pDocShell->GetDoc();
+ IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+ SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 3
+ // i.e. we got a format-then-delete, a format and a format-on-delete redline instead of a single
+ // format-on-delete redline.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+ CPPUNIT_ASSERT_EQUAL(u"AAA BBB CCC"_ustr, rRedlines[0]->GetText());
+ const SwRedlineData& rRedlineData = rRedlines[0]->GetRedlineData(0);
+ CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData.GetType());
+ CPPUNIT_ASSERT(rRedlineData.Next());
+ const SwRedlineData& rRedlineData2 = *rRedlineData.Next();
+ CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType());
+ CPPUNIT_ASSERT(!rRedlineData2.Next());
+}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/engine/sw/source/core/doc/DocumentRedlineManager.cxx b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
index 38219390f53f..78e44af01cae 100644
--- a/engine/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -2340,10 +2340,12 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
break;
}
case RedlineType::Format:
+ {
+ bool bHierarchical = rCtx.pRedl->GetRedlineData(0).Next() != nullptr;
switch( rCtx.eCmpPos )
{
case SwComparePosition::Equal:
- if (rCtx.pRedl->GetRedlineData(0).Next())
+ if (bHierarchical)
{
// rCtx.pRedl already has an underlying redline data entry (insert/delete) and
// rCtx.pRedl already records the old format to be restored on reject, so just leave
@@ -2365,8 +2367,10 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
break;

case SwComparePosition::Inside:
- if( rCtx.pRedl->IsOwnRedline( *rCtx.pNewRedl ) &&
- rCtx.pRedl->CanCombine( *rCtx.pNewRedl ))
+ {
+ bool bOwnRedlineToCombine = rCtx.pRedl->IsOwnRedline(*rCtx.pNewRedl)
+ && rCtx.pRedl->CanCombine(*rCtx.pNewRedl);
+ if (bOwnRedlineToCombine || bHierarchical)
{
// own one can be ignored completely
delete rCtx.pNewRedl;
@@ -2398,6 +2402,7 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
rCtx.bDec = true;
}
break;
+ }

case SwComparePosition::OverlapBefore:
case SwComparePosition::OverlapBehind:
@@ -2449,6 +2454,7 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
break;
}
break;
+ }
default:
break;
}

Reply all
Reply to author
Forward
0 new messages