online.git: engine/sw

0 views
Skip to first unread message

"Mike Kaganski (via cogerrit)"

unread,
Apr 20, 2026, 11:57:47 AMApr 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 AMApr 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 AMApr 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 AMApr 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 AMApr 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 AMApr 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 AMApr 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;
}

"Jaume Pujantell (via cogerrit)"

unread,
Apr 30, 2026, 8:05:24 AMApr 30
to collaboraon...@googlegroups.com
engine/sw/qa/extras/uiwriter/uiwriter11.cxx | 34 ++++++++++++++++++++++++++++
engine/sw/source/uibase/utlui/uitool.cxx | 6 ++++
2 files changed, 39 insertions(+), 1 deletion(-)

New commits:
commit d9c57bf632c520625c5cab58f53532def277602a
Author: Jaume Pujantell <jaume.p...@collabora.com>
AuthorDate: Fri Apr 24 17:17:07 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu Apr 30 12:04:54 2026 +0000

sw: preserve orientation on size change

When uno:AttributePageSize is fired with a PaperFormat, the
corresponding paper sizes are directly set ignoring current page
orientation. The size set should depend on the current paper
orientation.

Signed-off-by: Jaume Pujantell <jaume.p...@collabora.com>
Change-Id: I519212fab4d6f2408cb42beba59a5668d3a45975
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1600
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
index 2a22f47312a2..d203535f91af 100644
--- a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -14,6 +14,7 @@
#include <vcl/scheduler.hxx>

#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propertysequence.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/configuration.hxx>
@@ -22,6 +23,9 @@
#include <cmdid.h>
#include <docufld.hxx>
#include <edtwin.hxx>
+#include <fmtfsize.hxx>
+#include <i18nutil/paper.hxx>
+#include <pagedesc.hxx>
#include <PostItMgr.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
@@ -561,6 +565,36 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testTdf163194)
}
}

+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testPageSizeKeepsOrientation)
+{
+ createSwDoc();
+
+ dispatchCommand(mxComponent, u".uno:Orientation"_ustr,
+ comphelper::InitPropertySequence({ { "isLandscape", uno::Any(true) } }));
+
+ SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+ const size_t nPageDesc = pWrtShell->GetCurPageDesc();
+
+ CPPUNIT_ASSERT(pWrtShell->GetPageDesc(nPageDesc).GetLandscape());
+ const Size aLandscapeA4
+ = pWrtShell->GetPageDesc(nPageDesc).GetMaster().GetFrameSize().GetSize();
+ CPPUNIT_ASSERT_GREATER(aLandscapeA4.Height(), aLandscapeA4.Width());
+
+ dispatchCommand(
+ mxComponent, u".uno:AttributePageSize"_ustr,
+ comphelper::InitPropertySequence({ { "PaperFormat", uno::Any(sal_uInt16(PAPER_A3)) } }));
+
+ const SwPageDesc& rPageDesc = pWrtShell->GetPageDesc(nPageDesc);
+ CPPUNIT_ASSERT(rPageDesc.GetLandscape());
+ const Size aNewSize = rPageDesc.GetMaster().GetFrameSize().GetSize();
+ // Without the fix in place, this test would have failed with
+ // - Expected greater than: 23811
+ // - Actual : 16838
+ // i.e. the paper size change flipped the page to portrait.
+ CPPUNIT_ASSERT_GREATER(aNewSize.Height(), aNewSize.Width());
+ CPPUNIT_ASSERT_GREATER(aLandscapeA4.Width(), aNewSize.Width());
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

diff --git a/engine/sw/source/uibase/utlui/uitool.cxx b/engine/sw/source/uibase/utlui/uitool.cxx
index 0d4879dd1bb4..4a1308299336 100644
--- a/engine/sw/source/uibase/utlui/uitool.cxx
+++ b/engine/sw/source/uibase/utlui/uitool.cxx
@@ -344,7 +344,11 @@ void ItemSetToPageDesc(const SfxItemSet& rSet, SwPageDesc& rPageDesc, bool bAppl
{
const sal_uInt16 nSizeItem = rSet.GetItem<SfxUInt16Item>(FN_PARAM_1)->GetValue();
SwFormatFrameSize aSize(SwFrameSize::Fixed);
- aSize.SetSize(SvxPaperInfo::GetPaperSize(static_cast<Paper>(nSizeItem)));
+ Size aPaperSize = SvxPaperInfo::GetPaperSize(static_cast<Paper>(nSizeItem));
+ // GetPaperSize returns portrait-oriented dimensions
+ if (rPageDesc.GetLandscape())
+ Swap(aPaperSize);
+ aSize.SetSize(aPaperSize);
rMaster.SetFormatAttr(aSize);
}


"Stephan Bergmann (via cogerrit)"

unread,
May 4, 2026, 2:43:36 AMMay 4
to collaboraon...@googlegroups.com
engine/sw/qa/uitest/chart/tdf138556.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

New commits:
commit b37066f26ffbd120e53aa43fe5004a54b8b62df6
Author: Stephan Bergmann <stephan....@collabora.com>
AuthorDate: Sun May 3 20:24:16 2026 +0000
Commit: Tomaž Vajngerl <tomaz.v...@collabora.com>
CommitDate: Mon May 4 06:42:46 2026 +0000

Fix UITest after histogram chart was gated to experimental mode

UITest_sw_chart had started to fail with

> FAIL: test_stock_chart13_insert_series (tdf138556.tdf138556.test_stock_chart13_insert_series)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
> File ".../online/engine/sw/qa/uitest/chart/tdf138556.py", line 39, in test_stock_chart13_insert_series
> self.assertEqual("Series3", get_state_as_dict(xDialog.getChild("entry0"))["Text"])
> AssertionError: 'Series3' != 'Series1'
> - Series3
> ? ^
> + Series1
> ? ^

508c3456e85a88771ac5e264cee9460274685a22 "chart2: Add UI and basic rendering for
Histogram chart" added a Histogram entry at index 2 of the chart type list in
engine/chart2/source/controller/dialogs/tp_ChartType.cxx, which shifted Stock
from index 9 to 10, and updated this test accordingly. Then,
5bec82ff130a79508b8e205e46085dfa43052d2e "chart2: Add histogram to UI only in
experimental mode" gated the Histogram entry behind ExperimentalMode but did not
revert the test change.

Signed-off-by: Stephan Bergmann <stephan....@collabora.com>
Change-Id: Ia8536f66c7427326762546979c2def6ea5ca9400
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1897
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.v...@collabora.com>

diff --git a/engine/sw/qa/uitest/chart/tdf138556.py b/engine/sw/qa/uitest/chart/tdf138556.py
index 8266011f6135..df09ec4dde63 100644
--- a/engine/sw/qa/uitest/chart/tdf138556.py
+++ b/engine/sw/qa/uitest/chart/tdf138556.py
@@ -28,7 +28,7 @@ class tdf138556( UITestCase ):
#TODO: test other subtypes
with self.ui_test.execute_dialog_through_action( xChart, "COMMAND", mkPropertyValues({ "COMMAND" : "DiagramType" })) as xDialog:
xChartType = xDialog.getChild( "charttype" )
- xStockType = xChartType.getChild("10")
+ xStockType = xChartType.getChild("9")
xStockType.executeAction( "SELECT", tuple())

#Insert Data Series

"Karthik (via cogerrit)"

unread,
May 4, 2026, 1:17:52 PMMay 4
to collaboraon...@googlegroups.com
engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

New commits:
commit 2e9fe0f2428213c4c18d891c05bc382288fb8feb
Author: Karthik <karthi...@collabora.com>
AuthorDate: Sun May 3 13:30:07 2026 +0200
Commit: Michael Stahl <michae...@collabora.com>
CommitDate: Mon May 4 17:17:29 2026 +0000

DOCX: Incorrect import of inline paragraphs

During import inline paragraphs are converted to a text frame.
`finishParagraph` uses `xPreviousParagraph` while importing.
`xPreviousParagraph` is set by `xTextRange`, which contains a reference
to the paragraph. For inline paragraphs the paragraph is converted to a
frame and disposed by `convertToSwTextFrame`. So, `xTextRange` refers to
a disposed paragraph, this can lead to improper import of subsequent
paragraphs (loosing the paragraph break).

Don't assign `xTextRange` for inline paragraphs.

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

diff --git a/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
index 88f4515a101b..0f8793b4ce3c 100644
--- a/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -2861,7 +2861,7 @@ void DomainMapper_Impl::finishParagraph( const ParagraphPropertyMapPtr& pParaCon
//select paragraph
xParaCursor->gotoStartOfParagraph( true );

- xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) );
+ xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) );

uno::Reference< text::XTextRange > xRangeStart, xRangeEnd;
xRangeStart = xParaCursor->getStart();

"Caolán McNamara (via cogerrit)"

unread,
May 6, 2026, 7:05:20 AMMay 6
to collaboraon...@googlegroups.com
engine/sw/source/filter/xml/xmlimpit.cxx | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

New commits:
commit 68cfd41e16a16025abf7430563ea81ce78085e37
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Tue May 5 16:46:37 2026 +0100
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Wed May 6 11:04:13 2026 +0000

crashtesting: don't abort on dodgy multi-colon attribute name

assert on loading ooo53770-1.odt

soffice.bin: engine/xmloff/source/core/xmlcnimp.cxx:60:
bool SvXMLAttrContainerData::AddAttr(const rtl::OUString&, const rtl::OUString&):
Assertion `rLName.indexOf(':') == -1 && "colon in name?"' failed.

#4 SvXMLAttrContainerData::AddAttr (rLName="style:style:use-optimal-row-height", rValue="false")
at engine/xmloff/source/core/xmlcnimp.cxx:60
#5 SvXMLAttrContainerItem::AddAttr at engine/editeng/source/items/xmlcnitm.cxx:136
... (inlined SvXMLImportItemMapper::importXMLUnknownAttributes)
#10 SwXMLItemSetStyleContext_Impl::CreateItemSetContext at engine/sw/source/filter/xml/xmlfmt.cxx:552

The .odt's content.xml has a malformed attribute on
<style:table-row-properties>:

style:style:use-optimal-row-height="false"

(two "style:" prefixes - presumably written by an old buggy exporter).
The fast sax parser passes it through to importXMLUnknownAttributes
with rAttribute.Name = "style:style:use-optimal-row-height" and
rAttribute.NamespaceURL empty (the "style:style" pseudo-prefix isn't
in the namespace map).

The else-branch already had a guard rejecting attribute names whose
local part still contains a colon ("the sax parser doesn't reject
these, strangely"); apply the same guard to the empty-namespace
branch instead of crashing.

Signed-off-by: Caolán McNamara <caolan....@collabora.com>
Change-Id: I51a71523dc4a9236569c5ae2eeac3ac68c0d60db
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2057

diff --git a/engine/sw/source/filter/xml/xmlimpit.cxx b/engine/sw/source/filter/xml/xmlimpit.cxx
index 7ccda332ee5d..c23d20580bb7 100644
--- a/engine/sw/source/filter/xml/xmlimpit.cxx
+++ b/engine/sw/source/filter/xml/xmlimpit.cxx
@@ -219,7 +219,13 @@ void SvXMLImportItemMapper::importXMLUnknownAttributes( SfxItemSet& rSet,
if( pUnknownItem )
{
if( rAttribute.NamespaceURL.isEmpty() )
- pUnknownItem->AddAttr( rAttribute.Name, rAttribute.Value );
+ {
+ // the sax parser doesn't reject these, strangely
+ if (rAttribute.Name.indexOf(':') == -1)
+ pUnknownItem->AddAttr( rAttribute.Name, rAttribute.Value );
+ else
+ SAL_WARN("sw", "ignoring dodgy attribute: " + rAttribute.Name);
+ }
else
{
OUString sPrefix;

"Jakub Trzebiatowski (via cogerrit)"

unread,
May 6, 2026, 8:22:43 AMMay 6
to collaboraon...@googlegroups.com
engine/sw/qa/core/doc/data/tdf171549.fodt | 496 ++++++++++++++++++++++++++++++
engine/sw/qa/core/doc/doc.cxx | 26 +
engine/sw/source/core/doc/docchart.cxx | 19 -
3 files changed, 533 insertions(+), 8 deletions(-)

New commits:
commit 2842f2152f27aa42029ec4ed4b44e77e2f0097ab
Author: Jakub Trzebiatowski <jakt...@gmail.com>
AuthorDate: Tue May 5 21:51:58 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 6 12:21:44 2026 +0000

tdf#171549 sw: fix chart data link on table name collision

Ensure charts update using the resolved unique name when a requested
table name is empty or already exists. Previously, charts used the
invalid requested name, breaking the data link.

Signed-off-by: Jakub Trzebiatowski <ubap...@gmail.com>
Change-Id: If3b52bcb7f2d66d517362b9d9bf3b3e3c9a4e6f7
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2062
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/core/doc/data/tdf171549.fodt b/engine/sw/qa/core/doc/data/tdf171549.fodt
new file mode 100644
index 000000000000..b1d2672e2150
--- /dev/null
+++ b/engine/sw/qa/core/doc/data/tdf171549.fodt
@@ -0,0 +1,496 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:meta><meta:creation-date>2026-03-30T21:15:43.780361000</meta:creation-date><dc:date>2026-03-31T20:50:40.352629000</dc:date><meta:editing-duration>PT31S</meta:editing-duration><meta:editing-cycles>2</meta:editing-cycles><meta:generator>LibreOffice/25.8.3.2$MacOSX_AARCH64 LibreOffice_project/8ca8d55c161d602844f5428fa4b58097424e324e</meta:generator><meta:document-statistic meta:table-count="2" meta:image-count="0" meta:object-count="1" meta:page-count="1" meta:paragraph-count="2" meta:word-count="2" meta:character-count="2" meta:non-whitespace-character-count="2"/></office:meta>
+ <office:font-face-decls>
+ <style:font-face style:name="Arial Unicode MS1" svg:font-family="'Arial Unicode MS'" style:font-family-generic="system" style:font-pitch="variable"/>
+ <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Songti SC" svg:font-family="'Songti SC'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="graphic">
+ <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:writing-mode="lr-tb" style:flow-with-text="false"/>
+ <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Songti SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial Unicode MS1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
+ </style:default-style>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Songti SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial Unicode MS1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
+ </style:default-style>
+ <style:default-style style:family="table">
+ <style:table-properties table:border-model="collapsing"/>
+ </style:default-style>
+ <style:default-style style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto"/>
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+ <style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
+ <style:paragraph-properties fo:margin-top="0in" fo:margin-bottom="0.0972in" style:contextual-spacing="false" fo:line-height="115%"/>
+ </style:style>
+ <style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/>
+ </style:style>
+ <style:style style:name="OLE" style:family="graphic">
+ <style:graphic-properties text:anchor-type="paragraph" svg:x="0in" svg:y="0in" style:wrap="dynamic" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph" fo:background-color="transparent" draw:fill="none" draw:fill-color="#729fcf"/>
+ </style:style>
+ <text:outline-style style:name="Outline">
+ <text:outline-level-style text:level="1" loext:num-list-format="%1%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="2" loext:num-list-format="%2%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="3" loext:num-list-format="%3%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="4" loext:num-list-format="%4%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="5" loext:num-list-format="%5%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="6" loext:num-list-format="%6%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="7" loext:num-list-format="%7%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="8" loext:num-list-format="%8%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="9" loext:num-list-format="%9%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="10" loext:num-list-format="%10%" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ </text:outline-style>
+ <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
+ <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
+ <text:linenumbering-configuration text:number-lines="false" text:offset="0.1965in" style:num-format="1" text:number-position="left" text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="6.6931in" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="6.6931in" style:rel-column-width="65535*"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:padding="0.0382in" fo:border="0.5pt solid #000000"/>
+ </style:style>
+ <style:style style:name="Table2" style:family="table">
+ <style:table-properties style:width="6.6931in" table:align="margins"/>
+ </style:style>
+ <style:style style:name="Table2.A" style:family="table-column">
+ <style:table-column-properties style:column-width="6.6931in" style:rel-column-width="65535*"/>
+ </style:style>
+ <style:style style:name="Table2.A1" style:family="table-cell">
+ <style:table-cell-properties fo:padding="0.0382in" fo:border="0.5pt solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:text-properties/>
+ </style:style>
+ <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:text-properties/>
+ </style:style>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="OLE">
+ <style:graphic-properties style:horizontal-pos="center" style:horizontal-rel="paragraph" draw:ole-draw-aspect="1"/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="8.2681in" fo:page-height="11.6929in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.278in" style:layout-grid-ruby-height="0.139in" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0in" loext:margin-gutter="0in">
+ <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ <style:style style:name="dp1" style:family="drawing-page">
+ <style:drawing-page-properties draw:background-size="full"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:sequence-decls>
+ <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+ </text:sequence-decls>
+ <text:p text:style-name="Text_20_body"/>
+ <text:p text:style-name="Text_20_body"><draw:frame draw:style-name="fr1" draw:name="Object1" text:anchor-type="char" svg:width="6.2984in" svg:height="3.5429in" draw:z-index="0"><draw:object draw:notify-on-update-of-ranges="Table1">
+ <office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:chartooo="http://openoffice.org/2010/chart" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.chart">
+ <office:meta><meta:generator>LibreOffice/25.8.3.2$MacOSX_AARCH64 LibreOffice_project/8ca8d55c161d602844f5428fa4b58097424e324e</meta:generator></office:meta>
+ <office:styles/>
+ <office:automatic-styles>
+ <number:number-style style:name="N0">
+ <number:number number:min-integer-digits="1"/>
+ </number:number-style>
+ <style:style style:name="ch1" style:family="chart">
+ <style:graphic-properties draw:stroke="none" draw:fill="none"/>
+ </style:style>
+ <style:style style:name="ch2" style:family="chart">
+ <style:chart-properties chart:auto-position="true"/>
+ <style:graphic-properties draw:stroke="none" svg:stroke-color="#b3b3b3" draw:fill="none" draw:fill-color="#e6e6e6"/>
+ <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="ch3" style:family="chart">
+ <style:chart-properties chart:include-hidden-cells="false" chart:auto-position="true" chart:auto-size="true" chart:treat-empty-cells="leave-gap" chart:series-source="rows" chart:right-angled-axes="true"/>
+ </style:style>
+ <style:style style:name="ch4" style:family="chart" style:data-style-name="N0">
+ <style:chart-properties chart:display-label="true" chart:logarithmic="false" chart:reverse-direction="false" text:line-break="false" loext:try-staggering-first="false" chart:link-data-style-to-source="true" chart:axis-position="0"/>
+ <style:graphic-properties svg:stroke-color="#b3b3b3"/>
+ <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="ch5" style:family="chart" style:data-style-name="N0">
+ <style:chart-properties chart:display-label="true" chart:logarithmic="false" chart:reverse-direction="false" text:line-break="false" loext:try-staggering-first="false" chart:link-data-style-to-source="true" chart:axis-position="0"/>
+ <style:graphic-properties svg:stroke-color="#b3b3b3"/>
+ <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="ch6" style:family="chart">
+ <style:graphic-properties svg:stroke-color="#b3b3b3"/>
+ </style:style>
+ <style:style style:name="ch7" style:family="chart" style:data-style-name="N0">
+ <style:chart-properties chart:link-data-style-to-source="true"/>
+ <style:graphic-properties draw:stroke="none" draw:fill-color="#004586" dr3d:edge-rounding="5%"/>
+ <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
+ </style:style>
+ <style:style style:name="ch8" style:family="chart">
+ <style:graphic-properties draw:stroke="solid" svg:stroke-color="#b3b3b3" draw:fill="none" draw:fill-color="#e6e6e6"/>
+ </style:style>
+ <style:style style:name="ch9" style:family="chart">
+ <style:graphic-properties svg:stroke-color="#b3b3b3" draw:fill-color="#cccccc"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:chart>
+ <chart:chart svg:width="15.998cm" svg:height="8.999cm" xlink:href=".." xlink:type="simple" chart:class="chart:bar" chart:style-name="ch1">
+ <chart:legend chart:legend-position="end" svg:x="15.144cm" svg:y="4.2cm" style:legend-expansion="high" chart:style-name="ch2"/>
+ <chart:plot-area chart:style-name="ch3" svg:x="0.319cm" svg:y="0.179cm" svg:width="14.506cm" svg:height="8.641cm">
+ <chart:coordinate-region svg:x="1.067cm" svg:y="0.379cm" svg:width="13.758cm" svg:height="8.242cm"/>
+ <chart:axis chart:dimension="x" chart:name="primary-x" chart:style-name="ch4"/>
+ <chart:axis chart:dimension="y" chart:name="primary-y" chart:style-name="ch5">
+ <chart:grid chart:style-name="ch6" chart:class="major"/>
+ </chart:axis>
+ <chart:series chart:style-name="ch7" chart:values-cell-range-address="Table1.$A$1" chart:class="chart:bar">
+ <chart:data-point/>
+ </chart:series>
+ <chart:wall chart:style-name="ch8"/>
+ <chart:floor chart:style-name="ch9"/>
+ </chart:plot-area>
+ <table:table table:name="local-table">
+ <table:table-header-columns>
+ <table:table-column/>
+ </table:table-header-columns>
+ <table:table-columns>
+ <table:table-column/>
+ </table:table-columns>
+ <table:table-header-rows>
+ <table:table-row>
+ <table:table-cell>
+ <text:p/>
+ </table:table-cell>
+ <table:table-cell office:value-type="string">
+ <text:p/>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-header-rows>
+ <table:table-rows>
+ <table:table-row>
+ <table:table-cell office:value-type="string">
+ <text:p/>
+ <draw:g>
+ <svg:desc/></draw:g>
+ </table:table-cell>
+ <table:table-cell office:value-type="float" office:value="1">
+ <text:p>1</text:p>
+ <draw:g>
+ <svg:desc>Table1.$A$1</svg:desc></draw:g>
+ </table:table-cell>
+ </table:table-row>
+ </table:table-rows>
+ </table:table>
+ </chart:chart>
+ </office:chart>
+ </office:body>
+ </office:document>
+ </draw:object><draw:image>
+ <office:binary-data>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
+ </office:binary-data>
+ </draw:image>
+ </draw:frame></text:p>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1">1</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <table:table table:name="Table2" table:style-name="Table2">
+ <table:table-column table:style-name="Table2.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" office:value-type="string">
+ <text:p text:style-name="P2">2</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Standard"/>
+ </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/engine/sw/qa/core/doc/doc.cxx b/engine/sw/qa/core/doc/doc.cxx
index d39075a2dd84..b47b04ecd4f9 100644
--- a/engine/sw/qa/core/doc/doc.cxx
+++ b/engine/sw/qa/core/doc/doc.cxx
@@ -604,6 +604,32 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testSplitFlyInsertUndo)
CPPUNIT_ASSERT(!rFlyFormats.empty());
}

+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testEmptyTableNameUpdatesChart)
+{
+ createSwDoc("tdf171549.fodt");
+
+ SwFrameFormat* pFrameFormat = getSwDoc()->FindTableFormatByName(UIName("Table1"));
+ getSwDocShell()->GetEditShell()->SetTableName(*pFrameFormat, UIName(""));
+
+ saveAndReload(TestFilter::ODT);
+
+ xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc, "//draw:object", "notify-on-update-of-ranges", u"Table3");
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testTableNameCollisionUpdatesChart)
+{
+ createSwDoc("tdf171549.fodt");
+
+ SwFrameFormat* pFrameFormat = getSwDoc()->FindTableFormatByName(UIName("Table1"));
+ getSwDocShell()->GetEditShell()->SetTableName(*pFrameFormat, UIName("Table2"));
+
+ saveAndReload(TestFilter::ODT);
+
+ xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc, "//draw:object", "notify-on-update-of-ranges", u"Table3");
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testVirtPageNumReset)
{
createSwDoc("tdf160843.odt");
diff --git a/engine/sw/source/core/doc/docchart.cxx b/engine/sw/source/core/doc/docchart.cxx
index f1f889f2981c..3c5500cd2574 100644
--- a/engine/sw/source/core/doc/docchart.cxx
+++ b/engine/sw/source/core/doc/docchart.cxx
@@ -148,17 +148,18 @@ void SwDoc::UpdateCharts( const UIName& rName ) const
}
}

-void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rNewName )
+void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rInName )
{
+ UIName aNewName = rInName;
const UIName aOldName( rTableFormat.GetName() );

- bool bNameFound = rNewName.isEmpty();
+ bool bNameFound = aNewName.isEmpty();
if( !bNameFound )
{
for(const SwTableFormat* pFormat: *GetTableFrameFormats())
{
if( !pFormat->IsDefault() &&
- pFormat->GetName() == rNewName && IsUsed( *pFormat ) )
+ pFormat->GetName() == aNewName && IsUsed( *pFormat ) )
{
bNameFound = true;
break;
@@ -166,10 +167,12 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rNewName )
}
}

- if( !bNameFound )
- rTableFormat.SetFormatName( rNewName, true );
- else
- rTableFormat.SetFormatName( GetUniqueTableName(), true );
+ // If the new name is already taken or is empty, generate new unique table name
+ if ( bNameFound )
+ {
+ aNewName = GetUniqueTableName();
+ }
+ rTableFormat.SetFormatName( aNewName, true );

SwStartNode *pStNd;
SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
@@ -179,7 +182,7 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rNewName )
SwOLENode *pNd = aIdx.GetNode().GetOLENode();
if( pNd && aOldName == pNd->GetChartTableName() )
{
- pNd->SetChartTableName( rNewName );
+ pNd->SetChartTableName( aNewName );

SwTable* pTable = SwTable::FindTable( &rTableFormat );
SwChartDataProvider *pPCD = getIDocumentChartDataProviderAccess().GetChartDataProvider();

"Caolán McNamara (via cogerrit)"

unread,
May 7, 2026, 2:37:52 AMMay 7
to collaboraon...@googlegroups.com
engine/sw/inc/ndole.hxx | 13 ++
engine/sw/qa/extras/odfimport/data/draw-object-link.fodt | 22 ++++
engine/sw/qa/extras/odfimport/odfimport.cxx | 46 +++++++++
engine/sw/source/core/ole/ndole.cxx | 70 +++++++++++++++
engine/sw/source/filter/xml/xmltexti.cxx | 34 +++----
5 files changed, 166 insertions(+), 19 deletions(-)

New commits:
commit 8d8da430283feb7cdb4e6eb8210bc48d4b478266
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Tue Mar 31 12:06:07 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu May 7 06:36:48 2026 +0000

defer OLE link creation during ODF import until after the update prompt

draw:object elements with non-package xlink:href triggered type
detection during import which fetched the URL before the user prompt.

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

diff --git a/engine/sw/inc/ndole.hxx b/engine/sw/inc/ndole.hxx
index 37146ac16200..0511f7680921 100644
--- a/engine/sw/inc/ndole.hxx
+++ b/engine/sw/inc/ndole.hxx
@@ -23,6 +23,7 @@
#include <svtools/embedhlp.hxx>
#include <drawinglayer/primitive2d/Primitive2DContainer.hxx>
#include <rtl/ref.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>

class SvxDrawPage;
class SwGrfFormatColl;
@@ -100,6 +101,10 @@ class SW_DLLPUBLIC SwOLENode final: public SwNoTextNode
sfx2::SvBaseLink* mpObjectLink;
OUString maLinkURL;

+ // Stored when a linked OLE object is deferred during import until link
+ // updates are allowed
+ css::uno::Sequence<css::beans::PropertyValue> maDeferredMediaDescriptor;
+
SwOLENode( const SwNode& rWhere,
const svt::EmbeddedObjectRef&,
SwGrfFormatColl *pGrfColl,
@@ -153,6 +158,14 @@ public:

void CheckFileLink_Impl();

+ // Register a deferred link during import, when link updates are not yet
+ // allowed, and create the the actual embedded object when the user allows
+ // link updating.
+ void SetDeferredLink(const OUString& rLinkURL,
+ const css::uno::Sequence<css::beans::PropertyValue>& rMediaDescriptor);
+ bool CompleteDeferredLink();
+ bool HasDeferredLink() const { return maDeferredMediaDescriptor.hasElements(); }
+
// #i99665#
bool IsChart() const;

diff --git a/engine/sw/qa/extras/odfimport/data/draw-object-link.fodt b/engine/sw/qa/extras/odfimport/data/draw-object-link.fodt
new file mode 100644
index 000000000000..fb1a81e5a00c
--- /dev/null
+++ b/engine/sw/qa/extras/odfimport/data/draw-object-link.fodt
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
+ office:version="1.2"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p>
+ <draw:frame draw:name="Object1" svg:width="5cm" svg:height="5cm"
+ text:anchor-type="as-char">
+ <draw:object xlink:href="http://192.0.2.1:12345/probe"
+ xlink:type="simple" xlink:show="embed"
+ xlink:actuate="onLoad"/>
+ </draw:frame>
+ </text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/odfimport/odfimport.cxx b/engine/sw/qa/extras/odfimport/odfimport.cxx
index 690dda9d2406..ebeb08e8ecc0 100644
--- a/engine/sw/qa/extras/odfimport/odfimport.cxx
+++ b/engine/sw/qa/extras/odfimport/odfimport.cxx
@@ -42,10 +42,12 @@
#include <com/sun/star/document/XDocumentInsertable.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>

#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <editeng/boxitem.hxx>
+#include <sfx2/docfile.hxx>
#include <vcl/scheduler.hxx>

#include <IDocumentSettingAccess.hxx>
@@ -57,6 +59,8 @@
#include <olmenu.hxx>
#include <hintids.hxx>
#include <docsh.hxx>
+#include <fmtcntnt.hxx>
+#include <ndole.hxx>
#include <unotxdoc.hxx>
#include <frmatr.hxx>
#include <expfld.hxx>
@@ -80,6 +84,48 @@ class Test : public SwModelTestBase
Test() : SwModelTestBase(u"/sw/qa/extras/odfimport/data/"_ustr) {}
};

+CPPUNIT_TEST_FIXTURE(Test, testDrawObjectLinkDeferred)
+{
+ // Given a document with draw:object xlink:href pointing to a URL, the link
+ // shouldn't be fetched until the update links is called.
+ //
+ // Load with NO_UPDATE so that UpdateLinks does not complete the deferred
+ // link, we want to verify the state immediately after import. The test
+ // uses 192.0.2.1 (non-routeable) so without the fix type detection fetch
+ // would hang/timeout.
+ uno::Sequence<beans::PropertyValue> aParams = {
+ comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
+ sal_Int16(document::UpdateDocMode::NO_UPDATE)),
+ };
+ loadWithParams(createFileURL(u"draw-object-link.fodt"), aParams);
+ CPPUNIT_ASSERT(!getSwDocShell()->GetMedium()->GetWarningError());
+ calcLayout();
+
+ SwDoc* pDoc = getSwDoc();
+
+ // find the OLE node via fly frame formats
+ SwOLENode* pOLENode = nullptr;
+ for (const auto* pFlyFormat : *pDoc->GetSpzFrameFormats())
+ {
+ const SwNodeIndex* pIdx = pFlyFormat->GetContent().GetContentIdx();
+ if (!pIdx)
+ continue;
+ SwNode* pNd = pDoc->GetNodes()[pIdx->GetIndex() + 1];
+ if (pNd && pNd->IsOLENode())
+ {
+ pOLENode = pNd->GetOLENode();
+ break;
+ }
+ }
+
+ // the placeholder frame and OLE node must exist
+ CPPUNIT_ASSERT_MESSAGE("OLE placeholder node should exist after import", pOLENode);
+
+ // If this is false, the link was either not deferred or was completed despite NO_UPDATE.
+ CPPUNIT_ASSERT_MESSAGE("OLE link should be deferred, not created during import",
+ pOLENode->HasDeferredLink());
+}
+
CPPUNIT_TEST_FIXTURE(Test, testEmptySvgFamilyName)
{
createSwDoc("empty-svg-family-name.odt");
diff --git a/engine/sw/source/core/ole/ndole.cxx b/engine/sw/source/core/ole/ndole.cxx
index fd66aac063f5..ee0c9fcda3c4 100644
--- a/engine/sw/source/core/ole/ndole.cxx
+++ b/engine/sw/source/core/ole/ndole.cxx
@@ -18,6 +18,10 @@
*/

#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/embed/OOoEmbeddedObjectFactory.hpp>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/embed/XEmbedPersist.hpp>
@@ -178,6 +182,15 @@ SwEmbedObjectLink::SwEmbedObjectLink(SwOLENode* pNode)
::sfx2::SvBaseLink::UpdateResult SwEmbedObjectLink::DataChanged(
const OUString&, const uno::Any& )
{
+ // deferred link: the object was not created during import, complete the
+ // creation now
+ if (m_pOleNode->CompleteDeferredLink())
+ {
+ m_pOleNode->GetNewReplacement();
+ m_pOleNode->SetChanged();
+ return SUCCESS;
+ }
+
if (!m_pOleNode->UpdateLinkURL_Impl())
{
// the link URL was not changed
@@ -704,6 +717,63 @@ void SwOLENode::CheckFileLink_Impl()
}
}

+void SwOLENode::SetDeferredLink(const OUString& rLinkURL,
+ const uno::Sequence<beans::PropertyValue>& rMediaDescriptor)
+{
+ if (mpObjectLink)
+ return;
+
+ maLinkURL = rLinkURL;
+ maDeferredMediaDescriptor = rMediaDescriptor;
+
+ mpObjectLink = new SwEmbedObjectLink(this);
+ GetDoc().getIDocumentLinksAdministration().GetLinkManager().InsertFileLink(
+ *mpObjectLink, sfx2::SvBaseLinkObjectType::ClientOle, maLinkURL);
+}
+
+bool SwOLENode::CompleteDeferredLink()
+{
+ if (!maDeferredMediaDescriptor.hasElements())
+ return false;
+
+ // Take ownership of the descriptor and clear it so we don't retry
+ uno::Sequence<beans::PropertyValue> aMediaDescriptor;
+ std::swap(aMediaDescriptor, maDeferredMediaDescriptor);
+
+ try
+ {
+ uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+
+ // create object with desired ClassId
+ uno::Reference<embed::XEmbeddedObjectCreator> xFactory =
+ embed::OOoEmbeddedObjectFactory::create(::comphelper::getProcessComponentContext());
+
+ uno::Reference<embed::XEmbeddedObject> xObj(xFactory->createInstanceLink(
+ xStorage, u"DummyName"_ustr, aMediaDescriptor, uno::Sequence<beans::PropertyValue>()),
+ uno::UNO_QUERY);
+
+ if (!xObj.is())
+ return false;
+
+ SwDoc& rDoc = GetDoc();
+ comphelper::EmbeddedObjectContainer& rContainer = rDoc.GetDocShell()->getEmbeddedObjectContainer();
+
+ OUString aPersistName;
+ rContainer.InsertEmbeddedObject(xObj, aPersistName);
+
+ maOLEObj.GetObject().Assign(xObj, maOLEObj.GetObject().GetViewAspect());
+ maOLEObj.m_aName = aPersistName;
+
+ SetChanged();
+ return true;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ return false;
+}
+
// #i99665#
bool SwOLENode::IsChart() const
{
diff --git a/engine/sw/source/filter/xml/xmltexti.cxx b/engine/sw/source/filter/xml/xmltexti.cxx
index b1e5201b8592..bb97455c290f 100644
--- a/engine/sw/source/filter/xml/xmltexti.cxx
+++ b/engine/sw/source/filter/xml/xmltexti.cxx
@@ -580,26 +580,22 @@ uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertOOoLink(
uno::Sequence< beans::PropertyValue > aMediaDescriptor =
lcl_buildLinkMediaDescriptor( aAbsURL, pShell );

- rtl::Reference < SwXTextEmbeddedObject > xPropSet;
- uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
- try
- {
- // create object with desired ClassId
- uno::Reference < embed::XEmbeddedObjectCreator > xFactory =
- embed::OOoEmbeddedObjectFactory::create(::comphelper::getProcessComponentContext());
-
- uno::Reference < embed::XEmbeddedObject > xObj(
- xFactory->createInstanceLink(
- xStorage, u"DummyName"_ustr, aMediaDescriptor, uno::Sequence< beans::PropertyValue >() ),
- uno::UNO_QUERY_THROW );
-
- // TODO/LATER: in future may need a way to set replacement image url to the link ( may be even to the object ), needs oasis cws???
-
- xPropSet = lcl_insertOLEFrame( pDoc, *pTextCursor->GetPaM(),
- ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT), &aItemSet );
- }
- catch ( uno::Exception& )
+ // Insert a placeholder OLE frame and register the link with the link manager.
+ // The actual embedded object creation (includes its type detection) is deferred to
+ // SwOLENode::CompleteDeferredLink, called after link updates are allowed.
+ svt::EmbeddedObjectRef xEmptyRef;
+ // TODO/LATER: in future may need a way to set replacement image url to the link ( may be even to the object ), needs oasis cws???
+ rtl::Reference<SwXTextEmbeddedObject> xPropSet = lcl_insertOLEFrame(pDoc, *pTextCursor->GetPaM(), xEmptyRef, &aItemSet);
+ if (xPropSet)
{
+ SwFrameFormat *pFrameFormat = xPropSet->GetFrameFormat();
+ const SwNodeIndex* pIdx = pFrameFormat->GetContent().GetContentIdx();
+ if (pIdx)
+ {
+ SwOLENode* pOLENode = pDoc->GetNodes()[pIdx->GetIndex() + 1]->GetOLENode();
+ if (pOLENode)
+ pOLENode->SetDeferredLink(aAbsURL, aMediaDescriptor);
+ }
}

// TODO/LATER: should the rStyleName and rTableName be handled as for usual embedded object?

"Andras Timar (via cogerrit)"

unread,
May 7, 2026, 5:40:09 AMMay 7
to collaboraon...@googlegroups.com
engine/sw/inc/viscrs.hxx | 2 ++
1 file changed, 2 insertions(+)

New commits:
commit 516a94805b9ef4f231a45a0dfee389e5f2a374cb
Author: Andras Timar <andras...@collabora.com>
AuthorDate: Thu May 7 08:19:24 2026 +0200
Commit: Andras Timar <andras...@collabora.com>
CommitDate: Thu May 7 09:39:55 2026 +0000

sw: guard SwSelPaintRects::GetCursorOverlay() instead of dropping the member

On iOS neither HAVE_FEATURE_DESKTOP nor ANDROID is defined, so the
m_pCursorOverlay member is not declared, but the inline accessor
GetCursorOverlay() referenced it unconditionally and failed to build:

viscrs.hxx:137: error: use of undeclared identifier 'm_pCursorOverlay'

Apply the minimal fix: guard the accessor with the same
guards m_pCursorOverlay. The only caller of GetCursorOverlay() is the
sw_tiledrendering CppunitTest, which is gated to Linux in
sw/Module_sw.mk and so is unaffected.

Change-Id: I37612c8bdb3a06eaed107d16cc88e783db70e88b
Signed-off-by: Andras Timar <andras...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2081
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/inc/viscrs.hxx b/engine/sw/inc/viscrs.hxx
index d8a6a711967a..0590871f6e0f 100644
--- a/engine/sw/inc/viscrs.hxx
+++ b/engine/sw/inc/viscrs.hxx
@@ -134,7 +134,9 @@ public:
const VclPtr<SwContentControlButton>& GetContentControlButton() const;

const SwCursorShell* GetShell() const { return m_pCursorShell; }
+#if HAVE_FEATURE_DESKTOP || defined(ANDROID)
const sdr::overlay::OverlaySelection* GetCursorOverlay() const { return m_pCursorOverlay.get(); }
+#endif
// check current MapMode of the shell and set possibly the static members.
// Optional set the parameters pX, pY
static void Get1PixelInLogic( const SwViewShell& rSh,

"Miklos Vajna (via cogerrit)"

unread,
May 7, 2026, 6:06:10 AMMay 7
to collaboraon...@googlegroups.com
engine/sw/source/uibase/uno/unotxdoc.cxx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

New commits:
commit 4cdfc94f9732f30bc281cb155de80e11cc0dc40c
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Wed May 6 11:45:25 2026 +0200
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Thu May 7 10:05:50 2026 +0000

sw SwXTextDocument: clean up tiled annotations code

Similar to commit 90474d6a458188750e3201e6faebe48bdd9d8783 (sw
PostItMgr: clean up tiled annotations code, 2026-04-17).

This was the last use of comphelper::COKit::isTiledAnnotations() in sw/.

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

diff --git a/engine/sw/source/uibase/uno/unotxdoc.cxx b/engine/sw/source/uibase/uno/unotxdoc.cxx
index 60c8475abb77..5ac962735a7b 100644
--- a/engine/sw/source/uibase/uno/unotxdoc.cxx
+++ b/engine/sw/source/uibase/uno/unotxdoc.cxx
@@ -3987,7 +3987,7 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
// editing, see postMouseEvent and setGraphicSelection methods.
aViewOption.SetZoom(1 * 100);

- aViewOption.SetPostIts(comphelper::COKit::isTiledAnnotations());
+ aViewOption.SetPostIts(false);
pViewShell->ApplyViewOptions(aViewOption);

// position the pages again after setting view options. Eg: if postit

"Jakub Trzebiatowski (via cogerrit)"

unread,
May 8, 2026, 5:36:27 AMMay 8
to collaboraon...@googlegroups.com
engine/sw/inc/cellfml.hxx | 2
engine/sw/inc/swtable.hxx | 2
engine/sw/qa/core/doc/data/tdf83196.fodt | 152 +++++++++++++++++++++++++++++++
engine/sw/qa/core/doc/doc.cxx | 14 ++
engine/sw/qa/core/uwriter.cxx | 22 ++++
engine/sw/source/core/doc/docchart.cxx | 12 ++
engine/sw/source/core/fields/cellfml.cxx | 24 ++++
engine/sw/source/core/table/swtable.cxx | 4
8 files changed, 229 insertions(+), 3 deletions(-)

New commits:
commit 3dc80a7c07604a9cb4d2ed7d7309ab065822aa4b
Author: Jakub Trzebiatowski <jakt...@gmail.com>
AuthorDate: Thu May 7 11:12:15 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri May 8 09:35:55 2026 +0000

tdf#83196 sw: update table formulas on table rename

Example:
Formula: =<Table1.A1> + <Table2.B1>
Renaming "Table1" to "NewTable"
Result: =<NewTable.A1> + <Table2.B1>

Note: Tables with a dot ('.') in their name may not update correctly.
See: tdf#171783

Signed-off-by: Jakub Trzebiatowski <ubap...@gmail.com>
Change-Id: Ie91410e5d9a9800492c0b6138231121a7528719f
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2125
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/inc/cellfml.hxx b/engine/sw/inc/cellfml.hxx
index 3b843ce5cdaa..731b0cb6bcd9 100644
--- a/engine/sw/inc/cellfml.hxx
+++ b/engine/sw/inc/cellfml.hxx
@@ -141,6 +141,8 @@ public:
m_eNmType = EXTRNL_NAME;
m_bValidValue = false;
}
+ /// Update table references in the formula. Example: "<Table1.A1>" -> "<NewTable.A1>".
+ void RenameTableReference(std::u16string_view rOldName, std::u16string_view rNewName);

void GetBoxesOfFormula(const SwTable& rTable, SwSelBoxes& rBoxes);
// are all boxes valid which this formula relies on?
diff --git a/engine/sw/inc/swtable.hxx b/engine/sw/inc/swtable.hxx
index 5a4c87c669b7..36ac5fe285e2 100644
--- a/engine/sw/inc/swtable.hxx
+++ b/engine/sw/inc/swtable.hxx
@@ -367,7 +367,7 @@ public:
void Merge(const SwTable& rTable, SwHistory* pHistory);
void Split(const UIName& sNewTableName, sal_uInt16 nSplitLine, SwHistory* pHistory);

- static void GatherFormulas(SwDoc& rDoc, std::vector<SwTableBoxFormula*>& rvFormulas);
+ static void GatherFormulas(const SwDoc& rDoc, std::vector<SwTableBoxFormula*>& rvFormulas);

void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
diff --git a/engine/sw/qa/core/doc/data/tdf83196.fodt b/engine/sw/qa/core/doc/data/tdf83196.fodt
new file mode 100644
index 000000000000..6e5cc0594ad2
--- /dev/null
+++ b/engine/sw/qa/core/doc/data/tdf83196.fodt
@@ -0,0 +1,152 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:meta><meta:creation-date>2026-04-17T10:18:59.735336000</meta:creation-date><dc:date>2026-04-17T10:19:52.878181000</dc:date><meta:editing-duration>PT53S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="2" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="2" meta:word-count="2" meta:character-count="8" meta:non-whitespace-character-count="8"/><meta:generator>LibreOffice/25.8.3.2$MacOSX_AARCH64 LibreOffice_project/8ca8d55c161d602844f5428fa4b58097424e324e</meta:generator></office:meta>
+ <office:font-face-decls>
+ <style:font-face style:name="Arial Unicode MS1" svg:font-family="'Arial Unicode MS'" style:font-family-generic="system" style:font-pitch="variable"/>
+ <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+ <style:font-face style:name="Songti SC" svg:font-family="'Songti SC'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="graphic">
+ <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:flow-with-text="false"/>
+ <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+ <style:tab-stops/>
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Songti SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial Unicode MS1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
+ </style:default-style>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/>
+ <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US" style:letter-kerning="true" style:font-name-asian="Songti SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Arial Unicode MS1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
+ </style:default-style>
+ <style:default-style style:family="table">
+ <style:table-properties table:border-model="collapsing"/>
+ </style:default-style>
+ <style:default-style style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto"/>
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+ <style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/>
+ </style:style>
+ <text:outline-style style:name="Outline">
+ <text:outline-level-style text:level="1" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="2" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="3" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="4" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="5" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="6" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="7" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="8" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="9" style:num-format="">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
+ <style:list-level-label-alignment text:label-followed-by="listtab"/>
+ </style:list-level-properties>
+ </text:outline-level-style>
+ <text:outline-level-style text:level="10" style:num-format="">
+ <style:style style:name="Table2.A1" style:family="table-cell" style:data-style-name="N0">
+ <style:table-cell-properties fo:padding="0.0382in" fo:border="0.5pt solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Table_20_Contents">
+ <style:text-properties/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="8.2681in" fo:page-height="11.6929in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="lr-tb" style:footnote-max-height="0in" loext:margin-gutter="0in">
+ <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ <number:number-style style:name="N0">
+ <number:number number:min-integer-digits="1"/>
+ </number:number-style>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:sequence-decls>
+ <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+ <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+ </text:sequence-decls>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1">2026</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Standard"/>
+ <table:table table:name="Table2" table:style-name="Table2">
+ <table:table-column table:style-name="Table2.A"/>
+ <table:table-row>
+ <table:table-cell table:style-name="Table2.A1" table:formula="ooow:&lt;Table1.A1&gt;" office:value-type="float" office:value="2026">
+ <text:p text:style-name="Table_20_Contents">2026</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Standard"/>
+ </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/engine/sw/qa/core/doc/doc.cxx b/engine/sw/qa/core/doc/doc.cxx
index b47b04ecd4f9..4f526e45925d 100644
--- a/engine/sw/qa/core/doc/doc.cxx
+++ b/engine/sw/qa/core/doc/doc.cxx
@@ -630,6 +630,20 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testTableNameCollisionUpdatesChart)
assertXPath(pXmlDoc, "//draw:object", "notify-on-update-of-ranges", u"Table3");
}

+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testTableNameUpdatePropagatedToFormulas)
+{
+ createSwDoc("tdf83196.fodt");
+
+ SwFrameFormat* pFrameFormat = getSwDoc()->FindTableFormatByName(UIName("Table1"));
+ getSwDocShell()->GetEditShell()->SetTableName(*pFrameFormat, UIName("NewTableName"));
+
+ saveAndReload(TestFilter::ODT);
+
+ xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc, "//table:table[@table:name='Table2']//table:table-cell", "formula",
+ u"ooow:<NewTableName.A1>");
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testVirtPageNumReset)
{
createSwDoc("tdf160843.odt");
diff --git a/engine/sw/qa/core/uwriter.cxx b/engine/sw/qa/core/uwriter.cxx
index 595b4e62a2d9..d6f0b2a6889d 100644
--- a/engine/sw/qa/core/uwriter.cxx
+++ b/engine/sw/qa/core/uwriter.cxx
@@ -123,6 +123,7 @@ public:
void testGraphicAnchorDeletion();
void testTransliterate();
void testMarkMove();
+ void testRenameTableReference();
void testFormulas();
void testIntrusiveRing();
void testClientModify();
@@ -162,6 +163,7 @@ public:
CPPUNIT_TEST(testMergePortionsDeleteNotSorted);
CPPUNIT_TEST(testGraphicAnchorDeletion);
CPPUNIT_TEST(testMarkMove);
+ CPPUNIT_TEST(testRenameTableReference);
CPPUNIT_TEST(testFormulas);
CPPUNIT_TEST(testIntrusiveRing);
CPPUNIT_TEST(testClientModify);
@@ -1443,6 +1445,26 @@ void SwDocTest::testFormulas()
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), val.GetLong());
}

+// tdf#83196
+void SwDocTest::testRenameTableReference()
+{
+ SwInsertTableOptions aOpt(SwInsertTableFlags::DefaultBorder, 0);
+ SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
+ SwPosition aPos(aIdx);
+ const SwTable* pTable1 = m_pDoc->InsertTable(aOpt, aPos, 1, 1, 0);
+
+ aIdx.Assign(m_pDoc->GetNodes().GetEndOfContent(), -1);
+ aPos.Assign(aIdx.GetNode(), 0);
+ m_pDoc->InsertTable(aOpt, aPos, 1, 2, 0);
+
+ SwTableFormulaTest aFormula("", pTable1->GetTableNode());
+ aFormula.SetFormula(u"=<Table2.A1> * <Table1.A1> + <Table2.B1>"_ustr);
+ aFormula.BoxNmToPtr(pTable1);
+
+ aFormula.RenameTableReference(u"Table2", u"NewTable");
+ CPPUNIT_ASSERT_EQUAL(u"=<NewTable.A1> * <Table1.A1> + <NewTable.B1>"_ustr, aFormula.GetFormula());
+}
+
void SwDocTest::testMarkMove()
{
IDocumentMarkAccess* pMarksAccess = m_pDoc->getIDocumentMarkAccess();
diff --git a/engine/sw/source/core/doc/docchart.cxx b/engine/sw/source/core/doc/docchart.cxx
index 3c5500cd2574..edd42c724d42 100644
--- a/engine/sw/source/core/doc/docchart.cxx
+++ b/engine/sw/source/core/doc/docchart.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/

+#include <cellatr.hxx>
#include <doc.hxx>
#include <IDocumentChartDataProviderAccess.hxx>
#include <IDocumentState.hxx>
@@ -172,6 +173,17 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rInName )
{
aNewName = GetUniqueTableName();
}
+
+ // Update all table formulas to reflect the table name change
+ OUString sOldName = aOldName.toString();
+ OUString sNewName = aNewName.toString();
+ std::vector<SwTableBoxFormula*> aTableBoxFormulas;
+ SwTable::GatherFormulas(*this, aTableBoxFormulas);
+ for (SwTableBoxFormula* pFormula : aTableBoxFormulas)
+ {
+ pFormula->RenameTableReference(sOldName, sNewName);
+ }
+
rTableFormat.SetFormatName( aNewName, true );

SwStartNode *pStNd;
diff --git a/engine/sw/source/core/fields/cellfml.cxx b/engine/sw/source/core/fields/cellfml.cxx
index 034d0e4118cd..b09bdf378864 100644
--- a/engine/sw/source/core/fields/cellfml.cxx
+++ b/engine/sw/source/core/fields/cellfml.cxx
@@ -924,6 +924,30 @@ static OUString lcl_BoxNmToRel( const SwTable& rTable, const SwTableNode& rTable
return sTmp;
}

+void SwTableFormula::RenameTableReference(std::u16string_view rOldName, std::u16string_view rNewName)
+{
+ const SwNode* pNode = GetNodeOfFormula();
+ if (!pNode)
+ return;
+
+ const SwTableNode* pTableNode = pNode->FindTableNode();
+ if (!pTableNode)
+ return;
+
+ const SwTable* pTable = &pTableNode->GetTable();
+ // Convert internal pointers to text names before replacing the table name
+ PtrToBoxNm(pTable);
+
+ OUString sOldPrefix = u"<"_ustr + rOldName + u"."_ustr;
+ OUString sFormulaText = GetFormula();
+ if (sFormulaText.indexOf(sOldPrefix) == -1)
+ return;
+
+ OUString sNewPrefix = u"<"_ustr + rNewName + u"."_ustr;
+ sFormulaText = sFormulaText.replaceAll(sOldPrefix, sNewPrefix);
+ SetFormula(sFormulaText);
+}
+
void SwTableFormula::GetBoxesOfFormula( const SwTable& rTable,
SwSelBoxes& rBoxes )
{
diff --git a/engine/sw/source/core/table/swtable.cxx b/engine/sw/source/core/table/swtable.cxx
index 3021158cb261..ac6dd7701f07 100644
--- a/engine/sw/source/core/table/swtable.cxx
+++ b/engine/sw/source/core/table/swtable.cxx
@@ -1628,10 +1628,10 @@ void SwTable::GatherFormulas(std::vector<SwTableBoxFormula*>& rvFormulas)
GatherFormulas(GetFrameFormat()->GetDoc(), rvFormulas);
}

-void SwTable::GatherFormulas(SwDoc& rDoc, std::vector<SwTableBoxFormula*>& rvFormulas)
+void SwTable::GatherFormulas(const SwDoc& rDoc, std::vector<SwTableBoxFormula*>& rvFormulas)
{
rvFormulas.clear();
- sw::TableFrameFormats* pTableFrameFormats = rDoc.GetTableFrameFormats();
+ const sw::TableFrameFormats* pTableFrameFormats = rDoc.GetTableFrameFormats();
for(SwTableFormat* pFormat : *pTableFrameFormats)
{
SwTable* pTable = FindTable(pFormat);

"Jakub Trzebiatowski (via cogerrit)"

unread,
May 11, 2026, 3:17:48 AMMay 11
to collaboraon...@googlegroups.com
engine/sw/qa/core/uwriter.cxx | 5 ++++-
engine/sw/source/core/fields/cellfml.cxx | 18 ++----------------
2 files changed, 6 insertions(+), 17 deletions(-)

New commits:
commit 9d566e9027fcf1aa5515210830700d7f0453fa18
Author: Jakub Trzebiatowski <ubap...@gmail.com>
AuthorDate: Sat May 9 07:59:38 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Mon May 11 07:17:15 2026 +0000

tdf#83196 sw: simplify SwTableFormula::RenameTableReference

- m_sFormula uses the name of another table as a reference, even when
optimized to use pointers: <Table1.105553132416256>
- Therefore, there is no need to change pointers to box names (PtrToBoxNm)

Change-Id: I4bae13ca89a19225e6353304b4464e4670b1d8db
Signed-off-by: Jakub Trzebiatowski <ubap...@gmail.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2306
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/core/uwriter.cxx b/engine/sw/qa/core/uwriter.cxx
index d6f0b2a6889d..ff605c5ee255 100644
--- a/engine/sw/qa/core/uwriter.cxx
+++ b/engine/sw/qa/core/uwriter.cxx
@@ -1455,13 +1455,16 @@ void SwDocTest::testRenameTableReference()

aIdx.Assign(m_pDoc->GetNodes().GetEndOfContent(), -1);
aPos.Assign(aIdx.GetNode(), 0);
- m_pDoc->InsertTable(aOpt, aPos, 1, 2, 0);
+ const SwTable* pTable2 = m_pDoc->InsertTable(aOpt, aPos, 1, 2, 0);

SwTableFormulaTest aFormula("", pTable1->GetTableNode());
aFormula.SetFormula(u"=<Table2.A1> * <Table1.A1> + <Table2.B1>"_ustr);
aFormula.BoxNmToPtr(pTable1);

aFormula.RenameTableReference(u"Table2", u"NewTable");
+ // Rename the table so PtrToBoxNm can work correctly
+ pTable2->GetFrameFormat()->SetFormatName(UIName(u"NewTable"_ustr));
+ aFormula.PtrToBoxNm(pTable1);
CPPUNIT_ASSERT_EQUAL(u"=<NewTable.A1> * <Table1.A1> + <NewTable.B1>"_ustr, aFormula.GetFormula());
}

diff --git a/engine/sw/source/core/fields/cellfml.cxx b/engine/sw/source/core/fields/cellfml.cxx
index b09bdf378864..83652b65172e 100644
--- a/engine/sw/source/core/fields/cellfml.cxx
+++ b/engine/sw/source/core/fields/cellfml.cxx
@@ -926,26 +926,12 @@ static OUString lcl_BoxNmToRel( const SwTable& rTable, const SwTableNode& rTable

void SwTableFormula::RenameTableReference(std::u16string_view rOldName, std::u16string_view rNewName)
{
- const SwNode* pNode = GetNodeOfFormula();
- if (!pNode)
+ if (m_sFormula.indexOf(rOldName) == -1)
return;

- const SwTableNode* pTableNode = pNode->FindTableNode();
- if (!pTableNode)
- return;
-
- const SwTable* pTable = &pTableNode->GetTable();
- // Convert internal pointers to text names before replacing the table name
- PtrToBoxNm(pTable);
-
OUString sOldPrefix = u"<"_ustr + rOldName + u"."_ustr;
- OUString sFormulaText = GetFormula();
- if (sFormulaText.indexOf(sOldPrefix) == -1)
- return;
-
OUString sNewPrefix = u"<"_ustr + rNewName + u"."_ustr;
- sFormulaText = sFormulaText.replaceAll(sOldPrefix, sNewPrefix);
- SetFormula(sFormulaText);
+ m_sFormula = m_sFormula.replaceAll(sOldPrefix, sNewPrefix);

"Jakub Trzebiatowski (via cogerrit)"

unread,
May 11, 2026, 3:28:13 AMMay 11
to collaboraon...@googlegroups.com
engine/sw/inc/strings.hrc | 1
engine/sw/inc/swundo.hxx | 1
engine/sw/qa/core/doc/doc.cxx | 38 ++++++++++++++++++++++++++++++++
engine/sw/source/core/doc/docchart.cxx | 7 +++++
engine/sw/source/core/inc/UndoTable.hxx | 11 +++++++++
engine/sw/source/core/undo/undobj.cxx | 3 ++
engine/sw/source/core/undo/untbl.cxx | 20 ++++++++++++++++
7 files changed, 81 insertions(+)

New commits:
commit 04aeb628cb9ffaf3c27587edac8ec3ebef5f1461
Author: Jakub Trzebiatowski <jakt...@gmail.com>
AuthorDate: Sun May 10 05:37:04 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Mon May 11 07:27:16 2026 +0000

tdf#171784 sw: Implement undo for renaming table

Change-Id: I7b4b4bac19374345ad642733faa3549eb9474880
Signed-off-by: Jakub Trzebiatowski <ubap...@gmail.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2315
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sw/inc/strings.hrc b/engine/sw/inc/strings.hrc
index 964f8d7739c2..5e69621b7740 100644
--- a/engine/sw/inc/strings.hrc
+++ b/engine/sw/inc/strings.hrc
@@ -461,6 +461,7 @@
#define STR_INSTABLE_UNDO NC_("STR_INSTABLE_UNDO", "Insert table: $1$2$3")
#define STR_TEXTTOTABLE_UNDO NC_("STR_TEXTTOTABLE_UNDO", "Convert text -> table")
#define STR_TABLETOTEXT_UNDO NC_("STR_TABLETOTEXT_UNDO", "Convert table -> text")
+#define STR_RENAMETABLE_UNDO NC_("STR_RENAMETABLE_UNDO", "Rename table")
#define STR_COPY_UNDO NC_("STR_COPY_UNDO", "Copy: $1")
#define STR_REPLACE_UNDO NC_("STR_REPLACE_UNDO", "Replace $1 $2 $3")
#define STR_INSERT_PAGE_BREAK_UNDO NC_("STR_INSERT_PAGE_BREAK_UNDO", "Insert page break")
diff --git a/engine/sw/inc/swundo.hxx b/engine/sw/inc/swundo.hxx
index f73274929efc..ffe015a6451f 100644
--- a/engine/sw/inc/swundo.hxx
+++ b/engine/sw/inc/swundo.hxx
@@ -185,6 +185,7 @@ enum class SwUndoId
CONVERT_FIELD_TO_TEXT = 153,
REINSTATE_REDLINE = 154,
COPY_HEADER_FOOTER = 155,
+ RENAME_TABLE = 156
};

OUString GetUndoComment(SwUndoId eId);
diff --git a/engine/sw/qa/core/doc/doc.cxx b/engine/sw/qa/core/doc/doc.cxx
index 4f526e45925d..510e17555c06 100644
--- a/engine/sw/qa/core/doc/doc.cxx
+++ b/engine/sw/qa/core/doc/doc.cxx
@@ -9,6 +9,7 @@

#include <swmodeltestbase.hxx>

+#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>

#include <comphelper/classids.hxx>
@@ -644,6 +645,43 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testTableNameUpdatePropagatedToFormulas)
u"ooow:<NewTableName.A1>");
}

+// tdf#171784
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testTableNameUndo)
+{
+ createSwDoc("tdf83196.fodt");
+
+ // Table2.A1 contains a reference to Table1.A1.
+ // We assert that the formula updates correctly when the target table is renamed.
+ auto getFormula = [&] {
+ uno::Reference<text::XTextTablesSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextTable> xTable(xSupplier->getTextTables()->getByName("Table2"),
+ uno::UNO_QUERY);
+ return xTable->getCellByName("A1")->getFormula();
+ };
+
+ SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+ SwFrameFormat* pFrameFormat = getSwDoc()->FindTableFormatByName(UIName("Table1"));
+
+ pWrtShell->SetTableName(*pFrameFormat, UIName("Table1"));
+ bool bCreatedUndoAction = pWrtShell->GetLastUndoInfo(nullptr, nullptr);
+ CPPUNIT_ASSERT_MESSAGE("Renaming Table1 to Table1 should have no effect", !bCreatedUndoAction);
+
+ pWrtShell->SetTableName(*pFrameFormat, UIName("Table100"));
+ CPPUNIT_ASSERT_MESSAGE("Table1 name should be updated to Table100",
+ pFrameFormat->HasName(u"Table100"));
+ CPPUNIT_ASSERT_EQUAL(OUString("<Table100.A1>"), getFormula());
+
+ pWrtShell->Undo();
+ CPPUNIT_ASSERT_MESSAGE("Table100 name should revert to Table1 after Undo",
+ pFrameFormat->HasName(u"Table1"));
+ CPPUNIT_ASSERT_EQUAL(OUString("<Table1.A1>"), getFormula());
+
+ pWrtShell->Redo();
+ CPPUNIT_ASSERT_MESSAGE("Table1 name should change to Table100 after Redo",
+ pFrameFormat->HasName(u"Table100"));
+ CPPUNIT_ASSERT_EQUAL(OUString("<Table100.A1>"), getFormula());
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testVirtPageNumReset)
{
createSwDoc("tdf160843.odt");
diff --git a/engine/sw/source/core/doc/docchart.cxx b/engine/sw/source/core/doc/docchart.cxx
index edd42c724d42..cc554ec9741d 100644
--- a/engine/sw/source/core/doc/docchart.cxx
+++ b/engine/sw/source/core/doc/docchart.cxx
@@ -21,6 +21,7 @@
#include <doc.hxx>
#include <IDocumentChartDataProviderAccess.hxx>
#include <IDocumentState.hxx>
+#include <IDocumentUndoRedo.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <ndindex.hxx>
#include <swtable.hxx>
@@ -29,6 +30,7 @@
#include <swtblfmt.hxx>
#include <tblsel.hxx>
#include <frameformats.hxx>
+#include <UndoTable.hxx>
#include <unochart.hxx>
#include <osl/diagnose.h>

@@ -153,6 +155,8 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rInName )
{
UIName aNewName = rInName;
const UIName aOldName( rTableFormat.GetName() );
+ if (aOldName == aNewName)
+ return;

bool bNameFound = aNewName.isEmpty();
if( !bNameFound )
@@ -186,6 +190,9 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rInName )

rTableFormat.SetFormatName( aNewName, true );

+ if (GetIDocumentUndoRedo().DoesUndo())
+ GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoRenameTable>(aOldName, aNewName, *this));
+
SwStartNode *pStNd;
SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
diff --git a/engine/sw/source/core/inc/UndoTable.hxx b/engine/sw/source/core/inc/UndoTable.hxx
index cbe2a384b62e..3c8428e21ef7 100644
--- a/engine/sw/source/core/inc/UndoTable.hxx
+++ b/engine/sw/source/core/inc/UndoTable.hxx
@@ -428,4 +428,15 @@ public:
virtual SwRewriter GetRewriter() const override;
};

+class SwUndoRenameTable final : public SwUndo
+{
+ UIName m_sOldName;
+ UIName m_sNewName;
+public:
+ SwUndoRenameTable(const UIName& rOldName, const UIName& rNewName, const SwDoc& rDoc);
+
+ void UndoImpl(sw::UndoRedoContext& rContext) override;
+ void RedoImpl(sw::UndoRedoContext& rContext) override;
+};
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/engine/sw/source/core/undo/undobj.cxx b/engine/sw/source/core/undo/undobj.cxx
index 139f176323b1..40a9a5fbc267 100644
--- a/engine/sw/source/core/undo/undobj.cxx
+++ b/engine/sw/source/core/undo/undobj.cxx
@@ -700,6 +700,9 @@ OUString GetUndoComment(SwUndoId eId)
case SwUndoId::COPY_HEADER_FOOTER:
pId = STR_UNDO_COPY_HEADER_FOOTER;
break;
+ case SwUndoId::RENAME_TABLE:
+ pId = STR_RENAMETABLE_UNDO;
+ break;
}

assert(pId);
diff --git a/engine/sw/source/core/undo/untbl.cxx b/engine/sw/source/core/undo/untbl.cxx
index 68b218be656a..a6f07fc20dd2 100644
--- a/engine/sw/source/core/undo/untbl.cxx
+++ b/engine/sw/source/core/undo/untbl.cxx
@@ -3211,4 +3211,24 @@ SwRewriter SwUndoTableStyleUpdate::GetRewriter() const
return aResult;
}

+SwUndoRenameTable::SwUndoRenameTable(const UIName& rOldName, const UIName& rNewName, const SwDoc& rDoc)
+ : SwUndo(SwUndoId::RENAME_TABLE, rDoc)
+ , m_sOldName(rOldName)
+ , m_sNewName(rNewName)
+{ }
+
+void SwUndoRenameTable::UndoImpl(sw::UndoRedoContext& rContext)
+{
+ SwDoc& rDoc = rContext.GetDoc();
+ if (SwFrameFormat* pFormat = rDoc.FindTableFormatByName(m_sNewName))
+ rDoc.SetTableName(*pFormat, m_sOldName);
+}
+
+void SwUndoRenameTable::RedoImpl(sw::UndoRedoContext& rContext)
+{
+ SwDoc& rDoc = rContext.GetDoc();
+ if (SwFrameFormat* pFormat = rDoc.FindTableFormatByName(m_sOldName))
+ rDoc.SetTableName(*pFormat, m_sNewName);
+}

"Karthik (via cogerrit)"

unread,
May 12, 2026, 6:17:44 AM (13 days ago) May 12
to collaboraon...@googlegroups.com
engine/sw/qa/extras/layout/data/floattable-center-shift-down.docx |binary
engine/sw/qa/extras/layout/layout6.cxx | 13 ++++
engine/sw/source/core/layout/tabfrm.cxx | 27 +++++++---
3 files changed, 32 insertions(+), 8 deletions(-)

New commits:
commit 5d0765140507222dfa8a8275e6fc071b44b9614f
Author: Karthik <karthi...@collabora.com>
AuthorDate: Thu Apr 23 21:33:03 2026 +0530
Commit: Michael Stahl <michae...@collabora.com>
CommitDate: Tue May 12 10:16:47 2026 +0000

sw: Layout - avoid horizontal orientation check shifting down tables

This is an extension of 7b1c03ed87f7a21606e09863b23074e6b96e26d1,
no need to check HoriOrient to shift down tables. Also handle flys
inside a split-table.

Change-Id: I315cd253258ee001451403bab977b8695125d55d
Signed-off-by: Karthik <karthi...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1467
Reviewed-by: Michael Stahl <michae...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/extras/layout/data/floattable-center-shift-down.docx b/engine/sw/qa/extras/layout/data/floattable-center-shift-down.docx
new file mode 100644
index 000000000000..6de57f8cfb82
Binary files /dev/null and b/engine/sw/qa/extras/layout/data/floattable-center-shift-down.docx differ
diff --git a/engine/sw/qa/extras/layout/layout6.cxx b/engine/sw/qa/extras/layout/layout6.cxx
index 3db8d8fff99f..cdeb6c123c0f 100644
--- a/engine/sw/qa/extras/layout/layout6.cxx
+++ b/engine/sw/qa/extras/layout/layout6.cxx
@@ -2252,6 +2252,19 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170846_2)
assertXPath(pXmlDoc, "//page[2]//tab", 3); // Three tables on page 2
}

+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testInlineTableShiftDown)
+{
+ createSwDoc("floattable-center-shift-down.docx");
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // The floating table is on page 1.
+ assertXPath(pXmlDoc, "//page[1]/body/txt/anchored/fly", 1);
+ // Without the fix, an inline table was laid out at its natural position on
+ // page 1 and overlapped the floating table. With the fix, the inline tables
+ // are shifted to subsequent pages.
+ assertXPath(pXmlDoc, "//page[1]/body/tab", 0);
+}
+
} // end of anonymous namespace

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/engine/sw/source/core/layout/tabfrm.cxx b/engine/sw/source/core/layout/tabfrm.cxx
index 59d3b3116b44..6a5a5da382f3 100644
--- a/engine/sw/source/core/layout/tabfrm.cxx
+++ b/engine/sw/source/core/layout/tabfrm.cxx
@@ -3468,6 +3468,21 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,

bool bAddVerticalFlyOffsets = rIDSA.get(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS);

+ // A fly inside a split-table can cause the table to shift down because of
+ // IsAnLower(). A split-table contains a master SwTabFrame and its follows,
+ // IsAnLower() only walks GetUpper() chains, which skips checking follows
+ // of split-table.
+ auto isLowerOfTable = [this](const SwFrame* pFrame) -> bool
+ {
+ const SwTabFrame* pThisMaster = IsFollow() ? FindMaster() : this;
+ for (const SwTabFrame* pTab = pThisMaster; pTab; pTab = pTab->GetFollow())
+ {
+ if (pTab->IsAnLower(pFrame))
+ return true;
+ }
+ return false;
+ };
+
for (size_t i = 0; i < pPage->GetSortedObjs()->size(); ++i)
{
SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
@@ -3494,13 +3509,8 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
// text frame has already changed its page.
const SwTextFrame* pAnchorCharFrame = pFly->FindAnchorCharFrame();
const SwFormatHoriOrient& rHori= pFly->GetFormat()->GetHoriOrient();
- // TODO: why not just ignore HoriOrient?
- bool isHoriOrientShiftDown =
- rHori.GetHoriOrient() == text::HoriOrientation::NONE
- || rHori.GetHoriOrient() == text::HoriOrientation::LEFT
- || rHori.GetHoriOrient() == text::HoriOrientation::RIGHT;
// Only consider invalid Writer fly frames if they'll be shifted down.
- bool bIgnoreFlyValidity = bAddVerticalFlyOffsets && isHoriOrientShiftDown;
+ bool bIgnoreFlyValidity = bAddVerticalFlyOffsets;
bool bConsiderFly =
// #i46807# - do not consider invalid
// Writer fly frames.
@@ -3512,7 +3522,8 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
// fly isn't lower of table and
// anchor character frame of fly isn't lower of table
&& (pSpaceBelowBottom // not if in ShouldBwdMoved
- || (!IsAnLower(pFly) && (!pAnchorCharFrame || !IsAnLower(pAnchorCharFrame))))
+ || (!isLowerOfTable(pFly)
+ && (!pAnchorCharFrame || !isLowerOfTable(pAnchorCharFrame))))
// table isn't lower of fly
&& !pFly->IsAnLower(this)
// fly is lower of fly, the table is in
@@ -3560,7 +3571,7 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
const SwRect aFlyRectWithoutSpaces = pFly->GetObjRect();
if (!bShiftDown && bAddVerticalFlyOffsets)
{
- if (nSurround == text::WrapTextMode_PARALLEL && isHoriOrientShiftDown)
+ if (nSurround == text::WrapTextMode_PARALLEL)
{
// We know that wrapping was requested and the table frame overlaps with
// the fly frame. Check if the print area overlaps with the fly frame as

"Miklos Vajna (via cogerrit)"

unread,
May 13, 2026, 2:31:22 AM (13 days ago) May 13
to collaboraon...@googlegroups.com
engine/sw/qa/core/doc/DocumentRedlineManager.cxx | 53 ++++++++++
engine/sw/source/core/doc/DocumentContentOperationsManager.cxx | 10 +
engine/sw/source/core/doc/DocumentRedlineManager.cxx | 6 +
3 files changed, 69 insertions(+)

New commits:
commit 0449be1640408a3fad529ed5dec82ae7bd7af240
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Tue May 12 10:59:47 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 13 06:31:04 2026 +0000

cool#15749 sw interdependent redlines: fix creating a format on top of format

Open the bugdoc, BBB has a bold format redline from Alice. Select this,
apply italics, then reject the format redline, bold remains in the
document.

What happens is similar to commit
bd7f20bdf7d1e66ab13c46074c0482ccab6d6867 (cool#15451 sw interdependent
redlines: fix creating a format on top of format-on-delete, 2026-04-24),
but here we don't have a hierarchical change. DOCX also can't support
format-on-format, instead it merges the two format redlines into a
single one and goes with the metadata (author name, etc) of the new one.

Fix the problem the same way in Writer: keep the "use the new one, drop
the old one" behavior in
DocumentRedlineManager::PreAppendFormatRedline(), but copy the format
data over to the new redline, so a later reject will reject both the old
and the new format redline. Note that this function runs before the
format redline is filled based on the current format operation, so just
setting the extra data to the old redline's format data works.

An additional problem is that the old redline intentionally had no
format data (means: reset all direct format to default), but we had
unwanted fallback code at lcl_SetRedline(). As a result it filled an
empty format redline with the current model state. This makes sense for
a new format redline (bold, then start tracking, italics, revert: should
result in just bold), but not for format-on-format, because in that case
reject wants to get rid of bold, too. So check for the format-on-format
case here & don't fill the new redline from the model to have the
correct result.

Signed-off-by: Miklos Vajna <vmi...@collabora.com>
Change-Id: I558ed41ce0e84851092db4e51b301dc2ed15c0d8
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2438
Reviewed-by: Michael Stahl <michae...@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 c8bc7a0f5c14..7012bfa8fd1c 100644
--- a/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -536,6 +536,59 @@ CPPUNIT_TEST_FIXTURE(Test, testDelThenFormatFormatInside)
CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType());
CPPUNIT_ASSERT(!rRedlineData2.Next());
}
+
+CPPUNIT_TEST_FIXTURE(Test, testFormatThenFormatOther)
+{
+ // Given an "AAA <format>BBB CCC DDD</format> EEE" document with a bold
+ // format redline authored by Alice:
+ createSwDoc("fmt.docx");
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwDoc* pDoc = pDocShell->GetDoc();
+ IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+ SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+ CPPUNIT_ASSERT_EQUAL(u"Alice"_ustr, rRedlines[0]->GetAuthorString());
+
+ // When a different author selects the same range and applies italic:
+ SwModule* pModule = SwModule::get();
+ pModule->SetRedlineAuthor("Bob");
+ comphelper::ScopeGuard g(
+ [pModule] { pModule->SetRedlineAuthor(SwResId(STR_REDLINE_UNKNOWN_AUTHOR)); });
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ // Skip "AAA ".
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
+ // Select "BBB CCC DDD".
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 11, /*bBasicCall=*/false);
+ SwView& rView = pWrtShell->GetView();
+ {
+ 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 only surviving redline is now authored by Bob (the
+ // current user), not Alice:
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+ CPPUNIT_ASSERT_EQUAL(u"Bob"_ustr, rRedlines[0]->GetAuthorString());
+
+ // And when rejecting that surviving redline:
+ pWrtShell->RejectRedline(0, /*bDirect=*/false);
+
+ // Then make sure both Alice's bold and Bob's italic are gone from
+ // "BBB CCC DDD":
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 5, /*bBasicCall=*/false);
+ SfxItemSetFixed<RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT> aSet(pDoc->GetAttrPool());
+ pWrtShell->GetCurAttr(aSet);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 5 (WEIGHT_NORMAL)
+ // - Actual : 8 (WEIGHT_BOLD)
+ // i.e. the bold was in the document after reject, which is not correct.
+ CPPUNIT_ASSERT_EQUAL(WEIGHT_NORMAL, aSet.Get(RES_CHRATR_WEIGHT).GetValue());
+ CPPUNIT_ASSERT_EQUAL(ITALIC_NONE, aSet.Get(RES_CHRATR_POSTURE).GetValue());
+}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/engine/sw/source/core/doc/DocumentContentOperationsManager.cxx b/engine/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 3060f77bfba1..3539276bac5c 100644
--- a/engine/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/engine/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1263,6 +1263,7 @@ namespace //local functions originally from docfmt.cxx
// check existing redline on the same range, and use its extra data, if it exists
SwRedlineTable::size_type nRedlPos = rDoc.getIDocumentRedlineAccess().GetRedlinePos(
rRg.Start()->GetNode(), RedlineType::Format );
+ bool bExistingFormatRedlineAtRange = false;
if( SwRedlineTable::npos != nRedlPos )
{
const SwPosition *pRStt, *pREnd;
@@ -1273,6 +1274,7 @@ namespace //local functions originally from docfmt.cxx
SwComparePosition eCompare = ComparePosition( *rRg.Start(), *rRg.End(), *pRStt, *pREnd );
if ( eCompare == SwComparePosition::Inside || eCompare == SwComparePosition::Equal )
{
+ bExistingFormatRedlineAtRange = true;
if (pTmp->GetExtraData())
{
const SwRedlineExtraData* pExtraData = pTmp->GetExtraData();
@@ -1290,6 +1292,14 @@ namespace //local functions originally from docfmt.cxx
}
} while( pRStt <= rRg.Start() && ++nRedlPos < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size());
}
+ if (!xExtra && bExistingFormatRedlineAtRange)
+ {
+ // In case we have an existing format redline on the same range, but its data is
+ // intentionally empty, then make this explicit, to avoid having unwanted attributes in
+ // the format redline, due to the below "no existing format redline in the range" block.
+ xExtra.reset(new SwRedlineExtraData_FormatColl(
+ UIName(u""_ustr), SwPoolFormatId::UNKNOWN, nullptr));
+ }

SwRangeRedline * pRedline = new SwRangeRedline( RedlineType::Format, rRg );
auto const result(rDoc.getIDocumentRedlineAccess().AppendRedline( pRedline, true));
diff --git a/engine/sw/source/core/doc/DocumentRedlineManager.cxx b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
index 78e44af01cae..09dcb23dd95f 100644
--- a/engine/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/engine/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -2356,6 +2356,12 @@ void DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
MaybeNotifyRedlineModification(*rCtx.pRedl, m_rDoc);
break;
}
+
+ // Not hierarchical: then keep the new redline, but copy data from the old redline, so
+ // the result later can be a merge of both redline formats, not just the new one.
+ if (const SwRedlineExtraData* pExtra = rCtx.pRedl->GetExtraData())
+ rCtx.pNewRedl->SetExtraData(pExtra);
+
[[fallthrough]];
case SwComparePosition::Outside:
{

"Jakub Trzebiatowski (via cogerrit)"

unread,
May 13, 2026, 7:22:30 AM (12 days ago) May 13
to collaboraon...@googlegroups.com
engine/sw/qa/extras/unowriter/unowriter.cxx | 27 +++++++++++++++++++++
engine/sw/source/core/doc/docchart.cxx | 8 ------
engine/sw/source/core/unocore/unotbl.cxx | 36 ----------------------------
3 files changed, 29 insertions(+), 42 deletions(-)

New commits:
commit 209895b037f078d789f4901bc57cdb945e0ccd6c
Author: Jakub Trzebiatowski <ubap...@gmail.com>
AuthorDate: Mon May 11 18:15:43 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 13 11:21:44 2026 +0000

tdf#83196 tdf#171784 sw: unify table renaming logic

- Consolidate two code paths for renaming tables into SwDoc::SetTableName
- Move UpdateCharts to SwDoc::SetTableName to ensure consistent behavior
between the UNO API, Navigator and Table Properties
- UNO API contract change: Now generates a unique name instead of throwing an exception on name conflicts
- Optimization: Move the UpdateCharts call out of the loop

Change-Id: Ie64000e57f3186dea16cd9632ebc0bb7184ac4bd
Signed-off-by: Jakub Trzebiatowski <ubap...@gmail.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2408
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmi...@collabora.com>

diff --git a/engine/sw/qa/extras/unowriter/unowriter.cxx b/engine/sw/qa/extras/unowriter/unowriter.cxx
index 6dfc2799185b..ed0801dd4826 100644
--- a/engine/sw/qa/extras/unowriter/unowriter.cxx
+++ b/engine/sw/qa/extras/unowriter/unowriter.cxx
@@ -1230,6 +1230,33 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTextConvertToTableLineSpacing)
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(convertTwipToMm100(220)), aLineSpacing.Height);
}

+CPPUNIT_TEST_FIXTURE(SwUnoWriter, testRenameTableCollision)
+{
+ // Create a new document and add two tables
+ createSwDoc();
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Reference<lang::XMultiServiceFactory> xFac(xTextDocument, uno::UNO_QUERY_THROW);
+ auto xSimpleText = xTextDocument->getText();
+
+ auto addTable = [&]
+ {
+ uno::Reference<text::XTextTable> xTable(
+ xFac->createInstance(u"com.sun.star.text.TextTable"_ustr), uno::UNO_QUERY_THROW);
+ xSimpleText->insertTextContent(xSimpleText->getEnd(), xTable, true);
+ uno::Reference<container::XNamed> xNamed(xTable, uno::UNO_QUERY_THROW);
+ return xNamed;
+ };
+
+ auto xTable1 = addTable();
+ CPPUNIT_ASSERT_EQUAL(u"Table1"_ustr, xTable1->getName());
+ auto xTable2 = addTable();
+ CPPUNIT_ASSERT_EQUAL(u"Table2"_ustr, xTable2->getName());
+
+ // Without the accompanying change in place, this would have thrown an exception.
+ xTable1->setName(u"Table2"_ustr);
+ CPPUNIT_ASSERT_EQUAL(u"Table3"_ustr, xTable1->getName());
+}
+
CPPUNIT_TEST_FIXTURE(SwUnoWriter, testMultiSelect)
{
// Create a new document and add a text with several repeated sequences.
diff --git a/engine/sw/source/core/doc/docchart.cxx b/engine/sw/source/core/doc/docchart.cxx
index cc554ec9741d..4bebf17679d0 100644
--- a/engine/sw/source/core/doc/docchart.cxx
+++ b/engine/sw/source/core/doc/docchart.cxx
@@ -202,16 +202,10 @@ void SwDoc::SetTableName( SwFrameFormat& rTableFormat, const UIName &rInName )
if( pNd && aOldName == pNd->GetChartTableName() )
{
pNd->SetChartTableName( aNewName );
-
- SwTable* pTable = SwTable::FindTable( &rTableFormat );
- SwChartDataProvider *pPCD = getIDocumentChartDataProviderAccess().GetChartDataProvider();
- if (pPCD)
- pPCD->InvalidateTable( pTable );
- // following this the framework will now take care of repainting
- // the chart or it's replacement image...
}
aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
}
+ UpdateCharts( aNewName );
getIDocumentState().SetModified();
}

diff --git a/engine/sw/source/core/unocore/unotbl.cxx b/engine/sw/source/core/unocore/unotbl.cxx
index e140141ea506..95529c8bb85e 100644
--- a/engine/sw/source/core/unocore/unotbl.cxx
+++ b/engine/sw/source/core/unocore/unotbl.cxx
@@ -3019,41 +3019,7 @@ void SwXTextTable::setName(const OUString& rName)
throw uno::RuntimeException();

if(pFormat)
- {
- const UIName aOldName( pFormat->GetName() );
- const sw::TableFrameFormats* pFrameFormats = pFormat->GetDoc().GetTableFrameFormats();
- for (size_t i = pFrameFormats->size(); i;)
- {
- const SwTableFormat* pTmpFormat = (*pFrameFormats)[--i];
- if( !pTmpFormat->IsDefault() &&
- pTmpFormat->GetName() == rName &&
- pFormat->GetDoc().IsUsed( *pTmpFormat ))
- {
- throw uno::RuntimeException();
- }
- }
-
- pFormat->SetFormatName( UIName(rName) );
-
- SwStartNode *pStNd;
- SwNodeIndex aIdx( *pFormat->GetDoc().GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
- while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
- {
- ++aIdx;
- SwNode *const pNd = & aIdx.GetNode();
- if ( pNd->IsOLENode() &&
- aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() )
- {
- static_cast<SwOLENode*>(pNd)->SetChartTableName( UIName(rName) );
-
- SwTable* pTable = SwTable::FindTable( pFormat );
- //TL_CHART2: chart needs to be notified about name changes
- pFormat->GetDoc().UpdateCharts( pTable->GetFrameFormat()->GetName() );
- }
- aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
- }
- pFormat->GetDoc().getIDocumentState().SetModified();
- }
+ pFormat->GetDoc().SetTableName(*pFormat, UIName(rName));
else
m_pImpl->m_sTableName = rName;
}

"Méven Car (via cogerrit)"

unread,
May 14, 2026, 1:27:34 AM (12 days ago) May 14
to collaboraon...@googlegroups.com
engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

New commits:
commit 1d55dca77c10c4740df3ed901eaff38ecae41692
Author: Méven Car <meve...@collabora.com>
AuthorDate: Sat Apr 18 12:18:20 2026 +0000
Commit: Tomaž Vajngerl <tomaz.v...@collabora.com>
CommitDate: Thu May 14 05:27:04 2026 +0000

writerfilter: don't warn when popping top-level stylesheet/list contexts

DomainMapper_Impl::PopProperties warned "this should happen at a section
context end" whenever a non-CONTEXT_SECTION was popped to an empty stack.
styles.xml and numbering.xml push CONTEXT_STYLESHEET / CONTEXT_LIST at
document top level, so every such pop legitimately empties the stack and
the warning is a false positive. On a rich DOCX this can produce hundreds
of spurious lines.

Restrict the warning to unexpected contexts by accepting CONTEXT_STYLESHEET
during IsStyleSheetImport() and CONTEXT_LIST during IsNumberingImport().

Change-Id: I7f73c785c8f9f81988bd55000fb25f5cc826977c
Signed-off-by: Méven Car <meve...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2021
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Tomaž Vajngerl <tomaz.v...@collabora.com>

diff --git a/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
index 0f8793b4ce3c..04e79f6bbfe9 100644
--- a/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
+++ b/engine/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -1412,7 +1412,8 @@ void DomainMapper_Impl::PopProperties(ContextType eId)
}
else
{
- SAL_WARN_IF(eId != CONTEXT_SECTION, "writerfilter.dmapper",
+ SAL_WARN_IF((eId == CONTEXT_STYLESHEET && !IsStyleSheetImport())
+ || (eId == CONTEXT_LIST && !IsNumberingImport()), "writerfilter.dmapper",
"this should happen at a section context end");
m_pTopContext.clear();
}

"Caolán McNamara (via cogerrit)"

unread,
May 14, 2026, 6:35:46 AM (11 days ago) May 14
to collaboraon...@googlegroups.com
engine/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx | 11 ++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

New commits:
commit 5eb3238de9edb2faa1d996b942e5835b1456d8c7
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Wed May 13 19:44:19 2026 +0100
Commit: Noel Grandin <noel.g...@collabora.com>
CommitDate: Thu May 14 10:35:25 2026 +0000

Fix crash on attribute-less m:jc

Signed-off-by: Caolán McNamara <caolan....@collabora.com>
Change-Id: If8f8e2a1cfca4bd99f7daae4b6def713a3398d9a
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2577
Reviewed-by: Noel Grandin <noel.g...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx b/engine/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
index 127cddd251f5..7811706c957e 100644
--- a/engine/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
+++ b/engine/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
@@ -190,10 +190,13 @@ void SAL_CALL OOXMLFastContextHandler::startFastElement
else if (Element == (NMSP_officeMath | XML_jc) && mpParent && mpParent->mpParent )
{
mbIsMathPara = true;
- auto aAttrLst = Attribs->getFastAttributes();
- if (aAttrLst[0].Value == "center") mpParent->mpParent->mnMathJcVal = eMathParaJc::CENTER;
- if (aAttrLst[0].Value == "left") mpParent->mpParent->mnMathJcVal = eMathParaJc::LEFT;
- if (aAttrLst[0].Value == "right") mpParent->mpParent->mnMathJcVal = eMathParaJc::RIGHT;
+ if (Attribs->hasAttribute(M_TOKEN(val)))
+ {
+ OUString sVal = Attribs->getValue(M_TOKEN(val));
+ if (sVal == "center") mpParent->mpParent->mnMathJcVal = eMathParaJc::CENTER;
+ else if (sVal == "left") mpParent->mpParent->mnMathJcVal = eMathParaJc::LEFT;
+ else if (sVal == "right") mpParent->mpParent->mnMathJcVal = eMathParaJc::RIGHT;
+ }
}

if (oox::getNamespace(Element) == NMSP_mce)

"Noel Grandin (via cogerrit)"

unread,
May 14, 2026, 8:02:29 AM (11 days ago) May 14
to collaboraon...@googlegroups.com
engine/sw/source/filter/ww8/docxexport.cxx | 1 +
1 file changed, 1 insertion(+)

New commits:
commit 4d46d03fc56ddd7a816cd51cfa0b178d49f5465d
Author: Noel Grandin <noel.g...@collabora.co.uk>
AuthorDate: Wed May 13 13:17:23 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu May 14 12:01:31 2026 +0000

fix leak of XSLTTransformer

in

make CppunitTest_sw_ooxmlexport4

CPPUNIT_TEST_NAME=testSegFaultWhileSave

found by running under ASAN with detect_leaks=1

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

diff --git a/engine/sw/source/filter/ww8/docxexport.cxx b/engine/sw/source/filter/ww8/docxexport.cxx
index f9b20ed76586..5902a93b7cd9 100644
--- a/engine/sw/source/filter/ww8/docxexport.cxx
+++ b/engine/sw/source/filter/ww8/docxexport.cxx
@@ -1891,6 +1891,7 @@ static void lcl_UpdateXmlValues(const SdtData& sdtData, const uno::Reference<css

xTransformer->start();
xListener->wait();
+ xTransformer->terminate();
}

void DocxExport::WriteCustomXml()

"Noel Grandin (via cogerrit)"

unread,
May 14, 2026, 8:12:54 AM (11 days ago) May 14
to collaboraon...@googlegroups.com
engine/sw/source/core/bastyp/calc.cxx | 2 ++
1 file changed, 2 insertions(+)

New commits:
commit a8c1a7dd53d4c271deae4b1af9519b0b705f0ae3
Author: Noel Grandin <noel.g...@collabora.co.uk>
AuthorDate: Wed May 13 15:12:44 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu May 14 12:12:12 2026 +0000

fix leak in SwCalc::SetCharClass

triggered by running

make CppunitTest_sw_ooxmlexport16 CPPUNIT_TEST_NAME=testTdf150542

under ASAN with detect_leaks=1.

If this is called twice, we leak the previous object allocated.

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

diff --git a/engine/sw/source/core/bastyp/calc.cxx b/engine/sw/source/core/bastyp/calc.cxx
index 69543e33b97d..1e6df70fd182 100644
--- a/engine/sw/source/core/bastyp/calc.cxx
+++ b/engine/sw/source/core/bastyp/calc.cxx
@@ -560,6 +560,8 @@ const CharClass* SwCalc::GetCharClass() const

void SwCalc::SetCharClass(const LanguageTag& rLanguageTag)
{
+ if( m_pCharClass && m_pCharClass != &GetAppCharClass() )
+ delete m_pCharClass;
m_pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), rLanguageTag );
}


"Caolán McNamara (via cogerrit)"

unread,
May 15, 2026, 3:53:41 AM (11 days ago) May 15
to collaboraon...@googlegroups.com
engine/sw/source/core/doc/docredln.cxx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

New commits:
commit 7c967e23927222ab48d4fc3ed02baaa27ced82c0
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Thu May 14 12:20:31 2026 +0000
Commit: Noel Grandin <noel.g...@collabora.com>
CommitDate: Fri May 15 07:52:33 2026 +0000

ofz#513047070 return early before unnecessary dereference

Signed-off-by: Caolán McNamara <caolan....@collabora.com>
Change-Id: I046c867dd6426d4f27e8a8c73837b3e02894d857
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2602
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.g...@collabora.com>

diff --git a/engine/sw/source/core/doc/docredln.cxx b/engine/sw/source/core/doc/docredln.cxx
index a462ef857ab1..9f72ed3892a4 100644
--- a/engine/sw/source/core/doc/docredln.cxx
+++ b/engine/sw/source/core/doc/docredln.cxx
@@ -614,8 +614,10 @@ std::vector<std::unique_ptr<SwRangeRedline>> GetAllValidRanges(std::unique_ptr<S
static void lcl_setRowNotTracked(SwNode& rNode)
{
SwDoc& rDoc = rNode.GetDoc();
+ if (!rDoc.GetIDocumentUndoRedo().DoesUndo())
+ return;
const SwTableBox* pTableBox = rNode.GetTableBox();
- if ( rDoc.GetIDocumentUndoRedo().DoesUndo() && pTableBox )
+ if (pTableBox)
{
SvxPrintItem aSetTracking(RES_PRINT, false);
SwNodeIndex aInsPos( *(pTableBox->GetSttNd()), 1);

"Caolán McNamara (via cogerrit)"

unread,
May 15, 2026, 7:44:49 AM (10 days ago) May 15
to collaboraon...@googlegroups.com
engine/sw/source/core/graphic/ndgrf.cxx | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)

New commits:
commit 88fd877b797c2753d69b16c298b5cbfb182a0c97
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Thu May 14 14:19:01 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri May 15 11:44:06 2026 +0000

drop redundant getUserAllowsLinkUpdate guard around Connect in SwGrfNode::ReRead

redundant since:

commit 9b15aa2d222364341dc0b62913a79e7e4a74701f
Date: 2026-04-01 19:48:40 +0000

implement calc and draw/impress defer graphic fetch cases

which added the same check inside SvFileObject::Connect().

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

diff --git a/engine/sw/source/core/graphic/ndgrf.cxx b/engine/sw/source/core/graphic/ndgrf.cxx
index 426dd168312e..fb122ed0ce3e 100644
--- a/engine/sw/source/core/graphic/ndgrf.cxx
+++ b/engine/sw/source/core/graphic/ndgrf.cxx
@@ -231,13 +231,8 @@ bool SwGrfNode::ReRead(
maGrfObj.SetGraphic( *pGraphic );
onGraphicChanged();
bReadGrf = true;
- // Create connection without update, as we have the graphic,
- // but don't connect if the user has not yet allowed link
- // updates because the async download would fetch the URL
- // before the user is prompted
- SwDocShell* pDocSh = GetDoc().GetDocShell();
- if (!pDocSh || pDocSh->getEmbeddedObjectContainer().getUserAllowsLinkUpdate())
- mxLink->Connect();
+ // create connection without update, as we have the graphic
+ mxLink->Connect();
}
else
{

"Andras Timar (via cogerrit)"

unread,
May 17, 2026, 8:29:40 AM (8 days ago) May 17
to collaboraon...@googlegroups.com
engine/sw/source/uibase/shells/basesh.cxx | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

New commits:
commit 093183bf57f1c8f77cbd876f235e2063725a2d26
Author: Andras Timar <andras...@collabora.com>
AuthorDate: Sun May 17 14:28:40 2026 +0200
Commit: Andras Timar <andras...@collabora.com>
CommitDate: Sun May 17 14:28:40 2026 +0200

sw: fix C4065 in ExecField when DBCONNECTIVITY is disabled

When HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS is false (e.g. the
Windows app build), the only case label inside the switch was
preprocessed away, leaving a switch with just a default label. MSVC
warns C4065 on that, and the build treats warnings as errors.

Move the conditional outside the switch so the case-less form is not
generated at all.

Signed-off-by: Andras Timar <andras...@collabora.com>
Change-Id: I3fdf64817be87beb4cabcfe2a485a47fbf82d9df

diff --git a/engine/sw/source/uibase/shells/basesh.cxx b/engine/sw/source/uibase/shells/basesh.cxx
index 9242aad19220..89bc45c85296 100644
--- a/engine/sw/source/uibase/shells/basesh.cxx
+++ b/engine/sw/source/uibase/shells/basesh.cxx
@@ -3473,10 +3473,10 @@ void SwBaseShell::ExecuteGallery(SfxRequest &rReq)

void SwBaseShell::ExecField( SfxRequest const & rReq )
{
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
sal_uInt16 nSlot = rReq.GetSlot();
switch( nSlot )
{
-#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
case FN_CHANGE_DBFIELD:
{
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
@@ -3491,10 +3491,13 @@ void SwBaseShell::ExecField( SfxRequest const & rReq )
);
}
break;
-#endif
default:
OSL_FAIL("wrong dispatcher");
}
+#else
+ (void)rReq;
+ OSL_FAIL("wrong dispatcher");
+#endif
}

std::shared_ptr<std::vector<std::unique_ptr<SwPaM>>> SwBaseShell::CopyPaMRing(SwPaM& rOrig)

"Méven Car (via cogerrit)"

unread,
May 18, 2026, 1:30:16 AM (8 days ago) May 18
to collaboraon...@googlegroups.com
engine/sw/qa/extras/tiledrendering/tiledrendering.cxx | 40 +++++++++++++++++-
engine/sw/source/core/crsr/viscrs.cxx | 3 -
2 files changed, 40 insertions(+), 3 deletions(-)

New commits:
commit 85dfaa8a359bbed345ec3a8fd8b22bee72ee9364
Author: Méven Car <meve...@collabora.com>
AuthorDate: Wed May 6 13:48:28 2026 +0200
Commit: Tomaž Vajngerl <tomaz.v...@collabora.com>
CommitDate: Mon May 18 05:29:38 2026 +0000

sw: send invalidate-cursor with the originating view, not Current()

The SfxViewShell::Current() argument was introduced in 2021 by
273a25c7 ("change some LOK internal updates to be pull model
instead of push"), without any explicit justification - the
surrounding branches in the same patch already used the originating
view as both target and viewId.

In resize cascades (VCL setPosSize -> SfxFrame::Resize ->
SwView::OuterResizePixel -> ... -> SwVisibleCursor::Show)
Current() is null, which trips a "no explicit viewshell set"
SAL_WARN inside KitHelper. The end goal is to silence that
warning.

Use the 2-arg notifyUpdatePerViewId overload, which carries
pNotifyViewShell as target, viewId, and source. Add a regression
test that creates two views, makes view2 Current(), forces Show()
on view1, and asserts the callback's viewId is view1's own.

Update testVisCursorInvalidation accordingly: in the
setViewIdForVisCursorInvalidation block, view1's own-cursor
invalidation triggered by view2's typing is now attributed to
view1 (the cursor owner), not view2 (the active view at callback
time).

Change-Id: I15e931fd504beabab60ad8e176e1df9b29ca2543
Signed-off-by: Méven Car <meve...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2100
Reviewed-by: Tomaž Vajngerl <tomaz.v...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 9b5269739f11..5405c9aac827 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -65,6 +65,7 @@
#include <drawdoc.hxx>
#include <ndtxt.hxx>
#include <view.hxx>
+#include <viscrs.hxx>
#include <UndoManager.hxx>
#include <cmdid.h>
#include <redline.hxx>
@@ -2550,7 +2551,7 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testVisCursorInvalidation)

CPPUNIT_ASSERT(aView1.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
- CPPUNIT_ASSERT_EQUAL(nView2, aView1.m_nOwnCursorInvalidatedBy);
+ CPPUNIT_ASSERT_EQUAL(nView1, aView1.m_nOwnCursorInvalidatedBy);
CPPUNIT_ASSERT(aView2.m_bViewCursorInvalidated);
CPPUNIT_ASSERT(aView2.m_bOwnCursorInvalidated);
CPPUNIT_ASSERT_EQUAL(nView2, aView2.m_nOwnCursorInvalidatedBy);
@@ -2563,6 +2564,43 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testVisCursorInvalidation)
comphelper::COKit::setViewIdForVisCursorInvalidation(false);
}

+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testVisCursorInvalidationViewIdNotCurrent)
+{
+ // With two views and view2 active, Hide/Show on view1's own SwVisibleCursor
+ // must invalidate view1 and carry view1's id (not the active view's).
+ createDoc("dummy.fodt");
+ SwTestViewCallback aView1;
+ SwView* pView1 = dynamic_cast<SwView*>(SfxViewShell::Current());
+ CPPUNIT_ASSERT(pView1);
+ int nView1 = KitHelper::getCurrentView();
+
+ KitHelper::createView();
+ SwTestViewCallback aView2;
+ int nView2 = KitHelper::getCurrentView();
+ CPPUNIT_ASSERT(nView1 != nView2);
+ Scheduler::ProcessEventsToIdle();
+
+ comphelper::COKit::setViewIdForVisCursorInvalidation(true);
+
+ KitHelper::setView(nView2);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(SfxViewShell::Current() != static_cast<SfxViewShell*>(pView1));
+
+ aView1.m_bOwnCursorInvalidated = false;
+ aView1.m_nOwnCursorInvalidatedBy = -1;
+
+ SwVisibleCursor* pVisCursor = pView1->GetWrtShell().GetVisibleCursor();
+ CPPUNIT_ASSERT(pVisCursor);
+ pVisCursor->Hide();
+ pVisCursor->Show();
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT(aView1.m_bOwnCursorInvalidated);
+ CPPUNIT_ASSERT_EQUAL(nView1, aView1.m_nOwnCursorInvalidatedBy);
+
+ comphelper::COKit::setViewIdForVisCursorInvalidation(false);
+}
+
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testDeselectCustomShape)
{
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
diff --git a/engine/sw/source/core/crsr/viscrs.cxx b/engine/sw/source/core/crsr/viscrs.cxx
index 3caa45037491..fc3865622f22 100644
--- a/engine/sw/source/core/crsr/viscrs.cxx
+++ b/engine/sw/source/core/crsr/viscrs.cxx
@@ -255,8 +255,7 @@ void SwVisibleCursor::SetPosAndShow(SfxViewShell const * pViewShell)
}
else
{
- KitHelper::notifyUpdatePerViewId(*pNotifyViewShell, SfxViewShell::Current(),
- *pNotifyViewShell, KIT_CALLBACK_INVALIDATE_VISIBLE_CURSOR);
+ KitHelper::notifyUpdatePerViewId(*pNotifyViewShell, KIT_CALLBACK_INVALIDATE_VISIBLE_CURSOR);
KitHelper::notifyOtherViewsUpdatePerViewId(pNotifyViewShell, KIT_CALLBACK_INVALIDATE_VIEW_CURSOR);
}
}

"Jaume Pujantell (via cogerrit)"

unread,
May 18, 2026, 3:53:56 AM (8 days ago) May 18
to collaboraon...@googlegroups.com
engine/sw/qa/extras/uiwriter/uiwriter11.cxx | 28 ++++++++++++++++++++++++
engine/sw/source/uibase/docvw/AnnotationWin.cxx | 2 -
2 files changed, 29 insertions(+), 1 deletion(-)

New commits:
commit d8425d770caf10e92ebc8da30001dc75ae2fc37f
Author: Jaume Pujantell <jaume.p...@collabora.com>
AuthorDate: Wed May 13 17:41:18 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Mon May 18 07:53:35 2026 +0000

comments: resolve thread with root resolved

When a comment thread has the root resolved but is not fully resolved,
the user sees the option to resolve the thread, but clicking it
unresolves all comments instead of resolving them. Now with this fix
all comments get resolved.

Signed-off-by: Jaume Pujantell <jaume.p...@collabora.com>
Change-Id: Ic3b3bc9b82c1c640fffc0108673f37c5dff26480
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2593
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
index d203535f91af..9c52b9c5a6ff 100644
--- a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -595,6 +595,34 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testPageSizeKeepsOrientation)
CPPUNIT_ASSERT_GREATER(aLandscapeA4.Width(), aNewSize.Width());
}

+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testResolveCommentThreadPartiallyResolved)
+{
+ // Given a document with a comment thread (root + replies):
+ createSwDoc("tdf108791_comments_with_tracked_changes.fodt");
+
+ SwPostItMgr* pPostItMgr = getSwDocShell()->GetView()->GetPostItMgr();
+ auto& aPostItFields = pPostItMgr->GetPostItFields();
+ const SwPostItField* pRoot = aPostItFields[0]->mpPostIt->GetPostItField();
+ const SwPostItField* pReply = aPostItFields[1]->mpPostIt->GetPostItField();
+
+ // Put the thread into the partially-resolved state: root resolved, reply not.
+ OUString sRootId = OUString::number(pRoot->GetPostItId());
+ dispatchCommand(mxComponent, u".uno:ResolveComment"_ustr,
+ { comphelper::makePropertyValue(u"Id"_ustr, sRootId) });
+ CPPUNIT_ASSERT(pRoot->GetResolved());
+ CPPUNIT_ASSERT(!pReply->GetResolved());
+
+ // Resolve the thread the way online does, by id.
+ dispatchCommand(mxComponent, u".uno:ResolveCommentThread"_ustr,
+ { comphelper::makePropertyValue(u"Id"_ustr, sRootId) });
+
+ // Without the fix in place, this test would have failed with:
+ // - Expression: pRoot->GetResolved()
+ // i.e. the whole thread was unresolved.
+ CPPUNIT_ASSERT(pRoot->GetResolved());
+ CPPUNIT_ASSERT(pReply->GetResolved());
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

diff --git a/engine/sw/source/uibase/docvw/AnnotationWin.cxx b/engine/sw/source/uibase/docvw/AnnotationWin.cxx
index c1ce9fb7c264..902477f4f2f4 100644
--- a/engine/sw/source/uibase/docvw/AnnotationWin.cxx
+++ b/engine/sw/source/uibase/docvw/AnnotationWin.cxx
@@ -283,7 +283,7 @@ void SwAnnotationWin::ToggleResolved()
void SwAnnotationWin::ToggleResolvedForThread()
{
auto pTop = GetTopReplyNote();
- pTop->ToggleResolved();
+ pTop->SetResolved(!IsThreadResolved());
mrMgr.UpdateResolvedStatus(pTop);
mrMgr.LayoutPostIts();
}

"Andras Timar (via cogerrit)"

unread,
May 18, 2026, 4:04:26 AM (8 days ago) May 18
to collaboraon...@googlegroups.com
engine/sw/source/uibase/utlui/content.cxx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

New commits:
commit 49d66e488b5d6151c04abacf3508878c29766b12
Author: Andras Timar <andras...@collabora.com>
AuthorDate: Fri May 15 10:08:30 2026 +0200
Commit: Andras Timar <andras...@collabora.com>
CommitDate: Mon May 18 08:03:35 2026 +0000

sw: null-check SwPostItContent::GetPostItField() in BringCommentToAttention

Crash on NavigatorSelectComment when the underlying post-it field has
already died. SwPostItContent::Notify() nulls m_pField on SfxHintId::Dying,
so GetPostItField() may legitimately return nullptr while the navigator
entry is still around. content.cxx:7325 dereferenced it unconditionally:

SwContentTree::BringCommentToAttention (content.cxx:7325)
SwPostItContent::GetPostItField() -> nullptr
SwPostItField::GetPostItId() -> SIGSEGV (this+offsetof(m_nPostItId))

Capture the pointer and skip the entry if null, matching the guard
already used at content.cxx:6617.

Signed-off-by: Andras Timar <andras...@collabora.com>
Change-Id: I7a98ddb1cac69b15aa9af6346c4a177425a9718b
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2655

diff --git a/engine/sw/source/uibase/utlui/content.cxx b/engine/sw/source/uibase/utlui/content.cxx
index 70a716c4d5a5..b3f836d9f5c1 100644
--- a/engine/sw/source/uibase/utlui/content.cxx
+++ b/engine/sw/source/uibase/utlui/content.cxx
@@ -7322,7 +7322,8 @@ void SwContentTree::BringCommentToAttention(sal_uInt16 nCommentId)
{
if (const SwPostItContent* pPostIt = weld::fromId<SwPostItContent*>(m_xTreeView->get_id(*xIter)))
{
- if (nCommentId == pPostIt->GetPostItField()->GetPostItId())
+ const SwPostItField* pPostItField = pPostIt->GetPostItField();
+ if (pPostItField && nCommentId == pPostItField->GetPostItId())
{
GotoContent(weld::fromId<SwContent*>(m_xTreeView->get_id(*xIter)));
m_xTreeView->grab_focus();

"Caolán McNamara (via cogerrit)"

unread,
May 18, 2026, 9:24:35 AM (7 days ago) May 18
to collaboraon...@googlegroups.com
engine/sw/inc/numrule.hxx | 7
engine/sw/qa/core/layout/layout.cxx | 7
engine/sw/qa/extras/tiledrendering/data/image-bullet-link.fodt | 33 ++
engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx | 35 ++
engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx | 7
engine/sw/source/core/doc/number.cxx | 121 ++++++++++
engine/sw/source/core/layout/paintfrm.cxx | 16 +
7 files changed, 224 insertions(+), 2 deletions(-)

New commits:
commit e768c62b2140dd59910ce029cf82b2763ebad0ef
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Sat Apr 4 20:54:15 2026 +0100
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Mon May 18 13:24:25 2026 +0000

put writer numbering graphics under link control

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

diff --git a/engine/sw/inc/numrule.hxx b/engine/sw/inc/numrule.hxx
index c2541edba60e..491095cf0bd6 100644
--- a/engine/sw/inc/numrule.hxx
+++ b/engine/sw/inc/numrule.hxx
@@ -23,6 +23,7 @@
#include <rtl/ustring.hxx>
#include <editeng/numitem.hxx>
#include <i18nlangtag/lang.h>
+#include <tools/ref.hxx>
#include "swdllapi.h"
#include "swtypes.hxx"
#include "calbck.hxx"
@@ -38,6 +39,7 @@ class SwTextFormatColl;
class IDocumentListsAccess;
class SwNodeNum;
namespace vcl { class Font; }
+namespace sfx2 { class SvBaseLink; }
class SfxGrabBagItem;
class SwDoc;
class SwTextNode;
@@ -141,6 +143,8 @@ private:
OUString msDefaultListId;
std::shared_ptr<SfxGrabBagItem> mpGrabBagItem; ///< Style InteropGrabBag.

+ tools::SvRef<sfx2::SvBaseLink> maGrfLinks[ MAXLEVEL ];
+
public:
/// add parameter <eDefaultNumberFormatPositionAndSpaceMode>
SW_DLLPUBLIC SwNumRule( UIName aNm,
@@ -275,6 +279,9 @@ public:
void dumpAsXml(xmlTextWriterPtr w) const;
SW_DLLPUBLIC void GetGrabBagItem(css::uno::Any& rVal) const;
void SetGrabBagItem(const css::uno::Any& rVal);
+
+ void RegisterGrfLinks(SwDoc& rDoc);
+ void RemoveGrfLinks(SwDoc& rDoc);
};

/// namespace for static functions and methods for numbering and bullets
diff --git a/engine/sw/qa/core/layout/layout.cxx b/engine/sw/qa/core/layout/layout.cxx
index f4612122a6f6..374a4d640a70 100644
--- a/engine/sw/qa/core/layout/layout.cxx
+++ b/engine/sw/qa/core/layout/layout.cxx
@@ -14,6 +14,7 @@
#include <vcl/gdimtf.hxx>
#include <svx/svdpage.hxx>
#include <o3tl/string_view.hxx>
+#include <sfx2/linkmgr.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <editeng/frmdiritem.hxx>
@@ -23,6 +24,7 @@
#include <unotxdoc.hxx>
#include <drawdoc.hxx>
#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentLinksAdministration.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <rootfrm.hxx>
@@ -545,6 +547,11 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testLinkedBullet)
// Given a document with a graphic bullet, where the image is a linked one:
createSwDoc("linked-bullet.odt");
SwDocShell* pShell = getSwDocShell();
+ // allow link updates and trigger fetch so the linked bullet image
+ // is loaded before rendering
+ pShell->getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
+ sfx2::LinkManager& rLinkMgr = getSwDoc()->getIDocumentLinksAdministration().GetLinkManager();
+ rLinkMgr.UpdateAllLinks(false, nullptr, u""_ustr);

// When rendering that document:
std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
diff --git a/engine/sw/qa/extras/tiledrendering/data/image-bullet-link.fodt b/engine/sw/qa/extras/tiledrendering/data/image-bullet-link.fodt
new file mode 100644
index 000000000000..88c75f0eb8c5
--- /dev/null
+++ b/engine/sw/qa/extras/tiledrendering/data/image-bullet-link.fodt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+ office:version="1.2"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <text:list-style style:name="L1">
+ <text:list-level-style-image text:level="1"
+ xlink:href="http://192.0.2.1:12345/bullet.png"
+ xlink:type="simple" xlink:show="embed"
+ xlink:actuate="onLoad">
+ <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"
+ fo:width="0.4cm" fo:height="0.4cm">
+ <style:list-level-label-alignment text:label-followed-by="listtab"
+ fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/>
+ </style:list-level-properties>
+ </text:list-level-style-image>
+ </text:list-style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:list text:style-name="L1">
+ <text:list-item>
+ <text:p>Bullet item</text:p>
+ </text:list-item>
+ </text:list>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index 24428e256ab2..ba3960082626 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -27,10 +27,14 @@
#include <comphelper/scopeguard.hxx>
#include <sfx2/dispatch.hxx>
#include <tools/json_writer.hxx>
+#include <vcl/virdev.hxx>
#include <unotxdoc.hxx>

+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <sfx2/linkmgr.hxx>
#include <view.hxx>
#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentLinksAdministration.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <docsh.hxx>
@@ -855,6 +859,37 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testBlockedCommandSlotState)
eState = pDispatcher->QueryState(SID_ATTR_CHAR_WEIGHT, aResult);
CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED, eState);
}
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testImageBulletRemoteNotFetched)
+{
+ // text:list-level-style-image with a remote xlink:href must not fetch
+ // the URL during paint when link updates are not allowed.
+ comphelper::COKit::setActive(false);
+ comphelper::ScopeGuard aCOKitGuard([] { comphelper::COKit::setActive(true); });
+
+ uno::Sequence<beans::PropertyValue> aParams = {
+ comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
+ sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
+ };
+ loadWithParams(createFileURL(u"image-bullet-link.fodt"), aParams);
+
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+
+ // the bullet image link should be registered in the link manager
+ sfx2::LinkManager& rLinkMgr
+ = pDocShell->GetDoc()->getIDocumentLinksAdministration().GetLinkManager();
+ CPPUNIT_ASSERT_MESSAGE("bullet image link should be registered", !rLinkMgr.GetLinks().empty());
+
+ pWrtShell->CalcLayout();
+
+ // render through SwViewShell::Paint which exercises the full text paint
+ // path including SwGrfNumPortion::Paint -> DrawGraphic -> lcl_DrawGraphic.
+ // The getUserAllowsLinkUpdate guard blocks the fetch.
+ ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
+ pDevice->SetOutputSizePixel(Size(1024, 1024));
+ static_cast<SwViewShell*>(pWrtShell)->Paint(
+ *pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
+}
}

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx b/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
index 156ddb84b042..807886539935 100644
--- a/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
+++ b/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
@@ -38,6 +38,7 @@
#include <section.hxx>
#include <docary.hxx>
#include <frmfmt.hxx>
+#include <numrule.hxx>
#include <fmtcntnt.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
@@ -199,6 +200,12 @@ void DocumentLinksAdministrationManager::UpdateLinks()
return;
if (pShell->IsPreview())
return;
+
+ // Register links for numbering rules with remote bullet images
+ // before checking whether the link list is empty
+ for (SwNumRuleTable::size_type n = 0; n < m_rDoc.GetNumRuleTable().size(); ++n)
+ m_rDoc.GetNumRuleTable()[n]->RegisterGrfLinks(m_rDoc);
+
if (GetLinkManager().GetLinks().empty())
return;
sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode(true);
diff --git a/engine/sw/source/core/doc/number.cxx b/engine/sw/source/core/doc/number.cxx
index e3cd0915f423..3c3aadc6a4e8 100644
--- a/engine/sw/source/core/doc/number.cxx
+++ b/engine/sw/source/core/doc/number.cxx
@@ -39,6 +39,11 @@

#include <numrule.hxx>
#include <SwNodeNum.hxx>
+#include <sfx2/lnkbase.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <IDocumentLinksAdministration.hxx>

#include <list.hxx>

@@ -558,6 +563,122 @@ SwNumRule::~SwNumRule()
maParagraphStyleList.clear();
}

+namespace {
+
+class SwNumRuleLink final : public sfx2::SvBaseLink
+{
+ SwNumRule* m_pRule;
+ SwDoc* m_pDoc;
+ sal_uInt16 m_nLevel;
+public:
+ SwNumRuleLink(SwNumRule* pRule, SwDoc* pDoc, sal_uInt16 nLevel)
+ : SvBaseLink(SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
+ , m_pRule(pRule)
+ , m_pDoc(pDoc)
+ , m_nLevel(nLevel)
+ {
+ }
+
+ virtual UpdateResult DataChanged(const OUString& rMimeType,
+ const css::uno::Any& rValue) override
+ {
+ if (!m_pRule || !m_pDoc)
+ return ERROR_GENERAL;
+
+ Graphic aGrf;
+ sfx2::LinkManager& rLinkMgr
+ = m_pDoc->getIDocumentLinksAdministration().GetLinkManager();
+ if (!rLinkMgr.GetGraphicFromAny(rMimeType, rValue, aGrf, nullptr))
+ return ERROR_GENERAL;
+ if (aGrf.GetType() == GraphicType::Default)
+ return ERROR_GENERAL;
+
+ const SwNumFormat* pFmt = m_pRule->GetNumFormat(m_nLevel);
+ if (!pFmt)
+ return SUCCESS;
+
+ const SvxBrushItem* pBrush = pFmt->GetBrush();
+ if (!pBrush)
+ return SUCCESS;
+
+ SvxBrushItem aNewBrush(OUString(), OUString(), GPOS_AREA, RES_BACKGROUND);
+ aNewBrush.SetGraphic(aGrf);
+ Size aSize = pFmt->GetGraphicSize();
+ if (!aSize.Width() || !aSize.Height())
+ {
+ Size aPixelSize = aGrf.GetSizePixel();
+ if (aPixelSize.Width() && aPixelSize.Height())
+ aSize = OutputDevice::LogicToLogic(aPixelSize,
+ MapMode(MapUnit::MapPixel),
+ MapMode(MapUnit::MapTwip));
+ }
+ sal_Int16 eOrient = pFmt->GetVertOrient();
+ SwNumFormat aNewFmt(*pFmt);
+ aNewFmt.SetGraphicBrush(&aNewBrush, &aSize, &eOrient);
+ m_pRule->Set(m_nLevel, aNewFmt);
+
+ SwNumRule::tTextNodeList aTextNodeList;
+ m_pRule->GetTextNodeList(aTextNodeList);
+ for (SwTextNode* pNode : aTextNodeList)
+ pNode->NumRuleChgd();
+
+ return SUCCESS;
+ }
+};
+
+}
+
+void SwNumRule::RegisterGrfLinks(SwDoc& rDoc)
+{
+ sfx2::LinkManager& rLinkMgr
+ = rDoc.getIDocumentLinksAdministration().GetLinkManager();
+
+ for (sal_uInt16 n = 0; n < MAXLEVEL; ++n)
+ {
+ if (maGrfLinks[n])
+ continue;
+
+ const SwNumFormat* pFmt = GetNumFormat(n);
+ if (!pFmt)
+ continue;
+
+ const SvxBrushItem* pBrush = pFmt->GetBrush();
+ if (!pBrush)
+ continue;
+
+ const Graphic* pGrf = pBrush->GetGraphicObject()
+ ? &pBrush->GetGraphicObject()->GetGraphic()
+ : nullptr;
+ if (!pGrf)
+ continue;
+ if (pGrf->GetType() != GraphicType::Default)
+ continue;
+
+ OUString aOriginURL = pGrf->getOriginURL();
+ if (aOriginURL.isEmpty())
+ continue;
+
+ maGrfLinks[n] = new SwNumRuleLink(this, &rDoc, n);
+ rLinkMgr.InsertFileLink(*maGrfLinks[n],
+ sfx2::SvBaseLinkObjectType::ClientGraphic,
+ aOriginURL);
+ }
+}
+
+void SwNumRule::RemoveGrfLinks(SwDoc& rDoc)
+{
+ sfx2::LinkManager& rLinkMgr
+ = rDoc.getIDocumentLinksAdministration().GetLinkManager();
+ for (auto& rLink : maGrfLinks)
+ {
+ if (rLink)
+ {
+ rLinkMgr.Remove(rLink.get());
+ rLink.clear();
+ }
+ }
+}
+
void SwNumRule::CheckCharFormats( SwDoc& rDoc )
{
for(auto& rpNumFormat : maFormats)
diff --git a/engine/sw/source/core/layout/paintfrm.cxx b/engine/sw/source/core/layout/paintfrm.cxx
index 25b0f5688ba8..bb2faca87fc0 100644
--- a/engine/sw/source/core/layout/paintfrm.cxx
+++ b/engine/sw/source/core/layout/paintfrm.cxx
@@ -18,6 +18,7 @@
*/

#include <utility>
+#include <o3tl/test_info.hxx>
#include <vcl/alpha.hxx>
#include <vcl/canvastools.hxx>
#include <tools/lazydelete.hxx>
@@ -1661,11 +1662,22 @@ static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext &rOu

GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());

+ // If a graphic with a URL reaches paint without being loaded, only fetch
+ // it when link updates are allowed.
+ // Once all URLs as GraphicExternalLink are brought under link manager
+ // control (bullet images, background images, etc.), this block should
+ // become unreachable and can be removed.
OUString aOriginURL = pGrf->GetGraphic().getOriginURL();
if (pGrf->GetGraphic().GetType() == GraphicType::Default && !aOriginURL.isEmpty())
{
- Graphic aGraphic = vcl::graphic::loadFromURL(aOriginURL);
- pGrf->SetGraphic(aGraphic);
+ SfxObjectShell* pSh = rSh.GetDoc()->GetPersist();
+ if (pSh && pSh->getEmbeddedObjectContainer().getUserAllowsLinkUpdate())
+ {
+ assert(!o3tl::IsRunningUnitTest()
+ && "lcl_DrawGraphic: unexpected remote graphic fetch during unit test");
+ Graphic aGraphic = vcl::graphic::loadFromURL(aOriginURL);
+ pGrf->SetGraphic(aGraphic);
+ }
}

// Outsource drawing of background with a background color

"Caolán McNamara (via cogerrit)"

unread,
May 20, 2026, 5:26:04 AM (5 days ago) May 20
to collaboraon...@googlegroups.com
engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx | 1 -
engine/sw/source/core/doc/docnew.cxx | 1 +
engine/sw/source/core/doc/docnum.cxx | 1 +
engine/sw/source/core/doc/number.cxx | 1 +
4 files changed, 3 insertions(+), 1 deletion(-)

New commits:
commit 5ae5ec664c0f6b578c4006adc09ad7951760b644
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Mon May 18 14:51:39 2026 +0100
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 20 09:25:30 2026 +0000

call RemoveGrfLinks on num rule teardown

add some explanatory comment to the new class, and remove
some unnecessary scope guarding.

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

diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index ba3960082626..f51adce9a505 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -864,7 +864,6 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testImageBulletRemoteNotFetched)
// text:list-level-style-image with a remote xlink:href must not fetch
// the URL during paint when link updates are not allowed.
comphelper::COKit::setActive(false);
- comphelper::ScopeGuard aCOKitGuard([] { comphelper::COKit::setActive(true); });

uno::Sequence<beans::PropertyValue> aParams = {
comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
diff --git a/engine/sw/source/core/doc/docnew.cxx b/engine/sw/source/core/doc/docnew.cxx
index 43d4a537dd05..a98cb21b4735 100644
--- a/engine/sw/source/core/doc/docnew.cxx
+++ b/engine/sw/source/core/doc/docnew.cxx
@@ -724,6 +724,7 @@ void SwDoc::ClearDoc()
mpOutlineRule = nullptr;
for( SwNumRule* pNumRule : *mpNumRuleTable )
{
+ pNumRule->RemoveGrfLinks(*this);
getIDocumentListsAccess().deleteListForListStyle(pNumRule->GetName());
delete pNumRule;
}
diff --git a/engine/sw/source/core/doc/docnum.cxx b/engine/sw/source/core/doc/docnum.cxx
index dc14f30e6755..bb21ed7833ac 100644
--- a/engine/sw/source/core/doc/docnum.cxx
+++ b/engine/sw/source/core/doc/docnum.cxx
@@ -1182,6 +1182,7 @@ bool SwDoc::DelNumRule( const UIName& rName, bool bBroadcast )
// #i34097# DeleteAndDestroy deletes rName if
// rName is directly taken from the numrule.
const UIName aTmpName( rName );
+ (*mpNumRuleTable)[ nPos ]->RemoveGrfLinks(*this);
delete (*mpNumRuleTable)[ nPos ];
mpNumRuleTable->erase( mpNumRuleTable->begin() + nPos );
maNumRuleMap.erase(aTmpName);
diff --git a/engine/sw/source/core/doc/number.cxx b/engine/sw/source/core/doc/number.cxx
index 3c3aadc6a4e8..5776c742ab15 100644
--- a/engine/sw/source/core/doc/number.cxx
+++ b/engine/sw/source/core/doc/number.cxx
@@ -565,6 +565,7 @@ SwNumRule::~SwNumRule()

namespace {

+/// Numbering rule bullets can be bitmaps, and those can be links
class SwNumRuleLink final : public sfx2::SvBaseLink
{
SwNumRule* m_pRule;

"Caolán McNamara (via cogerrit)"

unread,
May 20, 2026, 5:34:32 AM (5 days ago) May 20
to collaboraon...@googlegroups.com
engine/sw/qa/extras/odfimport/data/background-image-link.fodt | 25 +++
engine/sw/qa/extras/tiledrendering/data/background-image-link.fodt | 25 +++
engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx | 32 ++++
engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx | 80 +++++++++-
engine/sw/source/core/inc/fillattrcache.hxx | 36 ++++
engine/sw/source/core/layout/atrfrm.cxx | 8 -
engine/sw/source/core/txtnode/ndtxt.cxx | 8 -
7 files changed, 211 insertions(+), 3 deletions(-)

New commits:
commit 970434f2e031a4bb5dfcd884e67795149631d00f
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Tue Apr 7 09:38:06 2026 +0100
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 20 09:33:50 2026 +0000

put writer bg images under link control

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

diff --git a/engine/sw/qa/extras/odfimport/data/background-image-link.fodt b/engine/sw/qa/extras/odfimport/data/background-image-link.fodt
new file mode 100644
index 000000000000..d0682dbe50cc
--- /dev/null
+++ b/engine/sw/qa/extras/odfimport/data/background-image-link.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ office:version="1.3"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="P1" style:family="paragraph">
+ <style:paragraph-properties>
+ <style:background-image
+ xlink:href="http://192.0.2.1:12345/background.png"
+ xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"
+ style:position="center" style:repeat="no-repeat"/>
+ </style:paragraph-properties>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p text:style-name="P1">Paragraph with remote background image.</text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/tiledrendering/data/background-image-link.fodt b/engine/sw/qa/extras/tiledrendering/data/background-image-link.fodt
new file mode 100644
index 000000000000..d0682dbe50cc
--- /dev/null
+++ b/engine/sw/qa/extras/tiledrendering/data/background-image-link.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ office:version="1.3"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="P1" style:family="paragraph">
+ <style:paragraph-properties>
+ <style:background-image
+ xlink:href="http://192.0.2.1:12345/background.png"
+ xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"
+ style:position="center" style:repeat="no-repeat"/>
+ </style:paragraph-properties>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:p text:style-name="P1">Paragraph with remote background image.</text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index f51adce9a505..8c6273f6525f 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -889,6 +889,38 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testImageBulletRemoteNotFetched)
static_cast<SwViewShell*>(pWrtShell)->Paint(
*pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
}
+
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testBackgroundImageRemoteNotFetched)
+{
+ // style:background-image with a remote xlink:href must not fetch
+ // the URL during paint when link updates are not allowed.
+ comphelper::COKit::setActive(false);
+
+ uno::Sequence<beans::PropertyValue> aParams = {
+ comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
+ sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
+ };
+ loadWithParams(createFileURL(u"background-image-link.fodt"), aParams);
+
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+
+ // the background image link should be registered in the link manager
+ sfx2::LinkManager& rLinkMgr
+ = pDocShell->GetDoc()->getIDocumentLinksAdministration().GetLinkManager();
+ CPPUNIT_ASSERT_MESSAGE("background image link should be registered",
+ !rLinkMgr.GetLinks().empty());
+
+ pWrtShell->CalcLayout();
+
+ // render through SwViewShell::Paint which exercises the fill attribute
+ // rendering path via createNewSdrFillGraphicAttribute.
+ // The assert in that function will fire if a remote fetch is attempted.
+ ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
+ pDevice->SetOutputSizePixel(Size(1024, 1024));
+ static_cast<SwViewShell*>(pWrtShell)->Paint(
+ *pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
+}
}

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx b/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
index 807886539935..46b6f1c8af94 100644
--- a/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
+++ b/engine/sw/source/core/doc/DocumentLinksAdministrationManager.cxx
@@ -38,21 +38,84 @@
#include <section.hxx>
#include <docary.hxx>
#include <frmfmt.hxx>
+#include <IDocumentLayoutAccess.hxx>
#include <numrule.hxx>
+#include <rootfrm.hxx>
#include <fmtcntnt.hxx>
#include <swtable.hxx>
#include <ndtxt.hxx>
#include <frameformats.hxx>
+#include <svl/itempool.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xdef.hxx>
#include <tools/urlobj.hxx>
#include <unotools/charclass.hxx>
#include <unotools/securityoptions.hxx>
+#include <vcl/GraphicObject.hxx>
#include <utility>

using namespace ::com::sun::star;

-//Helper functions for this file
namespace
{
+ // Link class for fill bitmap items with remote URLs.
+ // DataChanged receives the fetched graphic and updates the actual
+ // XFillBitmapItem in the attribute pool so the drawing layer picks up
+ // the resolved image on the next repaint.
+ class SwFillBitmapLink final : public sfx2::SvBaseLink
+ {
+ SwDoc* m_pDoc;
+ public:
+ SwFillBitmapLink(SwDoc* pDoc)
+ : SvBaseLink(SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
+ , m_pDoc(pDoc)
+ {
+ }
+
+ virtual UpdateResult DataChanged(const OUString& rMimeType,
+ const css::uno::Any& rValue) override
+ {
+ if (!m_pDoc)
+ return ERROR_GENERAL;
+
+ Graphic aGrf;
+ sfx2::LinkManager& rLinkMgr
+ = m_pDoc->getIDocumentLinksAdministration().GetLinkManager();
+ if (!rLinkMgr.GetGraphicFromAny(rMimeType, rValue, aGrf, nullptr))
+ return ERROR_GENERAL;
+ if (aGrf.GetType() == GraphicType::Default)
+ return ERROR_GENERAL;
+
+ OUString aURL;
+ sfx2::LinkManager::GetDisplayNames(this, nullptr, &aURL);
+ GraphicObject aGrfObj(aGrf);
+
+ // Replace the item in all attribute sets via pool surrogates
+ m_pDoc->GetAttrPool().iterateItemSurrogates(XATTR_FILLBITMAP,
+ [&aURL, &aGrfObj](SfxItemPool::SurrogateData& rData) -> bool
+ {
+ auto& rItem = static_cast<const XFillBitmapItem&>(rData.getItem());
+ const Graphic& rGrf = rItem.GetGraphicObject().GetGraphic();
+ if (rGrf.GetType() == GraphicType::Default
+ && rGrf.getOriginURL() == aURL)
+ {
+ rData.setItem(std::make_unique<XFillBitmapItem>(aGrfObj));
+ }
+ return true;
+ });
+
+ // The surrogate replacement bypasses Writer's change notification,
+ // but the SdrAllFillAttributesHelper cache on SwTextNode and
+ // SwFrameFormat is not populated for unresolved fill bitmaps, so
+ // invalidating all content is sufficient to pick up the new data.
+ for (SwRootFrame* pLayout : m_pDoc->GetAllLayouts())
+ pLayout->InvalidateAllContent(SwInvalidateFlags::PrtArea);
+
+ return SUCCESS;
+ }
+ };
+
+ //Helper functions for this file
::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks )
{
for (const auto& rLinkIter : rLinks)
@@ -206,6 +269,21 @@ void DocumentLinksAdministrationManager::UpdateLinks()
for (SwNumRuleTable::size_type n = 0; n < m_rDoc.GetNumRuleTable().size(); ++n)
m_rDoc.GetNumRuleTable()[n]->RegisterGrfLinks(m_rDoc);

+ // Register links for fill bitmap items (e.g. style:background-image)
+ // with remote URLs. Iterates unique pool items, not per-node.
+ for (const SfxPoolItem* pItem : m_rDoc.GetAttrPool().GetItemSurrogates(XATTR_FILLBITMAP))
+ {
+ auto* pBmpItem = static_cast<const XFillBitmapItem*>(pItem);
+ const Graphic& rGrf = pBmpItem->GetGraphicObject().GetGraphic();
+ if (rGrf.GetType() != GraphicType::Default)
+ continue;
+ OUString aURL = rGrf.getOriginURL();
+ if (aURL.isEmpty())
+ continue;
+ tools::SvRef<sfx2::SvBaseLink> xLink(new SwFillBitmapLink(&m_rDoc));
+ GetLinkManager().InsertFileLink(*xLink, sfx2::SvBaseLinkObjectType::ClientGraphic, aURL);
+ }
+
if (GetLinkManager().GetLinks().empty())
return;
sal_uInt16 nLinkMode = m_rDoc.GetDocumentSettingManager().getLinkUpdateMode(true);
diff --git a/engine/sw/source/core/inc/fillattrcache.hxx b/engine/sw/source/core/inc/fillattrcache.hxx
new file mode 100644
index 000000000000..e3d9626b10fd
--- /dev/null
+++ b/engine/sw/source/core/inc/fillattrcache.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * Copyright the Collabora Office contributors.
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_SW_SOURCE_CORE_INC_FILLATTRCACHE_HXX
+#define INCLUDED_SW_SOURCE_CORE_INC_FILLATTRCACHE_HXX
+
+#include <svx/xbtmpit.hxx>
+#include <svx/xdef.hxx>
+#include <vcl/graph.hxx>
+
+class SfxItemSet;
+
+// Returns true if the fill bitmap in rSet has an unresolved remote graphic
+// (GraphicType::Default with a non-empty originURL). When true, callers
+// should not cache SdrAllFillAttributesHelper built from this set, because
+// the pool item will be replaced when link updates are allowed and the
+// cache would become stale.
+inline bool hasDeferredFillBitmap(const SfxItemSet& rSet)
+{
+ const XFillBitmapItem* pBmpItem = rSet.GetItemIfSet(XATTR_FILLBITMAP, false);
+ if (!pBmpItem)
+ return false;
+ const Graphic& rGrf = pBmpItem->GetGraphicObject().GetGraphic();
+ return rGrf.GetType() == GraphicType::Default && !rGrf.getOriginURL().isEmpty();
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/engine/sw/source/core/layout/atrfrm.cxx b/engine/sw/source/core/layout/atrfrm.cxx
index 51d9770b47bb..fe7fda738699 100644
--- a/engine/sw/source/core/layout/atrfrm.cxx
+++ b/engine/sw/source/core/layout/atrfrm.cxx
@@ -79,6 +79,7 @@
#include <unoframe.hxx>
#include <SwStyleNameMapper.hxx>
#include <editeng/brushitem.hxx>
+#include <fillattrcache.hxx>
#include <vcl/GraphicObject.hxx>
#include <unomid.h>
#include <strings.hrc>
@@ -3744,7 +3745,12 @@ drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwFrameFormat::getSdrAllF
// create FillAttributes on demand
if(!maFillAttributes)
{
- const_cast< SwFrameFormat* >(this)->maFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(GetAttrSet());
+ auto pNew = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(GetAttrSet());
+
+ if (hasDeferredFillBitmap(GetAttrSet()))
+ return pNew;
+
+ const_cast<SwFrameFormat*>(this)->maFillAttributes = std::move(pNew);
}
}
else
diff --git a/engine/sw/source/core/txtnode/ndtxt.cxx b/engine/sw/source/core/txtnode/ndtxt.cxx
index 31f4fe406c5c..fdb1d670d87e 100644
--- a/engine/sw/source/core/txtnode/ndtxt.cxx
+++ b/engine/sw/source/core/txtnode/ndtxt.cxx
@@ -29,6 +29,7 @@
#include <editeng/rsiditem.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
+#include <fillattrcache.hxx>
#include <anchoredobject.hxx>
#include <txtfld.hxx>
#include <txtinet.hxx>
@@ -5818,7 +5819,12 @@ drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwTextNode::getSdrAllFill
// create SdrAllFillAttributesHelper on demand
if(!maFillAttributes)
{
- const_cast< SwTextNode* >(this)->maFillAttributes = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(GetSwAttrSet());
+ auto pNew = std::make_shared<drawinglayer::attribute::SdrAllFillAttributesHelper>(GetSwAttrSet());
+
+ if (hasDeferredFillBitmap(GetSwAttrSet()))
+ return pNew;
+
+ const_cast<SwTextNode*>(this)->maFillAttributes = std::move(pNew);
}

return maFillAttributes;

"Caolán McNamara (via cogerrit)"

unread,
May 20, 2026, 8:53:23 AM (5 days ago) May 20
to collaboraon...@googlegroups.com
engine/sw/qa/extras/tiledrendering/data/page-background-link.fodt | 28 ++++++++++
engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx | 25 ++++++++
2 files changed, 53 insertions(+)

New commits:
commit 16d33fbb77e23d03fa16dd9e47d047ee1f6a45ff
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Thu Apr 16 07:23:54 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Wed May 20 12:52:29 2026 +0000

add a fodt page background test

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

diff --git a/engine/sw/qa/extras/tiledrendering/data/page-background-link.fodt b/engine/sw/qa/extras/tiledrendering/data/page-background-link.fodt
new file mode 100644
index 000000000000..1f4d126f7d7f
--- /dev/null
+++ b/engine/sw/qa/extras/tiledrendering/data/page-background-link.fodt
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ office:version="1.3"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties>
+ <style:background-image
+ xlink:href="http://192.0.2.1:12345/background.png"
+ xlink:type="simple" xlink:actuate="onLoad" xlink:show="embed"
+ style:position="center" style:repeat="no-repeat"/>
+ </style:page-layout-properties>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:p>Page with remote background image.</text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index 8c6273f6525f..cbb4e2f9a400 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -923,6 +923,31 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testBackgroundImageRemoteNotFetched)
}
}

+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testPageBackgroundImageRemoteNotFetched)
+{
+ // style:background-image on a page style with a remote xlink:href must
+ // not fetch the URL during paint when link updates are not allowed.
+ comphelper::COKit::setActive(false);
+
+ uno::Sequence<beans::PropertyValue> aParams = {
+ comphelper::makePropertyValue(u"UpdateDocMode"_ustr,
+ sal_Int16(css::document::UpdateDocMode::NO_UPDATE)),
+ };
+ loadWithParams(createFileURL(u"page-background-link.fodt"), aParams);
+
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+
+ pWrtShell->CalcLayout();
+
+ // render through SwViewShell::Paint - the assert in
+ // createNewSdrFillGraphicAttribute will fire if a remote fetch is attempted.
+ ScopedVclPtrInstance<VirtualDevice> pDevice(DeviceFormat::WITHOUT_ALPHA);
+ pDevice->SetOutputSizePixel(Size(1024, 1024));
+ static_cast<SwViewShell*>(pWrtShell)->Paint(
+ *pDevice, tools::Rectangle(Point(0, 0), pWrtShell->GetLayout()->getFrameArea().SSize()));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

"Parth Raiyani (via cogerrit)"

unread,
May 20, 2026, 10:05:43 AM (5 days ago) May 20
to collaboraon...@googlegroups.com
engine/sw/source/uibase/utlui/content.cxx | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

New commits:
commit e52a4fce222159478240e7e91a4b887ccce0cd20
Author: Parth Raiyani <parth....@collabora.com>
AuthorDate: Tue May 19 15:46:54 2026 +0530
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Wed May 20 14:05:05 2026 +0000

Add JSON handling for PostIt content focus in GotoContent

- issue: there was no way to reach existing comment from navigator -> Comments section using keyboard only

- this change fixes this issue by sending the json of 'Focus' type action back to online which will then be used to find the active comment and move focus on that comment

Change-Id: I30fc2baca926967bb7c5936e2981e754f8fbccc2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202617
Tested-by: Caolán McNamara <caolan....@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscoll...@gmail.com>
Reviewed-by: Caolán McNamara <caolan....@collabora.com>
Signed-off-by: Parth Raiyani <parth....@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2914

diff --git a/engine/sw/source/uibase/utlui/content.cxx b/engine/sw/source/uibase/utlui/content.cxx
index b3f836d9f5c1..2b37919c5c45 100644
--- a/engine/sw/source/uibase/utlui/content.cxx
+++ b/engine/sw/source/uibase/utlui/content.cxx
@@ -18,8 +18,10 @@
*/

#include <svx/svditer.hxx>
+#include <boost/property_tree/json_parser.hpp>
#include <comphelper/kit.hxx>
#include <comphelper/string.hxx>
+#include <COKit/COKitEnums.h>
#include <editeng/frmdiritem.hxx>
#include <svl/urlbmk.hxx>
#include <osl/thread.h>
@@ -7136,10 +7138,26 @@ void SwContentTree::GotoContent(const SwContent* pCnt)
}
break;
case ContentTypeId::POSTIT:
+ {
if (SwFormatField const*const pField{static_cast<const SwPostItContent*>(pCnt)->GetPostIt()})
{
m_pActiveShell->GotoFormatField(*pField);
+ if (comphelper::COKit::isActive())
+ {
+ const SwPostItField* pPostItField
+ = static_cast<const SwPostItField*>(pField->GetField());
+ boost::property_tree::ptree aAnnotation;
+ aAnnotation.put("action", "Focus");
+ aAnnotation.put("id", pPostItField->GetPostItId());
+ boost::property_tree::ptree aTree;
+ aTree.add_child("comment", aAnnotation);
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ m_pActiveShell->GetView().viewCallback(
+ KIT_CALLBACK_COMMENT, OString(aStream.str()));
+ }
}
+ }
break;
case ContentTypeId::DRAWOBJECT:
{

"Miklos Vajna (via cogerrit)"

unread,
May 21, 2026, 7:27:20 AM (4 days ago) May 21
to collaboraon...@googlegroups.com
engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx | 48 +++++++++++++++++
engine/sw/source/core/inc/layact.hxx | 2
engine/sw/source/core/inc/layfrm.hxx | 2
engine/sw/source/core/layout/layact.cxx | 28 +++++++--
4 files changed, 72 insertions(+), 8 deletions(-)

New commits:
commit 5b9832680358b4f23eb98c28bd206da286dc0855
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Tue May 19 16:06:41 2026 +0200
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Thu May 21 11:26:42 2026 +0000

cool#15779 engine sw, idle spellcheck: interrupt on user input

Open the 494 pages long bugdoc, wait for the first page to show up,
press ctrl-enter to insert a page break at the doc start, Writer hangs
for ~1s before inserting the page break.

What seems to happen is that we do the layout + spellcheck for the
visible area, then we start idle layout, which gets interrupted by
ctrl-enter, but idle spellcheck is not interrupted.

Fix the problem by asking comphelper::COKit::anyInput() in
SwLayIdle::DoIdleJob_(), where Application::AnyInput() was used already
and also enable the IdleLayouting flag for the duration of the idle
spellcheck in SwLayIdle::SwLayIdle(). The same was done for the idle
layout already in the past: commit
41aec3e9a088ad4e99e43e033c7653e2c25a85ba (Related: cool#9735 sw lok:
handle the AnyInput() callback during idle layout, 2024-08-15)
introduced anyInput() and commit
0a85a093fb3b4a6661d0cfd8fac92f115c65e069 (tdf#170595 sw lok, idle
layout: fast render of the 2nd page, too, 2026-03-05) introduced the
IdleLayouting flag.

Note that unlike layout, spellcheck uses SwLayIdle::DoIdleJob_() both to
check the visible area (sync) and to check the rest of the document
(async), so only ask the anyInput callback in the IdleJobArea::ALL case.

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

diff --git a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index cbb4e2f9a400..adb6e727e8f7 100644
--- a/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/engine/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -32,6 +32,8 @@

#include <com/sun/star/document/UpdateDocMode.hpp>
#include <sfx2/linkmgr.hxx>
+#include <ndtxt.hxx>
+#include <txtfrm.hxx>
#include <view.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentLinksAdministration.hxx>
@@ -783,6 +785,52 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSpellcheckVisibleArea)
CPPUNIT_ASSERT(pPage3->IsInvalidSpelling());
}

+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSpellcheckIdle)
+{
+ // Given a document with 3 pages, the first page is visible, spellcheck is only done for the
+ // visible page:
+ OUString aURL = createFileURL(u"3pages.odt");
+ UnoApiXmlTest::loadFromURL(aURL);
+ SwDocShell* pDocShell = getSwDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwRootFrame* pLayout = pWrtShell->GetLayout();
+ SwPageFrame* pPage1 = pLayout->GetLower()->DynCastPageFrame();
+ pWrtShell->setKitVisibleArea(pPage1->getFrameArea().SVRect());
+ SwPageFrame* pPage2 = pPage1->GetNext()->DynCastPageFrame();
+ SwPageFrame* pPage3 = pPage2->GetNext()->DynCastPageFrame();
+ pWrtShell->LayoutIdle();
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(!pPage1->IsInvalidSpelling());
+ CPPUNIT_ASSERT(!pPage2->IsInvalidSpelling());
+ CPPUNIT_ASSERT(!pPage3->IsInvalidSpelling());
+ for (SwPageFrame* pPage : { pPage2, pPage3 })
+ {
+ SwContentFrame* pContent = pPage->ContainsContent();
+ while (pContent && pPage->IsAnLower(pContent))
+ {
+ if (pContent->IsTextFrame())
+ {
+ SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pContent);
+ if (SwTextNode* pNode = pTextFrame->GetTextNodeFirst())
+ pNode->SetWrongDirty(sw::WrongState::TODO);
+ }
+ pContent = pContent->GetNextContentFrame();
+ }
+ pPage->InvalidateSpelling();
+ }
+ CPPUNIT_ASSERT(pPage2->IsInvalidSpelling());
+ CPPUNIT_ASSERT(pPage3->IsInvalidSpelling());
+
+ // When doing idle layout and and the anyInput callback wants to interrupt:
+ AnyInputCallback aAnyInput;
+ pWrtShell->LayoutIdle();
+
+ // Then make sure spellcheck is avoided for non-visible pages:
+ // Without the fix in place, async layout did spellcheck for all pages.
+ CPPUNIT_ASSERT(pPage2->IsInvalidSpelling());
+ CPPUNIT_ASSERT(pPage3->IsInvalidSpelling());
+}
+
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testIdleLayoutShape)
{
// Given a loaded document with a defined viewport:
diff --git a/engine/sw/source/core/inc/layact.hxx b/engine/sw/source/core/inc/layact.hxx
index f29be8bceed5..0f1e0dc8fb55 100644
--- a/engine/sw/source/core/inc/layact.hxx
+++ b/engine/sw/source/core/inc/layact.hxx
@@ -215,7 +215,7 @@ class SwLayIdle
void ShowIdle( Color eName );
#endif

- bool DoIdleJob_( const SwContentFrame*, IdleJobType );
+ bool DoIdleJob_( const SwContentFrame*, IdleJobType, IdleJobArea );
bool DoIdleJob(IdleJobType eJobType, IdleJobArea eJobArea);

static bool isJobEnabled(IdleJobType eJob, const SwViewShell* pViewShell);
diff --git a/engine/sw/source/core/inc/layfrm.hxx b/engine/sw/source/core/inc/layfrm.hxx
index b6f3d07a0d8d..1bd54be314b1 100644
--- a/engine/sw/source/core/inc/layfrm.hxx
+++ b/engine/sw/source/core/inc/layfrm.hxx
@@ -115,7 +115,7 @@ public:
*/
const SwFrame *ContainsAny( const bool _bInvestigateFootnoteForSections = false ) const;
inline SwFrame *ContainsAny( const bool _bInvestigateFootnoteForSections = false );
- bool IsAnLower( const SwFrame * ) const;
+ SW_DLLPUBLIC bool IsAnLower( const SwFrame * ) const;

virtual const SwFrameFormat *GetFormat() const;
virtual SwFrameFormat *GetFormat();
diff --git a/engine/sw/source/core/layout/layact.cxx b/engine/sw/source/core/layout/layact.cxx
index afeacea3c75d..69a75fc79854 100644
--- a/engine/sw/source/core/layout/layact.cxx
+++ b/engine/sw/source/core/layout/layact.cxx
@@ -2089,7 +2089,7 @@ void SwLayAction::FormatFlyContent( const SwFlyFrame *pFly )
CheckWaitCursor();
}

-bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
+bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob, IdleJobArea eJobArea )
{
OSL_ENSURE( pCnt->IsTextFrame(), "NoText neighbour of Text" );
// robust against misuse by e.g. #i52542#
@@ -2173,8 +2173,16 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
m_bPageValid = m_bPageValid && (sw::WrongState::TODO != pTextNode->GetWrongDirty());
if ( aRepaint.HasArea() )
m_pImp->GetShell().InvalidateWindows( aRepaint );
- if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
+ bool bInterrupt = Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER));
+ if (!bInterrupt && eJobArea == IdleJobArea::ALL)
+ {
+ // Idle spellcheck for the non-visible area: interrupt on user input.
+ bInterrupt = comphelper::COKit::anyInput();
+ }
+ if (bInterrupt)
+ {
return true;
+ }
break;
}
case IdleJobType::AUTOCOMPLETE_WORDS:
@@ -2226,7 +2234,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
{
if ( pC->IsTextFrame() )
{
- if ( DoIdleJob_( pC, eJob ) )
+ if ( DoIdleJob_( pC, eJob, eJobArea ) )
return true;
}
pC = pC->GetNextContentFrame();
@@ -2301,7 +2309,7 @@ bool SwLayIdle::DoIdleJob(IdleJobType eJob, IdleJobArea eJobArea)
const SwContentFrame* pContentFrame = pPage->ContainsContent();
while (pContentFrame && pPage->IsAnLower(pContentFrame))
{
- if (DoIdleJob_(pContentFrame, eJob))
+ if (DoIdleJob_(pContentFrame, eJob, eJobArea))
{
SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
return true;
@@ -2321,7 +2329,7 @@ bool SwLayIdle::DoIdleJob(IdleJobType eJob, IdleJobArea eJobArea)
{
if ( pC->IsTextFrame() )
{
- if ( DoIdleJob_( pC, eJob ) )
+ if ( DoIdleJob_( pC, eJob, eJobArea ) )
{
SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
return true;
@@ -2551,8 +2559,16 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
{
if (!DoIdleJob(IdleJobType::WORD_COUNT, IdleJobArea::ALL))
if (!DoIdleJob(IdleJobType::SMART_TAGS, IdleJobArea::ALL))
- if (!DoIdleJob(IdleJobType::ONLINE_SPELLING, IdleJobArea::ALL))
+ {
+ // Let the COKit anyInput() mechanism know that we're inside the idle spellcheck.
+ comphelper::COKit::setIdleLayouting(true);
+ bool bRet = DoIdleJob(IdleJobType::ONLINE_SPELLING, IdleJobArea::ALL);
+ comphelper::COKit::setIdleLayouting(false);
+ if (!bRet)
+ {
DoIdleJob(IdleJobType::AUTOCOMPLETE_WORDS, IdleJobArea::ALL);
+ }
+ }
}

bool bInValid = false;

"Karthik (via cogerrit)"

unread,
May 21, 2026, 11:26:05 AM (4 days ago) May 21
to collaboraon...@googlegroups.com
engine/sw/qa/extras/layout/data/inline-textbox-position.docx |binary
engine/sw/qa/extras/layout/layout6.cxx | 21 +++++++++
engine/sw/source/core/doc/textboxhelper.cxx | 25 +++++++++--
3 files changed, 42 insertions(+), 4 deletions(-)

New commits:
commit 3d53aa0e171e72274831278234648f11641b55fe
Author: Karthik <karthi...@collabora.com>
AuthorDate: Wed May 13 09:47:53 2026 +0530
Commit: Michael Stahl <michae...@collabora.com>
CommitDate: Thu May 21 15:25:28 2026 +0000

sw: Fix positioning of inline text-boxes

This is a regression from 0d29394598db2e336a9982cbb7041ea407b2bf6d
(https://gerrit.libreoffice.org/c/core/+/129627).

Word text-boxes are imported as dual-frame (SwFlyFrame inside a
SdrObject), for inline text-boxes the text (SwFlyFrame) is positioned
incorrectly.

While addressing a different problem the commit
0d29394598db2e336a9982cbb7041ea407b2bf6d changed how inline text-boxes
are positioned. Because of this there is a mismatch b/w the position of
shape (SdrObject) and text (SwFlyFrame) inside the shape.

SwFlyFrame should be positioned based on the SdrObject's position in
the document.

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

diff --git a/engine/sw/qa/extras/layout/data/inline-textbox-position.docx b/engine/sw/qa/extras/layout/data/inline-textbox-position.docx
new file mode 100644
index 000000000000..c9863c9d3c01
Binary files /dev/null and b/engine/sw/qa/extras/layout/data/inline-textbox-position.docx differ
diff --git a/engine/sw/qa/extras/layout/layout6.cxx b/engine/sw/qa/extras/layout/layout6.cxx
index cdeb6c123c0f..b64354c1bce4 100644
--- a/engine/sw/qa/extras/layout/layout6.cxx
+++ b/engine/sw/qa/extras/layout/layout6.cxx
@@ -2232,6 +2232,27 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf169999)
}
}

+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testInlineTextBoxPosition)
+{
+ createSwDoc("inline-textbox-position.docx");
+
+ xmlDocUniquePtr pLayoutDump = parseLayoutDump();
+ CPPUNIT_ASSERT(pLayoutDump);
+
+ const sal_Int32 nShortShapeTop
+ = getXPath(pLayoutDump,
+ "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
+ .toInt32();
+ const sal_Int32 nShortFlyTop
+ = getXPath(pLayoutDump,
+ "/root/page/body/txt/anchored/fly[1]/infos/bounds", "top")
+ .toInt32();
+
+ // Without the fix ShortBox's fly landed at the anchor paragraph's
+ // print-area top while its SdrObject sat below it. The two must coincide.
+ CPPUNIT_ASSERT_EQUAL(nShortShapeTop, nShortFlyTop);
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170846_1)
{
// In this document, the whole floating table must move to page 2
diff --git a/engine/sw/source/core/doc/textboxhelper.cxx b/engine/sw/source/core/doc/textboxhelper.cxx
index 23d316a11b3d..fd396050847b 100644
--- a/engine/sw/source/core/doc/textboxhelper.cxx
+++ b/engine/sw/source/core/doc/textboxhelper.cxx
@@ -8,7 +8,9 @@
*/

#include <textboxhelper.hxx>
+#include <anchoredobject.hxx>
#include <dcontact.hxx>
+#include <frame.hxx>
#include <fmtcntnt.hxx>
#include <fmtanchr.hxx>
#include <fmtcnct.hxx>
@@ -1408,10 +1410,25 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb
}
else
{
- // Simple textboxes: vertical position equals to the vertical offset of the shape
- aNewVOri.SetPos(
- ((pShape->GetVertOrient().GetPos()) > 0 ? pShape->GetVertOrient().GetPos() : 0)
- + aRect.Top());
+ SdrObject* pRealObj = pObj ? pObj : pShape->FindRealSdrObject();
+ const tools::Rectangle aSnapRect(pRealObj->GetSnapRect());
+
+ // Simple textboxes: place the textframe at the shape's actual
+ // laid-out text-area top, expressed relative to the anchor
+ // paragraph's print area.
+ SwTwips nPrintAreaAbsTop = 0;
+ if (auto* pContact = dynamic_cast<SwContact*>(pRealObj->GetUserCall()))
+ {
+ if (const SwAnchoredObject* pAnchObj = pContact->GetAnchoredObj(pRealObj))
+ {
+ if (const SwFrame* pAnchorFrame = pAnchObj->GetAnchorFrame())
+ {
+ nPrintAreaAbsTop = pAnchorFrame->getFrameArea().Top()
+ + pAnchorFrame->getFramePrintArea().Top();
+ }
+ }
+ }
+ aNewVOri.SetPos(aSnapRect.Top() + aRect.Top() - nPrintAreaAbsTop);
}

// Special cases when the shape is aligned to the line

"Karthik (via cogerrit)"

unread,
May 21, 2026, 6:13:12 PM (4 days ago) May 21
to collaboraon...@googlegroups.com
engine/sw/qa/extras/layout/data/toc-inline-heading-order.fodt | 99 ++++++++++
engine/sw/qa/extras/layout/layout6.cxx | 16 +
engine/sw/source/core/inc/txmsrt.hxx | 1
engine/sw/source/core/tox/txmsrt.cxx | 18 +
engine/sw/source/uibase/utlui/content.cxx | 21 +-
5 files changed, 150 insertions(+), 5 deletions(-)

New commits:
commit 745330e2d6f8c31193bdd10ba7e039a2aba6d6a8
Author: Karthik <karthi...@collabora.com>
AuthorDate: Thu May 14 16:00:56 2026 +0530
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Thu May 21 22:12:23 2026 +0000

sw: Inline headings produce incorrect order in TOC

Inline headings are stored as flys anchored at the start of the
paragraph.

`SwTOXSortTabBase::sort_lt` is responsible for sorting the content of
Table of Contents. Inline headings are not properly handled, which
results in incorrect ordering of outline elements in TOC.

Navigation panel also suffers with the same problem, where fly nodes
are always assumed to render after the anchor paragraph. Handle as-char
fly nodes which are positioned at the start of the anchor paragraph.

Change-Id: Id3339b85fbae7731cfc5620477def1057ca15e31
Signed-off-by: Karthik <karthi...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2596
Reviewed-by: Caolán McNamara <caolan....@collabora.com>
Tested-by: Caolán McNamara <caolan....@collabora.com>

diff --git a/engine/sw/qa/extras/layout/data/toc-inline-heading-order.fodt b/engine/sw/qa/extras/layout/data/toc-inline-heading-order.fodt
new file mode 100644
index 000000000000..d5fa5a9dbacf
--- /dev/null
+++ b/engine/sw/qa/extras/layout/data/toc-inline-heading-order.fodt
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+ xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
+ office:version="1.4"
+ office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'"/>
+ <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+ <style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard"
+ style:next-style-name="Standard" style:class="chapter">
+ <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm"
+ style:contextual-spacing="false" fo:keep-with-next="always"/>
+ <style:text-properties style:font-name="Liberation Sans" fo:font-size="14pt"/>
+ </style:style>
+ <style:style style:name="Heading_20_1" style:display-name="Heading 1" style:family="paragraph"
+ style:parent-style-name="Heading" style:default-outline-level="1" style:class="chapter">
+ <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm"
+ style:contextual-spacing="false"/>
+ <style:text-properties fo:font-size="18pt" fo:font-weight="bold"/>
+ </style:style>
+ <style:style style:name="Heading_20_2" style:display-name="Heading 2" style:family="paragraph"
+ style:parent-style-name="Heading" style:default-outline-level="2" style:class="chapter">
+ <style:paragraph-properties fo:margin-top="0.353cm" fo:margin-bottom="0.212cm"
+ style:contextual-spacing="false"/>
+ <style:text-properties fo:font-size="16pt" fo:font-weight="bold"/>
+ </style:style>
+ <style:style style:name="Contents_20_1" style:display-name="Contents 1" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="index"/>
+ <style:style style:name="Contents_20_2" style:display-name="Contents 2" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="index"/>
+ <style:style style:name="Contents_20_Heading" style:display-name="Contents Heading"
+ style:family="paragraph" style:parent-style-name="Heading" style:class="index">
+ <style:text-properties fo:font-size="16pt" fo:font-weight="bold"/>
+ </style:style>
+ <style:style style:name="Index_20_Link" style:display-name="Index Link" style:family="text"/>
+ <style:style style:name="Inline_20_Heading" style:display-name="Inline Heading" style:family="graphic">
+ <style:graphic-properties text:anchor-type="as-char"
+ svg:y="0cm" fo:margin-left="0cm" fo:margin-right="0cm"
+ style:vertical-pos="middle" style:vertical-rel="text"
+ fo:background-color="transparent" draw:fill="none"/>
+ </style:style>
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Heading_20_1">
+ <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
+ </style:style>
+ <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Inline_20_Heading">
+ <style:graphic-properties style:vertical-pos="middle" style:vertical-rel="text"/>
+ </style:style>
+ <style:style style:name="Sect1" style:family="section">
+ <style:section-properties>
+ <style:columns fo:column-count="1" fo:column-gap="0cm"/>
+ </style:section-properties>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21cm" fo:page-height="29.7cm"
+ fo:margin-top="2cm" fo:margin-bottom="2cm"
+ fo:margin-left="2cm" fo:margin-right="2cm"/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:h text:style-name="Heading_20_1" text:outline-level="1">Foo</text:h>
+ <text:h text:style-name="Heading_20_2" text:outline-level="2"><draw:frame draw:style-name="fr1" draw:name="Frame1" text:anchor-type="as-char" draw:z-index="0"><draw:text-box><text:h text:style-name="P1" text:outline-level="1">Bar</text:h></draw:text-box></draw:frame> boo</text:h>
+ <text:table-of-content text:style-name="Sect1" text:protected="true" text:name="TOC1">
+ <text:table-of-content-source text:outline-level="10">
+ <text:index-title-template text:style-name="Contents_20_Heading">Table of Contents</text:index-title-template>
+ <text:table-of-content-entry-template text:outline-level="1" text:style-name="Contents_20_1">
+ <text:index-entry-link-start text:style-name="Index_20_Link"/>
+ <text:index-entry-text/>
+ <text:index-entry-link-end/>
+ </text:table-of-content-entry-template>
+ <text:table-of-content-entry-template text:outline-level="2" text:style-name="Contents_20_2">
+ <text:index-entry-link-start text:style-name="Index_20_Link"/>
+ <text:index-entry-text/>
+ <text:index-entry-link-end/>
+ </text:table-of-content-entry-template>
+ </text:table-of-content-source>
+ <text:index-body>
+ <text:index-title text:style-name="Sect1" text:name="TOC1_Head">
+ <text:p text:style-name="Contents_20_Heading">Table of Contents</text:p>
+ </text:index-title>
+ </text:index-body>
+ </text:table-of-content>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/engine/sw/qa/extras/layout/layout6.cxx b/engine/sw/qa/extras/layout/layout6.cxx
index b64354c1bce4..e9d29884e501 100644
--- a/engine/sw/qa/extras/layout/layout6.cxx
+++ b/engine/sw/qa/extras/layout/layout6.cxx
@@ -2273,6 +2273,22 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170846_2)
assertXPath(pXmlDoc, "//page[2]//tab", 3); // Three tables on page 2
}

+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTocInlineHeadingOrder)
+{
+ createSwDoc("toc-inline-heading-order.fodt");
+ dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // The TOC is the second section in the body. The body section's three
+ // txt children carry the entries in document order.
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout",
+ "portion", u"Foo");
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/SwParaPortion/SwLineLayout",
+ "portion", u"Bar");
+ assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/SwParaPortion/SwLineLayout",
+ "portion", u" boo");
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testInlineTableShiftDown)
{
createSwDoc("floattable-center-shift-down.docx");
diff --git a/engine/sw/source/core/inc/txmsrt.hxx b/engine/sw/source/core/inc/txmsrt.hxx
index 0643cd5f05db..6239620b859c 100644
--- a/engine/sw/source/core/inc/txmsrt.hxx
+++ b/engine/sw/source/core/inc/txmsrt.hxx
@@ -162,6 +162,7 @@ struct SwTOXSortTabBase

private:
bool m_bValidText;
+ bool m_bAnchoredAsChar; // used by SwTOXSortTabBase::sort_lt to break ties
TextAndReading m_aSort;

virtual TextAndReading GetText_Impl(SwRootFrame const* pLayout) const = 0;
diff --git a/engine/sw/source/core/tox/txmsrt.cxx b/engine/sw/source/core/tox/txmsrt.cxx
index 5cb92b4e3816..6d24677a2482 100644
--- a/engine/sw/source/core/tox/txmsrt.cxx
+++ b/engine/sw/source/core/tox/txmsrt.cxx
@@ -36,6 +36,7 @@
#include <pam.hxx>
#include <txttxmrk.hxx>
#include <frmfmt.hxx>
+#include <fmtanchr.hxx>
#include <fmtfld.hxx>
#include <txmsrt.hxx>
#include <ndtxt.hxx>
@@ -139,6 +140,7 @@ SwTOXSortTabBase::SwTOXSortTabBase( TOXSortType nTyp, const SwContentNode* pNd,
: pTOXNd( nullptr ), pTextMark( pMark ), pTOXIntl( pInter ),
nPos( 0 ), nCntPos( 0 ), nType( o3tl::narrowing<sal_uInt16>(nTyp) )
, m_bValidText( false )
+ , m_bAnchoredAsChar( false )
{
if ( pLocale )
aLocale = *pLocale;
@@ -177,6 +179,10 @@ SwTOXSortTabBase::SwTOXSortTabBase( TOXSortType nTyp, const SwContentNode* pNd,
OSL_ENSURE(bResult, "where is the text node");
nPos = aPos.GetNodeIndex();
nCntPos = aPos.GetContentIndex();
+
+ const SwFrameFormat* pFlyFormat = pNd->GetFlyFormat();
+ if (pFlyFormat && pFlyFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+ m_bAnchoredAsChar = true;
}
}
else
@@ -291,8 +297,16 @@ bool SwTOXSortTabBase::sort_lt(const SwTOXSortTabBase& rCmp)
}
else if( pFirst && pFirst->IsTextNode() &&
pNext && pNext->IsTextNode() )
- return ::IsFrameBehind( *static_cast<const SwTextNode*>(pNext), nCntPos,
- *static_cast<const SwTextNode*>(pFirst), nCntPos );
+ {
+ // An inline (as-char) anchored fly's content is rendered
+ // at its anchor character position. If the character offset is same
+ // then the inline fly is rendered before the paragraph.
+ if (m_bAnchoredAsChar != rCmp.m_bAnchoredAsChar)
+ return m_bAnchoredAsChar;
+
+ return ::IsFrameBehind(*static_cast<const SwTextNode*>(pNext), nCntPos,
+ *static_cast<const SwTextNode*>(pFirst), nCntPos);
+ }
}
}
return false;
diff --git a/engine/sw/source/uibase/utlui/content.cxx b/engine/sw/source/uibase/utlui/content.cxx
index 2b37919c5c45..1a61173592af 100644
--- a/engine/sw/source/uibase/utlui/content.cxx
+++ b/engine/sw/source/uibase/utlui/content.cxx
@@ -579,10 +579,25 @@ void SwContentType::FillMemberList(bool* pbContentChanged)
if (nLevel >= m_nOutlineLevel)
continue;
double nYPos = m_bAlphabeticSort ? 0 : static_cast<double>(getYPos(*pNode));
- if (nEndOfExtrasIndex >= pNode->GetIndex() && pNode->GetFlyFormat())
+ const SwFrameFormat* pFlyFormat = pNode->GetFlyFormat();
+ if (nEndOfExtrasIndex >= pNode->GetIndex() && pFlyFormat)
{
- nYPos += nOutlinesInFramesIndexAdjustment;
- nOutlinesInFramesIndexAdjustment += 0.00001;
+ // For fly nodes getYPos() returns their anchor node's nYPos
+ const SwFormatAnchor& rAnchor = pFlyFormat->GetAnchor();
+ const SwPosition* pAnchorPos = rAnchor.GetContentAnchor();
+ if (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR && pAnchorPos
+ && pAnchorPos->GetContentIndex() == 0)
+ {
+ // An inline (as-char) fly anchored at the start of its
+ // anchor paragraph renders before the paragraph's own
+ // text. Place its outline entry before the anchor's nYPos.
+ nYPos -= 0.0001;
+ }
+ else
+ {
+ nYPos += nOutlinesInFramesIndexAdjustment;
+ nOutlinesInFramesIndexAdjustment += 0.00001;
+ }
}

auto pCnt(std::make_unique<SwOutlineContent>(this, aEntry, i, nLevel,

"Jaume Pujantell (via cogerrit)"

unread,
May 22, 2026, 3:49:59 AM (4 days ago) May 22
to collaboraon...@googlegroups.com
engine/sw/qa/extras/uiwriter/uiwriter11.cxx | 22 ++++++++++++++++++++++
engine/sw/source/core/edit/acorrect.cxx | 4 ++--
2 files changed, 24 insertions(+), 2 deletions(-)

New commits:
commit 729809a69558a567afb3333db458220cf5d44814
Author: Jaume Pujantell <jaume.p...@collabora.com>
AuthorDate: Thu May 21 09:35:00 2026 +0000
Commit: Miklos Vajna <vmi...@collabora.com>
CommitDate: Fri May 22 07:49:06 2026 +0000

sw: don't skip word autocorrect on insert redlines

ChgAutoCorrWord checked for any redline crossing the word boundary,
which silently skipped the replacement whenever just-typed text (a
tracked insertion under change tracking) extended past the word
being autocorrected. Narrow the check to tracked deletions, matching
what ReplaceRange already does for the single-character path. The
tdf#130546 guard this is derived from was specifically about text inside
a deletion.

Signed-off-by: Jaume Pujantell <jaume.p...@collabora.com>
Change-Id: I7ad7f0319ea74bccf2d7e5acc5d7a991029f632e
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/3039
Reviewed-by: Miklos Vajna <vmi...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
index 9c52b9c5a6ff..aaa2fdfdb9e1 100644
--- a/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/engine/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -32,6 +32,7 @@
#include <unotxdoc.hxx>
#include <ndtxt.hxx>
#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
#include <svx/svxids.hrc>

namespace
@@ -623,6 +624,27 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testResolveCommentThreadPartiallyResolved
CPPUNIT_ASSERT(pReply->GetResolved());
}

+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testRedlineAutoCorrectInsertOverlap)
+{
+ createSwDoc();
+ SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+ CPPUNIT_ASSERT(pWrtShell);
+
+ emulateTyping(u"tset");
+
+ RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
+ pWrtShell->SetRedlineFlags(nMode);
+ CPPUNIT_ASSERT(getSwDoc()->getIDocumentRedlineAccess().IsRedlineOn());
+
+ // The trailing space is a tracked insertion adjacent to the autocorrect
+ // word "tset". The replacement "tset" -> "test" must still fire.
+ emulateTyping(u" ");
+
+ // NOTE: whether the autocorrect replacement itself should be recorded
+ // as a tracked change is an open question.
+ CPPUNIT_ASSERT_EQUAL(u"tsettest "_ustr, getParagraph(1)->getString());
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

diff --git a/engine/sw/source/core/edit/acorrect.cxx b/engine/sw/source/core/edit/acorrect.cxx
index 33566e8b6b65..e6b5c65ea9b1 100644
--- a/engine/sw/source/core/edit/acorrect.cxx
+++ b/engine/sw/source/core/edit/acorrect.cxx
@@ -414,8 +414,8 @@ bool SwAutoCorrDoc::ChgAutoCorrWord( sal_Int32& rSttPos, sal_Int32 nEndPos,
SwPosition aEndPos( pFrame->MapViewToModelPos(TextFrameIndex(nEndPos + (replaceLastChar ? 1 : 0))) );
SwPaM aPam(aStartPos, aEndPos);

- // don't replace, if a redline starts or ends within the original text
- if ( pDoc->getIDocumentRedlineAccess().HasRedline( aPam, RedlineType::Any, /*bStartOrEndInRange=*/true ) )
+ // don't replace, if a tracked deletion starts or ends within the original text
+ if ( pDoc->getIDocumentRedlineAccess().HasRedline( aPam, RedlineType::Delete, /*bStartOrEndInRange=*/true ) )
{
return bRet;
}

"Miklos Vajna (via cogerrit)"

unread,
May 22, 2026, 6:35:13 AM (3 days ago) May 22
to collaboraon...@googlegroups.com
engine/sw/source/core/layout/layact.cxx | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)

New commits:
commit a18142deb9227255f657b77a2606708f7c195b7d
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Thu May 21 13:27:01 2026 +0200
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Fri May 22 10:34:37 2026 +0000

engine sw: clean up a pair of comphelper::COKit::isActive()s in SwLayIdle

As suggested at
<https://gerrit.collaboraoffice.com/c/online/+/2884/2#message-01e0a2fecce228aa710e89b2d1a885566256dddd>,
it was inconsistent that the idle layout changed its comphelper "in
idle" flag only in the comphelper::COKit::isActive() case, but the idle
spellcheck did that unconditionally.

Fix the inconsistency by dropping the isActive() check also for the idle
layout, since in practice that flag is always true for both COOL and
CODA.

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

diff --git a/engine/sw/source/core/layout/layact.cxx b/engine/sw/source/core/layout/layact.cxx
index 69a75fc79854..d1a65c873a8e 100644
--- a/engine/sw/source/core/layout/layact.cxx
+++ b/engine/sw/source/core/layout/layact.cxx
@@ -2453,18 +2453,12 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
bSdrModelIdle = pSdrModel->IsWriterIdle();
pSdrModel->SetWriterIdle(true);
}
- if (comphelper::COKit::isActive())
- {
- // Let the COKit anyInput() mechanism know that we're inside the idle layout.
- comphelper::COKit::setIdleLayouting(true);
- }
+ // Let the COKit anyInput() mechanism know that we're inside the idle layout.
+ comphelper::COKit::setIdleLayouting(true);

aAction.Action(m_pImp->GetShell().GetOut());

- if (comphelper::COKit::isActive())
- {
- comphelper::COKit::setIdleLayouting(false);
- }
+ comphelper::COKit::setIdleLayouting(false);
if (pSdrModel)
{
pSdrModel->SetWriterIdle(bSdrModelIdle);

"Ujjawal Kumar (via cogerrit)"

unread,
May 22, 2026, 6:51:04 AM (3 days ago) May 22
to collaboraon...@googlegroups.com
engine/sw/qa/filter/md/md.cxx | 16 ++++++++++++++++
engine/sw/source/filter/md/swmd.cxx | 16 +++++++++++++---
engine/sw/source/filter/md/swmd.hxx | 2 ++
engine/sw/source/uibase/dochdl/swdtflvr.cxx | 7 ++++---
4 files changed, 35 insertions(+), 6 deletions(-)

New commits:
commit a0878c24dbc868c5ffb2d679bfb683f787d86fb6
Author: Ujjawal Kumar <ujjawal.ku...@collabora.com>
AuthorDate: Tue May 19 23:13:26 2026 +0530
Commit: Michael Stahl <michae...@collabora.com>
CommitDate: Fri May 22 10:50:21 2026 +0000

tdf#172084 Don't detect encoding when pasting markdown

Explicitly use UCS2 encoding when pasting data because
TransferableDataHelper.GetString already offers endianess
aware utf16 data. Thus removing the need for detecting
encoding.

Pasting as markdown was producing gibberish text because when
pasting ctl content like "שלום" the clipboard data doesn't include
the bom due to which the heuristic detection of the data was producing
inverted endianess for the data stream due to the data being short.
For my system it was LE -> BE.

Signed-off-by: Ujjawal Kumar <ujjawal.ku...@collabora.com>
Change-Id: I9c41610fe070c794ab0764e320305ad1d56e7440
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2956
Reviewed-by: Caolán McNamara <caolan....@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 60ee4e738458..8f2808e757ba 100644
--- a/engine/sw/qa/filter/md/md.cxx
+++ b/engine/sw/qa/filter/md/md.cxx
@@ -1034,6 +1034,22 @@ CPPUNIT_TEST_FIXTURE(Test, testPaste)
CPPUNIT_ASSERT_EQUAL(aABottom, aList2Bottom);
}

+CPPUNIT_TEST_FIXTURE(Test, testCTLPaste)
+{
+ createSwDoc();
+ SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
+ xTransferable->CopyString(SotClipboardFormatId::MARKDOWN, u"שלום"_ustr);
+ TransferableDataHelper aHelper(xTransferable);
+ SwTransferable::PasteFormat(*pWrtShell, aHelper, SotClipboardFormatId::MARKDOWN);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: שלום
+ // - Actual : some gibberish value at beginning + ?픅?
+ CPPUNIT_ASSERT_EQUAL(u"שלום"_ustr, getParagraph(1)->getString());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/engine/sw/source/filter/md/swmd.cxx b/engine/sw/source/filter/md/swmd.cxx
index 31d7a915dda5..ec6b08f2f755 100644
--- a/engine/sw/source/filter/md/swmd.cxx
+++ b/engine/sw/source/filter/md/swmd.cxx
@@ -761,6 +761,8 @@ void SwMarkdownParser::RegisterTable(MDTable* pTable) { m_aTables.push_back(pTab

void SwMarkdownParser::DeRegisterTable(MDTable* pTable) { std::erase(m_aTables, pTable); }

+void SwMarkdownParser::SetSrcEncoding(rtl_TextEncoding eSrcEnc) { m_eSrcEnc = eSrcEnc; }
+
SwMarkdownParser::SwMarkdownParser(SwDoc& rD, SwPaM& rCursor, SvStream& rIn, OUString aBaseURL,
bool bReadNewDoc)
: m_xDoc(&rD)
@@ -874,6 +876,10 @@ ErrCodeMsg MarkdownReader::Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rP
}

SwMarkdownParser parser(rDoc, rPam, *m_pStream, rBaseURL, !m_bInsertMode);
+ const rtl_TextEncoding eSrcEnc = m_aOption.GetASCIIOpts().GetCharSet();
+ parser.SetSrcEncoding(eSrcEnc);
+ comphelper::ScopeGuard guard([this] { m_aOption.ResetASCIIOpts(); });
+
if (pNumRuleItem)
{
parser.SetNumRuleItem(pNumRuleItem);
@@ -891,11 +897,15 @@ ErrCodeMsg MarkdownReader::Read(SwDoc& rDoc, const OUString& rBaseURL, SwPaM& rP
ErrCode SwMarkdownParser::CallParser()
{
// use utf8
- m_rInput.DetectEncoding();
- const rtl_TextEncoding eSrcEnc = m_rInput.GetStreamEncoding();
+ rtl_TextEncoding eSrcEnc = m_eSrcEnc;
if (eSrcEnc == RTL_TEXTENCODING_DONTKNOW)
{
- return ERRCODE_IO_INVALIDCHAR;
+ m_rInput.DetectEncoding();
+ eSrcEnc = m_rInput.GetStreamEncoding();
+ if (eSrcEnc == RTL_TEXTENCODING_DONTKNOW)
+ {
+ return ERRCODE_IO_INVALIDCHAR;
+ }
}

const sal_uInt64 nFilesize = m_rInput.remainingSize();
diff --git a/engine/sw/source/filter/md/swmd.hxx b/engine/sw/source/filter/md/swmd.hxx
index dad2825aaf99..c3221f6f8e1f 100644
--- a/engine/sw/source/filter/md/swmd.hxx
+++ b/engine/sw/source/filter/md/swmd.hxx
@@ -91,6 +91,7 @@ class SwMarkdownParser

sal_Int32 m_nBlockQuoteDepth = -1;
sal_uInt64 m_nProgress = 0;
+ rtl_TextEncoding m_eSrcEnc = RTL_TEXTENCODING_DONTKNOW;

bool m_bNewDoc;
bool m_bNoParSpace = true;
@@ -156,6 +157,7 @@ class SwMarkdownParser
public:
void RegisterTable(MDTable* pTable);
void DeRegisterTable(MDTable* pTable);
+ void SetSrcEncoding(rtl_TextEncoding eSrcEnc);

public:
SwMarkdownParser(SwDoc& rD, SwPaM& rCursor, SvStream& rIn, OUString aBaseURL, bool bReadNewDoc);
diff --git a/engine/sw/source/uibase/dochdl/swdtflvr.cxx b/engine/sw/source/uibase/dochdl/swdtflvr.cxx
index ae3bd0ec3b28..abbd9889473c 100644
--- a/engine/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/engine/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -2248,14 +2248,15 @@ bool SwTransferable::PasteFileContent( const TransferableDataHelper& rData,
}

pRead = ReadAscii;
- SwAsciiOptions aAOpt;
- aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
- pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
}
else
{
pRead = ReadMarkdown;
}
+
+ SwAsciiOptions aAOpt;
+ aAOpt.SetCharSet( RTL_TEXTENCODING_UCS2 );
+ pRead->GetReaderOpt().SetASCIIOpts( aAOpt );
}
}


"Miklos Vajna (via cogerrit)"

unread,
May 22, 2026, 7:03:45 AM (3 days ago) May 22
to collaboraon...@googlegroups.com
engine/sw/qa/uitest/fieldDialog/tdf145062.py | 2 ++
1 file changed, 2 insertions(+)

New commits:
commit 11a848dc6a576e1ff7d4fb9bae3c305986b4f332
Author: Miklos Vajna <vmi...@collabora.com>
AuthorDate: Thu May 21 13:39:31 2026 +0200
Commit: Noel Grandin <noel.g...@collabora.com>
CommitDate: Fri May 22 11:02:46 2026 +0000

UITest_sw_fieldDialog: disable broken test_tdf145062

This started to fail at commit 3e1c54967bdda59acdda86c6298b1051e7719a5f
(sw: make Review Fields (input field) dialog async and a JSDialog,
2026-05-20), disable it so we'll notice if other uichecks fail.

Signed-off-by: Miklos Vajna <vmi...@collabora.com>
Change-Id: I4dbb338e194fe759021e82442b0036c73c93aae5
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/3060
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>
Reviewed-by: Noel Grandin <noel.g...@collabora.com>

diff --git a/engine/sw/qa/uitest/fieldDialog/tdf145062.py b/engine/sw/qa/uitest/fieldDialog/tdf145062.py
index 358f650f92f8..48d8a3938747 100644
--- a/engine/sw/qa/uitest/fieldDialog/tdf145062.py
+++ b/engine/sw/qa/uitest/fieldDialog/tdf145062.py
@@ -15,6 +15,8 @@ from uitest.uihelper.common import select_pos
class Tdf145062(UITestCase):

def test_tdf145062(self):
+ # FIXME: convert to cypress that works with async dialogs better
+ return

with self.ui_test.create_doc_in_start_center("writer") as writer_doc:


"Karthik (via cogerrit)"

unread,
May 22, 2026, 9:05:03 AM (3 days ago) May 22
to collaboraon...@googlegroups.com
engine/sw/source/ui/fldui/flddok.cxx | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)

New commits:
commit 32017444efd5db64a9aeed99f65acd896fc1947f
Author: Karthik <karthi...@collabora.com>
AuthorDate: Tue May 19 14:37:03 2026 +0530
Commit: Michael Stahl <michae...@collabora.com>
CommitDate: Fri May 22 13:04:14 2026 +0000

sw: Hide Prev/Next page fields in non ODF formats

Word doesn't have Prev/Next page fields feature, disable it in UI while
working on non ODF formats.

Change-Id: I5a23baea7d521bd549343449cbf9ba55578aea2c
Signed-off-by: Karthik <karthi...@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2894
Reviewed-by: Michael Stahl <michae...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/source/ui/fldui/flddok.cxx b/engine/sw/source/ui/fldui/flddok.cxx
index e22543cd65ea..03e637336903 100644
--- a/engine/sw/source/ui/fldui/flddok.cxx
+++ b/engine/sw/source/ui/fldui/flddok.cxx
@@ -25,6 +25,8 @@
#include <swmodule.hxx>
#include <wrtsh.hxx>
#include <comphelper/kit.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
#include <svl/numformat.hxx>
#include <svl/zformat.hxx>
#include <o3tl/string_view.hxx>
@@ -32,6 +34,23 @@
#define USER_DATA_VERSION_1 "1"
#define USER_DATA_VERSION USER_DATA_VERSION_1

+namespace
+{
+bool isOwnFormat()
+{
+ if (const SwDocShell* pDocShell = dynamic_cast<SwDocShell*>(SfxObjectShell::Current()))
+ {
+ if (const SfxMedium* pMedium = pDocShell->GetMedium())
+ {
+ if (const std::shared_ptr<const SfxFilter>& pFilter = pMedium->GetFilter())
+ return pFilter->IsOwnFormat();
+ }
+ }
+
+ return true;
+}
+}
+
SwFieldDokPage::SwFieldDokPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet)
: SwFieldPage(pPage, pController, u"modules/swriter/ui/flddocumentpage.ui"_ustr,
u"FieldDocumentPage"_ustr, pCoreSet)
@@ -289,10 +308,14 @@ IMPL_LINK_NOARG(SwFieldDokPage, TypeHdl, weld::TreeView&, void)
else
{
AddSubType(SwFieldTypesEnum::PageNumber);
- AddSubType(SwFieldTypesEnum::PreviousPage);
- AddSubType(SwFieldTypesEnum::NextPage);
+ nCount = 1;
+ if (isOwnFormat())
+ {
+ AddSubType(SwFieldTypesEnum::PreviousPage);
+ AddSubType(SwFieldTypesEnum::NextPage);
+ nCount = 3;
+ }
nTypeId = static_cast<SwFieldTypesEnum>(m_xSelectionLB->get_id(0).toUInt32());
- nCount = 3;
m_xSelectionLB->connect_selection_changed(LINK(this, SwFieldDokPage, SubTypeHdl));
}


"Caolán McNamara (via cogerrit)"

unread,
May 24, 2026, 5:05:01 AM (yesterday) May 24
to collaboraon...@googlegroups.com
engine/sw/source/filter/xml/xmltble.cxx | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

New commits:
commit 43f4db8327999c085768abc199b41ddb0c94be3f
Author: Caolán McNamara <caolan....@collabora.com>
AuthorDate: Fri May 22 12:37:40 2026 +0000
Commit: Caolán McNamara <caolan....@collabora.com>
CommitDate: Sun May 24 09:04:15 2026 +0000

crashtesting: deduplicate maTableNodes to avoid duplicate auto-styles in ODF

Six docx-to-odt files in crashtesting assert in
XMLTextParagraphExport::RecordNodeIndex since:

commit 801debfc365b4c5e6bf63324aaef82f449ddb443
Date: Mon Jun 16 12:37:30 2025 +0500

tdf#167033: allow double processing of Writer shapes' text frame nodes

It turns out, that these are naturally processed twice.

with callstack of:

collectAutoStyles -> exportTable ->
CollectTableLinesAutoStyles -> exportText (cell) ->
exportTextContentEnumeration -> RecordNodeIndex.

fdo74357-1.docx
tdf119800-1.docx
forum-mso-en-18694.docx
forum-mso-de-60423.docx
forum-mso-de-139649.docx
forum-mso-en4-152181.docx

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

diff --git a/engine/sw/source/filter/xml/xmltble.cxx b/engine/sw/source/filter/xml/xmltble.cxx
index 87f5b967f19f..4e88af10a9d4 100644
--- a/engine/sw/source/filter/xml/xmltble.cxx
+++ b/engine/sw/source/filter/xml/xmltble.cxx
@@ -1239,10 +1239,12 @@ void SwXMLTextParagraphExport::exportTable(
if (!isAutoStylesCollected()
&& (bExportStyles || !pFormat->GetDoc().IsInHeaderFooter(*pTableNd)))
{
- maTableNodes.push_back(pTableNd);
- m_TableFormats.try_emplace(pTableNd);
- // Collect all tables inside cells of this table, too
- CollectTableLinesAutoStyles(pTable->GetTabLines(), *pFormat, _bProgress);
+ if (m_TableFormats.try_emplace(pTableNd).second)
+ {
+ maTableNodes.push_back(pTableNd);
+ // Collect all tables inside cells of this table, too
+ CollectTableLinesAutoStyles(pTable->GetTabLines(), *pFormat, _bProgress);
+ }
}
}
else

"Mike Kaganski (via cogerrit)"

unread,
May 24, 2026, 8:44:33 AM (yesterday) May 24
to collaboraon...@googlegroups.com
engine/sw/source/uibase/app/apphdl.cxx | 59 ++++++++++++++-------------------
1 file changed, 26 insertions(+), 33 deletions(-)

New commits:
commit 30db25d933eee124c81fd5d7e456fa252207d6ed
Author: Mike Kaganski <mike.k...@collabora.com>
AuthorDate: Sun Jan 25 08:37:54 2026 +0100
Commit: Mike Kaganski <mike.k...@collabora.com>
CommitDate: Sun May 24 12:43:32 2026 +0000

Deduplicate some code, and provide dialog parent

Move m_pView check to the top: this avoids following unnecessary
checks; if another instance of the wizard is already running, it
would do that itself.

Assign pView early, and use it to provide parent where needed.

Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198057
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.k...@collabora.com>
Signed-off-by: Mike Kaganski <mike.k...@collabora.com>
Change-Id: I7908d9e2c3d933e5c5e3d3e67b56821c77c1c68d
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1517
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/source/uibase/app/apphdl.cxx b/engine/sw/source/uibase/app/apphdl.cxx
index d360b7e4e2e6..777d3f1675f8 100644
--- a/engine/sw/source/uibase/app/apphdl.cxx
+++ b/engine/sw/source/uibase/app/apphdl.cxx
@@ -403,6 +403,16 @@ bool lcl_hasAllComponentsAvailable()

void SwMailMergeWizardExecutor::ExecuteMailMergeWizard( const SfxItemSet * pArgs )
{
+ if (m_pView)
+ {
+ OSL_FAIL("SwMailMergeWizardExecutor::ExecuteMailMergeWizard: Already executing the wizard!");
+ return;
+ }
+
+ auto pView = ::GetActiveView();
+ if (!pView)
+ return;
+
if(!lcl_hasAllComponentsAvailable())
{
if (officecfg::Office::Common::PackageKit::EnableBaseInstallation::get())
@@ -411,53 +421,36 @@ void SwMailMergeWizardExecutor::ExecuteMailMergeWizard( const SfxItemSet * pArgs
{
using namespace org::freedesktop::PackageKit;
using namespace svtools;
- css::uno::Reference< XSyncDbusSessionHelper > xSyncDbusSessionHelper(SyncDbusSessionHelper::create(comphelper::getProcessComponentContext()));
+ auto xSyncDbusSessionHelper(SyncDbusSessionHelper::create(comphelper::getProcessComponentContext()));
const css::uno::Sequence< OUString > vPackages{ u"libreoffice-base"_ustr };
xSyncDbusSessionHelper->InstallPackageNames(vPackages, OUString());
SolarMutexGuard aGuard;
- (void)executeRestartDialog(comphelper::getProcessComponentContext(), nullptr, RESTART_REASON_MAILMERGE_INSTALL);
+ (void)executeRestartDialog(comphelper::getProcessComponentContext(),
+ pView->GetFrameWeld(), RESTART_REASON_MAILMERGE_INSTALL);
+ return;
}
catch (const css::uno::Exception &)
{
TOOLS_INFO_EXCEPTION(
"sw.core",
"trying to install LibreOffice Base, caught");
- auto xRestartManager
- = css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext());
- if (!xRestartManager->isRestartRequested(false))
- {
- // Base is absent, and could not initiate its install - ask user to do that manually
- // Only show the dialog if restart is not initiated yet
- std::unique_ptr<weld::MessageDialog> xWarnBox(Application::CreateMessageDialog(
- nullptr, VclMessageType::Info, VclButtonsType::Ok,
- SwResId(STR_NO_BASE_FOR_MERGE)));
- xWarnBox->run();
- }
- }
- } else {
- auto xRestartManager
- = css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext());
- if (!xRestartManager->isRestartRequested(false))
- {
- // Base is absent, and could not initiate its install - ask user to do that manually
- // Only show the dialog if restart is not initiated yet
- std::unique_ptr<weld::MessageDialog> xWarnBox(Application::CreateMessageDialog(
- nullptr, VclMessageType::Info, VclButtonsType::Ok,
- SwResId(STR_NO_BASE_FOR_MERGE)));
- xWarnBox->run();
}
}
- return;
- }
- if ( m_pView )
- {
- OSL_FAIL("SwMailMergeWizardExecutor::ExecuteMailMergeWizard: Already executing the wizard!" );
+ auto xRestartManager
+ = css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext());
+ if (!xRestartManager->isRestartRequested(false))
+ {
+ // Base is absent, and could not initiate its install - ask user to do that manually
+ // Only show the dialog if restart is not initiated yet
+ std::unique_ptr<weld::MessageDialog> xWarnBox(Application::CreateMessageDialog(
+ pView->GetFrameWeld(), VclMessageType::Info, VclButtonsType::Ok,
+ SwResId(STR_NO_BASE_FOR_MERGE)));
+ xWarnBox->run();
+ }
return;
}

- m_pView = ::GetActiveView();
- if (!m_pView)
- return;
+ m_pView = pView;

// keep self alive until done.
acquire();

"Mike Kaganski (via cogerrit)"

unread,
May 24, 2026, 1:28:07 PM (yesterday) May 24
to collaboraon...@googlegroups.com
engine/sw/source/core/layout/tabfrm.cxx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

New commits:
commit ac5983bc4e1c233959d17d1e291fdf185ee7b523
Author: Mike Kaganski <mike.k...@collabora.com>
AuthorDate: Sun Jan 25 09:52:31 2026 +0100
Commit: Mike Kaganski <mike.k...@collabora.com>
CommitDate: Sun May 24 17:27:49 2026 +0000

Drop unneeded cast

FindAnchorCharFrame is a method of SwAnchoredObject, so pFly
can be used just as well.

Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198061
Reviewed-by: Mike Kaganski <mike.k...@collabora.com>
Tested-by: Jenkins
Signed-off-by: Mike Kaganski <mike.k...@collabora.com>
Change-Id: Ic538a372f62d62e1cdc2b52807ba34ed8232c098
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/1520
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/source/core/layout/tabfrm.cxx b/engine/sw/source/core/layout/tabfrm.cxx
index 87534d97e21c..5981331aae1b 100644
--- a/engine/sw/source/core/layout/tabfrm.cxx
+++ b/engine/sw/source/core/layout/tabfrm.cxx
@@ -2930,9 +2930,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
SwFlyFrame* pFly = FindFlyFrame();
if (!pIndPrev && pFly && pFly->IsFlySplitAllowed())
{
- auto pFlyAtContent = static_cast<SwFlyAtContentFrame*>(pFly);
- SwFrame* pAnchor = pFlyAtContent->FindAnchorCharFrame();
- if (pAnchor)
+ if (SwFrame* pAnchor = pFly->FindAnchorCharFrame())
{
// If the anchor of the split has a previous frame, we're allowed to move forward.
pIndPrev = pAnchor->GetIndPrev();

"Aron Budea (via cogerrit)"

unread,
6:07 AM (11 hours ago) 6:07 AM
to collaboraon...@googlegroups.com
engine/sw/qa/extras/ooxmlexport/data/Cool15788_symbolContentControl.docx |binary
engine/sw/qa/extras/ooxmlexport/ooxmlexport27.cxx | 14 ++++++++++
engine/sw/source/filter/ww8/wrtw8nds.cxx | 7 +++++
3 files changed, 21 insertions(+)

New commits:
commit 42abcebb9245692729e5efe23d9979087d7f65a2
Author: Aron Budea <aron....@collabora.com>
AuthorDate: Tue May 19 10:33:17 2026 +0200
Commit: Mike Kaganski <mike.k...@collabora.com>
CommitDate: Mon May 25 10:06:35 2026 +0000

sw: don't write <sym> to DOCX content controls

At least in plain text content controls it's not allowed.
(possibly not in others, either)

Started recently after 9fce988742260ef35024a6f4af60e662ef01eb55.

The special export of symbols was added in commit
87e82f80e87bb4a216ea83383864d494f3e92eea.
Keep that in other cases.

Change-Id: Ia8412a93b680bec6f9df9ce5422a82cdd1ad86ee
Signed-off-by: Aron Budea <aron....@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/2888
Reviewed-by: Mike Kaganski <mike.k...@collabora.com>
Tested-by: Jenkins CPCI <rel...@collaboraoffice.com>

diff --git a/engine/sw/qa/extras/ooxmlexport/data/Cool15788_symbolContentControl.docx b/engine/sw/qa/extras/ooxmlexport/data/Cool15788_symbolContentControl.docx
new file mode 100644
index 000000000000..5b61e42d6934
Binary files /dev/null and b/engine/sw/qa/extras/ooxmlexport/data/Cool15788_symbolContentControl.docx differ
diff --git a/engine/sw/qa/extras/ooxmlexport/ooxmlexport27.cxx b/engine/sw/qa/extras/ooxmlexport/ooxmlexport27.cxx
index 924b839fa067..3d7f4b60a1b2 100644
--- a/engine/sw/qa/extras/ooxmlexport/ooxmlexport27.cxx
+++ b/engine/sw/qa/extras/ooxmlexport/ooxmlexport27.cxx
@@ -90,6 +90,20 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtPictureDataBinding)
CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

+CPPUNIT_TEST_FIXTURE(Test, testCool15788_symbolContentControl)
+{
+ createSwDoc("Cool15788_symbolContentControl.docx");
+
+ save(TestFilter::DOCX);
+
+ xmlDocUniquePtr pXmlDoc = parseExport(u"word/document.xml"_ustr);
+ // this must not exist, otherwise Word complains about the file
+ // <w:sym w:font="Wingdings" w:char="f04b"/>
+ CPPUNIT_ASSERT_EQUAL(0, countXPathNodes(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r[2]/w:sym"));
+ // simply a <w:t> element with the symbol must exist instead
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r[2]/w:t", u"\xf04b");
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

diff --git a/engine/sw/source/filter/ww8/wrtw8nds.cxx b/engine/sw/source/filter/ww8/wrtw8nds.cxx
index 0589967c8a5b..842f7a9e6cfb 100644
--- a/engine/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/engine/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2300,6 +2300,13 @@ bool MSWordExportBase::NeedTextNodeSplit( const SwTextNode& rNd, SwSoftPageBreak
namespace {
OUString lcl_GetSymbolFont(SwAttrPool& rPool, const SwTextNode& rTextNode, int nStart, int nEnd)
{
+ // later symbol font is used to replace exported character with element "sym"
+ // this is not allowed in (some?) content controls, Word won't open result
+ SwTextAttr* pAttr = rTextNode.GetTextAttrAt(nStart, RES_TXTATR_CONTENTCONTROL,
+ ::sw::GetTextAttrMode::Default);
+ if (pAttr)
+ return OUString();
+
SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet( rPool );
if (rTextNode.GetParaAttr(aSet, nStart, nEnd))
{

Reply all
Reply to author
Forward
0 new messages